clang
's ShadowCallStack, in this post, we will take a look into some
implementations that were tried in the meantime.
Following the findings of previous weeks of investigation work, the issue of clang
not providing a runtime for the ShadowCallStak was resolved by coming up with a primitive constructor which would take care of initializing the Shadow Stack.
This constructor had to be moved in the ukboot
library, more specifically, in boot.c
, in order to be called at the same time (at bootstrapping) with the other Unikraft specific constructors and init functions.
As a result, the constructor cannot maintain its current form, as it brings critical overhead to the boot process, which, following Unikraft's vision, should be highly performant.
Documenting each and every step took by this stage was a must, and you'll be able to find my investigation work here; understanding the layout of both boot.c
and traps_arm64.c
facilitated debugging work.
The biggest milestone achieved until now was bringing Shadow Stack support for a simple app (helloworld
, to be more precise).
This constitutes the key part of the draft PR and the whole documentation of the process can be found here.
As a Proof of Concept, I used both gdb
to investigate the content of the Shadow Stack and assembly
code to prove the way the prologue and epilogue of the function is modified by this security mechanism.
What's more, improving the performance of the aforementioned constructor was anticipated and a first step taken into this direction was giving the Shadow Stack the same size as the regular, visible stack.
The biggest problem faced during this stage was debugging my Unikraft application; catching traps isn't fun, but the community helped and a straightforward solution to debugging an AArch64
app was documented.
Nevertheless, not realizing that the x18
register wasn't fixed (using the -ffixed-x18
flag) for all Unikraft functions was another issue which was finally resolved with help from my mentors.
At the request of my mentors, I embarked on a mission to document the reason as to why the x86
clang's
version of the ShadowCallStack was dropped.
The reason seems to be quite obscure, but after putting the pieces together, I was left with the conclusion that a Time-Of-Check-To-Time-Of-Use (TOCTOU) vulnerability was the main actor in this complicated play.
But more on that in my documentation.
Testing the Shadow Stack support (which proved to work fine on the helloworld
app) on other, more complex applications (such as SQLite
, redis
and nginx
) is an important first step forward.
I've already started working on these apps, here it is a sneak peak:
App\Compiler | gcc - x86 | gcc - aarch64 | clang - x86 | clang - aarch64 | clang with scs | gcc-12 with scs |
---|---|---|---|---|---|---|
SQLite | ✔️ | 🔜 | 🔜 | 🔜 | 🔜 | 🔜 |
redis | ✔️ | 🔜 | 🔜 | 🔜 | 🔜 | 🔜 |
nginx | ✔️ | 🔜 | 🔜 | 🔜 | 🔜 | 🔜 |
The second step consists of providing a simple ROP attack and observing how the execution behaves under these circumstances.
Thirdly, it should also be taken into consideration how my implementation would influence future security mechanisms (CET or CFI).
I aim to provide a proposal which will facilitate fitting both Shadow Stack and other related means of securing against ROP attacks together, on Unikraft.
Feel free to ask questions, report issues, and meet new people.