0

Here is the c-source code line which crashes on an armv7:

ret = fnPtr (param1, param2);

In the debugger, fnPtr has an address of 0x04216c00. When I disassemble at the pc where it's pointing at the statement above, here is what I get:

0x18918e:  movw   r0, #0x73c
0x189192:  movt   r0, #0x1
0x189196:  add    r0, r2
0x189198:  ldr    r0, [r0]
0x18919a:  str    r0, [sp, #0x20]
0x18919c:  ldr    r0, [sp, #0x20]
0x18919e:  ldr    r1, [sp, #0x28]
0x1891a0:  ldr    r2, [sp, #0x2c]
0x1891a2:  str    r0, [sp, #0x14]
0x1891a4:  mov    r0, r1
0x1891a6:  mov    r1, r2
0x1891a8:  ldr    r2, [sp, #0x14]
0x1891aa:  blx    r2

Now, when I disassemble the memory at address $r2 (=0x4216c00), I get what is seemingly valid code that should be executed without any problem:

(lldb) disassemble -s 0x4216c00 -C 10
   0x4216c00:  push   {r4, r5, r6, r7, lr}
   0x4216c04:  add    r7, sp, #0xc
   0x4216c08:  push   {r8, r10, r11}
   0x4216c0c:  vpush  {d8, d9, d10, d11, d12, d13, d14, d15}
   0x4216c10:  sub    r7, r7, #0x280
   0x4216c14:  mov    r6, r0
   0x4216c18:  bx     r1
   0x4216c1c:  add    r7, r7, #0x280

Yet what really happens is this:

EXC_BAD_ACCESS (code=2, address=0x4216c00)

Can anyone explain what is wrong and why the address is considered illegal?

Full disclosure: I am no assembly expert. The code compiled and linked is all c-code. Compiler is clang.

user3342339
  • 349
  • 1
  • 5
  • 19
  • What does the stack look like? A quick look around suggests running out of stack through impossibly large allocations or runaway recursion can give this error in seemingly innocent code. – Notlikethat Sep 01 '14 at 22:51
  • @Notlikethat: ok; this sounds plausible. How can I figure this one out? What constitutes "A quick look around". 'much appreciated! – user3342339 Sep 01 '14 at 23:08
  • @Notlikethat: So, I figured I would increase the memory partition for the app until I hear back from you. (≈ a quick check if i'm running into low mem issues that i can't see). I still crash with the same exception. – user3342339 Sep 01 '14 at 23:14
  • I don't know iOS so I just searched EXC_BAD_ACCESS to check it is the equivalent of SIGSEGV as I assumed. The suggestions of stack exhaustion e.g. [here](http://stackoverflow.com/q/9836251/3156750) and [here](http://stackoverflow.com/q/327082/3156750) caught my eye, since it's the sort of situation where you can end up with all kinds of weirdness. Dumping a stack trace at the point of the crash might be informative. Of course, it may still be something else like trying to call a freed object - just because the memory is still mapped doesn't mean it's still executable. – Notlikethat Sep 01 '14 at 23:34
  • It might be good to try to reproduce the issue in C and share it. If it is a stack corruption it can be somewhere else before where you get bitten. Are you doing something fancy with function pointers and varargs, etc? – auselen Sep 02 '14 at 06:35

2 Answers2

1

Check the value of r2 before calling executing blx instruction. It might be odd, telling the cpu that address is in thumb mode however from the listing it looks like in arm mode.

Try forcing clang to only arm mode by -mno-thumb to test this.

auselen
  • 27,577
  • 7
  • 73
  • 114
  • $r2 =0x4216c00 ; 0x4216c00 mod 2 = 0. The address is even – user3342339 Sep 01 '14 at 19:26
  • @user3342339 hmm.. that was a shot in the dark :) then I guess next thing is to see where `SP` points to. Can you add that one as well? – auselen Sep 01 '14 at 19:29
  • will do; i will also check that compiler flag and report the effect. thx. – user3342339 Sep 01 '14 at 19:56
  • tried the -mno-thumb: no go. I still get the bad access error. Also, the stack pointer is sp = 0x00f00eb8 : even address. – user3342339 Sep 01 '14 at 21:02
  • Amusingly, only the `mov` and the `bx` give it away as ARM - all the other instructions in that block would be 32-bit Thumb-2 encodings. Anyway, in the mismatched-interworking case surely you'd expect an undefined instruction error rather than a memory fault, no? – Notlikethat Sep 01 '14 at 21:15
  • @Notlikethat I am not sure I understand your comment. Like I said, I am not an assembly guru or that familiar with the different variations in the ISA of the different ARM architectures. – user3342339 Sep 01 '14 at 23:01
  • @Notlikethat I just jumped into interworking issue because I saw a function pointer and guessing `mov r6, r0` shouldn't be 4 bytes on thumb. – auselen Sep 02 '14 at 06:26
1

The EXC_BAD_ACCESS exception has two bits of data in it, the first is the "kern_return_t" number describing the access failure, and the second is the address accessed. In your case the code is 2, which means (from /usr/include/mach/kern_return.h):

#define KERN_PROTECTION_FAILURE         2
                /* Specified memory is valid, but does not permit the
                 * required forms of access.
                 */

Not sure why this is happening, sounds like you are trying to execute code that doesn't have the execute permission set. What does:

(lldb) image lookup -va 0x4216c00

say?

BTW, the exception types are in /usr/include/mach/exception_types.h, and if the codes have machine specific meanings, those will be in, e.g. /usr/include/mach/i386/exception.h) For ARM info you may have to look in the header in the Xcode SDK.

Jim Ingham
  • 25,260
  • 2
  • 55
  • 63
  • Thank you @Jim Ingham. This is very helpful. Indeed, I am trying to execute code that is created on the fly. I would say more but I am NDA'ed. Flushing the icache does not work and I am wondering if there is any legit, workaround. – user3342339 Sep 04 '14 at 14:15
  • I don't think iOS allows you to change permissions on a region from writable to executable, but you should really ask ADC about whether this is possible and if so how. – Jim Ingham Sep 04 '14 at 19:59