Hey Jessie, where's your W^X gone?
Jul 21, 2017
3 minute read

Note: the following has been done in collaboration with Robin Verton.

Playing with our newly set up Raspberry Pis, we noticed that even though binaries are compiled to have a (by default) non-executable stack, they almost all end up having an executable stack. For example:

pi@raspwn:~ cat /proc/self/maps
00010000-00019000 r-xp 00000000 b3:02 524        /bin/cat
00028000-00029000 r--p 00008000 b3:02 524        /bin/cat
00029000-0002a000 rw-p 00009000 b3:02 524        /bin/cat
00e37000-00e58000 rw-p 00000000 00:00 0          [heap]
76bdc000-76bfe000 rw-p 00000000 00:00 0 
76bfe000-76d88000 r--p 00000000 b3:02 233        /usr/lib/locale/locale-archive
76d88000-76eb3000 r-xp 00000000 b3:02 1946       /lib/arm-linux-gnueabihf/libc-2.19.so
76eb3000-76ec3000 ---p 0012b000 b3:02 1946       /lib/arm-linux-gnueabihf/libc-2.19.so
76ec3000-76ec5000 r--p 0012b000 b3:02 1946       /lib/arm-linux-gnueabihf/libc-2.19.so
76ec5000-76ec6000 rw-p 0012d000 b3:02 1946       /lib/arm-linux-gnueabihf/libc-2.19.so
76ec6000-76ec9000 rw-p 00000000 00:00 0 
76ec9000-76ece000 r-xp 00000000 b3:02 33476      /usr/lib/arm-linux-gnueabihf/libarmmem.so
76ece000-76edd000 ---p 00005000 b3:02 33476      /usr/lib/arm-linux-gnueabihf/libarmmem.so
76edd000-76ede000 rw-p 00004000 b3:02 33476      /usr/lib/arm-linux-gnueabihf/libarmmem.so
76ede000-76efe000 r-xp 00000000 b3:02 1914       /lib/arm-linux-gnueabihf/ld-2.19.so
76f02000-76f04000 rw-p 00000000 00:00 0 
76f0b000-76f0d000 rw-p 00000000 00:00 0 
76f0d000-76f0e000 r--p 0001f000 b3:02 1914       /lib/arm-linux-gnueabihf/ld-2.19.so
76f0e000-76f0f000 rw-p 00020000 b3:02 1914       /lib/arm-linux-gnueabihf/ld-2.19.so
7e90c000-7e92d000 rwxp 00000000 00:00 0          [stack]
7ed76000-7ed77000 r-xp 00000000 00:00 0          [sigpage]
7ed77000-7ed78000 r--p 00000000 00:00 0          [vvar]
7ed78000-7ed79000 r-xp 00000000 00:00 0          [vdso]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

shows that cat has a rwx stack, like in the 90’s! But cat’s stack should not be executable since readelf shows a RW flag, not a RWE flag:

pi@raspwn:~$ readelf -l /bin/cat | grep GNU_STACK
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10

After some search, we found this link. This post reveals that the problem had already occured in Wheezy (it is now fixed). So we’ve discovered that is has reappeared in Jessie, although the library libcofi_rpi that was responsible for the bug in Wheezy is no longer in /usr/lib/arm-linux-gnueabihf. But this library seems, from the cat output above, to have been replaced by libarmmem. And this library is indeed the culprit since

pi@raspwn:~$ readelf -l /usr/lib/arm-linux-gnueabihf/libarmmem.so | grep GNU_STACK
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10

Digging into the arm-mem source reveals that 1 file (architecture.S) out of the 5 assembly source files does not contain the instructions that prevent the stack from being executable.

We then downloaded the source, added the missing lines

/* Prevent the stack from becoming executable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif

at the end of architecture.S, compiled with make, stripped the resulting shared object with strip libarmmem.so and checked that

pi@raspwn:~/arm-mem$ readelf -l ./libarmmem.so | grep GNU_STACK
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10

The final step is to replace the original buggy libarmmem.so thanks to

pi@raspwn:~/arm-mem$ sudo install ./libarmmem.so /usr/lib/arm-linux-gnueabihf/libarmmem.so

and check that the problem is cured:

pi@raspwn:~$ cat /proc/self/maps | grep stack
7e8cd000-7e8ee000 rw-p 00000000 00:00 0          [stack]

Note 1: We have submitted a pull request and reported the bug.

Note 2: One can wonder how many other libraries suffer from this problem, and the answer is: one, as can be seen from

pi@raspwn:~$ scanelf -lpqe
RWX --- ---  /lib/klibc-YL2Pal4e_FwRI58JJ6S97Xf241g.so

(scanelf is available after sudo apt install pax-utils)