cloudius-systems / osv

OSv, a new operating system for the cloud.
osv.io
Other
4.11k stars 603 forks source link

Support binaries compiled with -fstack-protector #589

Open nyh opened 9 years ago

nyh commented 9 years ago

Some executables and libraries are compiled with -fstack-protector. These do not run correctly on OSv today: The code generated by the stack protector assumes that the C library puts in %fs:0x28 a random value ("SSP canary") and puts a copy of that value on the stack so it can be later tested (see explanation in, for example,http://www.drdobbs.com/security/anatomy-of-a-stack-smashing-attack-and-h/240001832).

%fs:0x28 means position 0x28 in the TCB, and our struct thread_control_block is too small, and doesn't have this position. We need to enlarge thread_control_block, and consider setting this canary to a random value in setup_tcb(). Would be good to take this oportunity to understand gcc's entire layout of the TCB, and if we might be missing another important thing.

Paweł Dziepak saw one example of such library - libgomp.so from his Linux distribution, and the attempt to read %fs:0x28 resulted in a crash in his test.

nyh commented 1 year ago

I just noticed https://x41-dsec.de/news/missing-or-weak-mitigations-in-various-unikernels/ discusses the importance of stack canaries, and the fact it's not supported properly on OSv (and most other unikernels). They say the following about OSv - which I have to admit, I didn't quite understand:

The main Makefile of OSv uses the -fno-stack-protector flag, which explicitly disables stack smashing protections / stack canaries. When creating an application, one can enable stack canaries by using e.g.\ the -fstack-protector-all flag. While this advises the compiler to generate the necessary stack checking code, the OS is still in charge of generating a random value and placing it at the correct address so that it can be copied onto the stack. OSv ships the musl libc with its code, but does not use musl’s stack smashing protection code. Instead, OSv implements its own stack smashing protection in runtime.cc, defining a static canary value. There is a flaw in the canary value initialization process, leading to the canary value always being 0 when explicitly enabling stack smashing protection. Due to time constraints it was not possible to conduct a root cause analysis yet. Interestingly, the code being faulty might even make it more secure here, as many string based input function stop reading input when a 0 byte occurs. Thus, it might be harder for an attacker to include a 0 byte in the exploit string than to include a static canary not containing a 0 byte.

wkozaczuk commented 1 year ago

The x86_64 glibc layout is defined here. Not only we would need to expand our current one but possibly move down the syscall stack related fields so they do not collide. Not sure if other fields may pose any challenges especially once we start supporting statically linked executables.

BTW is the TCB/TLS layout dictated by GCC or does it come from glibc? In other words, why is the offset equal to 0x28?

wkozaczuk commented 1 year ago

Useful information in another article - https://ctf-wiki.mahaloz.re/pwn/linux/mitigation/canary/. I guess the 0x28 value is specific to Linux rather than glibc. What is interesting musl seems to have a similar structure (see the 1st part of the pthread struct in https://github.com/bminor/musl/blob/master/src/internal/pthread_impl.h) and see this commit - https://github.com/bminor/musl/commit/58aa5f45ed3282751ae118c107ff008d4df765dc.