Repository: angr/angr

Issue:
Sigaction syscall triggers "Not enough data for store" error
### Description

Running Angr on an AMD64 binary that makes a `sigaction` syscall triggers an error

```
Traceback (most recent call last):
  File "/home/ubuntu/angr-exp/sigactionbug/demo.py", line 7, in <module>
    state_successors = state_successors[0].step()
  File "/home/ubuntu/angr-dev/angr/angr/sim_state.py", line 607, in step
    return self.project.factory.successors(self, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/factory.py", line 77, in successors
    return self.default_engine.process(*args, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/engines/vex/light/slicing.py", line 20, in process
    return super().process(*args, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/engines/engine.py", line 163, in process
    self.process_successors(self.successors, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/engines/failure.py", line 24, in process_successors
    return super().process_successors(successors, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/engines/syscall.py", line 50, in process_successors
    return self.process_procedure(state, successors, sys_procedure, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/engines/procedure.py", line 39, in process_procedure
    inst = procedure.execute(state, successors, ret_to=ret_to, arguments=arguments)
  File "/home/ubuntu/angr-dev/angr/angr/sim_procedure.py", line 286, in execute
    inst.ret(r)
  File "/home/ubuntu/angr-dev/angr/angr/sim_procedure.py", line 459, in ret
    ret_addr = self.cc.teardown_callsite(self.state, return_val=expr, prototype=self.prototype)
  File "/home/ubuntu/angr-dev/angr/angr/calling_conventions.py", line 921, in teardown_callsite
    self.set_return_val(state, return_val, prototype.returnty)
  File "/home/ubuntu/angr-dev/angr/angr/calling_conventions.py", line 1339, in set_return_val
    super().set_return_val(state, val, ty, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/calling_conventions.py", line 798, in set_return_val
    loc.set_value(state, val, stack_base=stack_base)
  File "/home/ubuntu/angr-dev/angr/angr/calling_conventions.py", line 310, in set_value
    state.registers.store(offset, value, size=self.size)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/unwrapper_mixin.py", line 10, in store
    return super().store(
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/name_resolution_mixin.py", line 60, in store
    return super().store(addr, data, size=size, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/bvv_conversion_mixin.py", line 26, in store
    super().store(addr, data_bv, size=size, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/simplification_mixin.py", line 13, in store
    super().store(addr, real_data, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/clouseau_mixin.py", line 7, in store
    super().store(addr, data, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/actions_mixin.py", line 34, in store
    super().store(addr, data, size=size, action=action, condition=condition, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/underconstrained_mixin.py", line 28, in store
    super().store(addr, data, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/size_resolution_mixin.py", line 99, in store
    super().store(addr, data, size=size, condition=condition, **kwargs)
  File "/home/ubuntu/angr-dev/angr/angr/storage/memory_mixins/size_resolution_mixin.py", line 43, in store
    raise SimMemoryError("Not enough data for store")
angr.errors.SimMemoryError: Not enough data for store
```

### Steps to reproduce the bug

Here is a minimal code that triggers the bug :

```C
#include <signal.h>
#include <stdio.h>

int main() {
   sigaction(SIGSEGV, NULL, NULL);
   return 0;
}
```

```python
import angr

angr_project = angr.Project("./target_program", exclude_sim_procedures_list=['sigaction'])
state_successors = angr_project.factory.entry_state().step()

while not state_successors.is_empty:
    state_successors = state_successors[0].step()
```

The bug happens when the SimProcedure for the sigaction syscall is executed (not the SimProcedure for the libc wrapper ). Excluding the libc wrapper SimProcedure is necessary to actually reach the code calling the syscall and trigger the bug.

### Environment

_No response_

### Additional context

As far as I understand, this is due to an inconsistency between the prototype and the implementation of the SimProcedure for the `sigaction` syscall, like #4033. According to its prototype, the SimProcedure should return a long but it actually returns an int.

The error happens when the SimProcedure for the syscall returns. It is raised from this check in `angr/storage/memory_mixins/size_resolution_mixin.py`

```
        if out_size > max_size:
            raise SimMemoryError("Not enough data for store")
```

because `max_size` is 4 and `out_size` is 8.

`max_size` is determined by the length of the value returned by the SimProcedure, i.e. an int in the current implementation in `angr/procedures/linux_kernel/sigaction.py`
```python
class rt_sigaction(angr.SimProcedure):
    def run(self, signum, act, oldact, sigsetsize):  # pylint:disable=arguments-differ,unused-argument
        # TODO: actually do something
        # ...hack
        if self.state.solver.is_true(signum == 33):
            return self.state.libc.ret_errno("EINVAL")
        return self.state.solver.BVV(0, self.arch.sizeof["int"])
```


`out_size` is determined by the return type given in the prototype of the SimProcedure in `angr/procedures/definitions/linux_kernel.py`, i.e. a long :

```python
# long sys_rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
'rt_sigaction': SimTypeFunction([SimTypeInt(signed=True), SimTypePointer(SimStruct({}, name="sigaction", pack=False, align=None), offset=0), SimTypePointer(SimStruct({}, name="sigaction", pack=False, align=None), offset=0), SimTypeLong(signed=False, label="size_t")], SimTypeLong(signed=True), arg_names=["None", "None", "None", "None"]),
```

Replacing `int` with `long` in the return of the SimProcedure fixes the problem for me.


Discussion:

Resolving patch:
diff --git a/angr/procedures/linux_kernel/sigaction.py b/angr/procedures/linux_kernel/sigaction.py
--- a/angr/procedures/linux_kernel/sigaction.py
+++ b/angr/procedures/linux_kernel/sigaction.py
@@ -4,7 +4,7 @@
 class sigaction(angr.SimProcedure):
     def run(self, signum, act, oldact):  # pylint:disable=arguments-differ,unused-argument
         # TODO: actually do something
-        return self.state.solver.BVV(0, self.arch.sizeof["int"])
+        return self.state.solver.BVV(0, self.arch.sizeof["long"])
 
 
 class rt_sigaction(angr.SimProcedure):
@@ -13,4 +13,4 @@ def run(self, signum, act, oldact, sigsetsize):  # pylint:disable=arguments-diff
         # ...hack
         if self.state.solver.is_true(signum == 33):
             return self.state.libc.ret_errno("EINVAL")
-        return self.state.solver.BVV(0, self.arch.sizeof["int"])
+        return self.state.solver.BVV(0, self.arch.sizeof["long"])


Test patch: