-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ssamoswap traps / asynchronous runtime disabling #206
Comments
Since the libary loading happens from the dynamic loader, clearing
|
Presuming that the broadcast disable of SSE is done via a libc-internal signal, libc could protect its own stack switch code by masking the internal signal for the duration of the stack switch, but that doesn't help if users want to write their own switch code. |
That is why I said - disable it for the thread that did |
Is there however a reason to disable |
I don't understand how you think this could possibly work. If a library that contains code that mishandles shadow stacks, and it's loaded in one thread, the functions it defines can be called on all threads as soon as inter-thread communication happens, which could be as simple as writing a pointer to shared memory.
We don't need to disable SSE on dlopen of a library which is not compiled with shadow stack prologues/epilogues. We do need to disable SSE on dlopen of a library which contains its own shadow stack unaware implementation of unwinding or stack switching. The current ELF ABI conflates these into a single bit. |
If the library does stack switching but returns to the caller on the stack it was called on then that would not be an issue. If the library only unwinds its own call frames but not the callers call frames then it would be okay. So the we worry about a library that unwinds past its entry function or does not return to the caller on the stack it was called on? NOPing the
|
If we really want to disable Zicfiss and not fail
Option 2:
|
But cleanest may be to just not allow |
Yes, these are the sorts of things that are problematic.
If the ABI part of this proposal is adopted, the stack switch code would recheck ssrdp before the unimp.
Good catch. Will fix.
This is equivalent to signal masking as described in my previous message, somewhat faster but doesn't solve the actual problem where it tightly couples user code to libc implementation details.
I don't see how you can "insert a shim" on every single function in a shared library, including static functions that don't have dynamic symbols and are returned by pointer. Even if you could do this I don't see how it would be anything other than a maintenance, performance, and compatibility disaster.
I think this will be a very hard sell for musl, which has a high bar for breaking standards-compliant C code (much lower for things that already use asm or GNU extensions). |
Is that compliant with ABI. At least not returning on the stack that the caller used seems functionally wrong.
That seems like a good way to address this case.
I was thinking that the shim is created by the loader when returning a function pointer in response to
The thought here was that the user code is already opting into the Zicfiss extension. The restriction on not opening incompatible libraries could be part of this opt-in ABI. Code unaware of Zicfiss would see no change. |
Yes. These functions all cause a call site to return where the new stack and pc are correct.
I don't see how any of this solves the problem I was pointing out.
How does the shim get executed before the execution of foo in the second thread? foo doesn't have a dynamic symbol and at the time the thread is created, dlopen hasn't been called.
CFI enablement appears to be being done globally at a distro level, not as an opt-in. |
The shim would be on the bar() so would not help this case.
Each application needs to be compiled with the CFI options and the corresponding attributes set in the image for CFI to be activated on that program. The distro should not be shipping an application an application compiled with CFI if it is tested to be compatible with CFI - i.e., all its dependent libraries are also compatible. The two options suggested in the Linux thread seem feasible:
|
This threat model is incoherent. If an attacker can replace libraries, they don't need to bypass CFI because they already have full control of the process.
The ISA specification is the contract between software and the execution environment. It is not a hardware functionality specification, and existing cases where privileged software does interesting things in response to exceptions like misaligned accesses are reflected in the ISA specification. So if you want to go down this route it ought to be in the ISA specification. |
I am suggesting to fail the dlopen. However, software can choose to do the second option similar to other architectures like ARM and x86 . |
We likely need to be able to disable shadow stacks in all threads when a shared library without shadow stack compatibility is loaded. This is under discussion on linux-riscv. This is mostly a code generation issue (userspace code needs to allow for SSE to switch from 1 to 0 at any instruction boundary), but we need to decide what ssamoswap does in the uABI when shadow stacks are disabled, since "raise SIGILL" isn't an option. Presumably ssamoswap should perform no memory accesses and write 0 to the destination register if the shadow stack is disabled, and CSR writes to ssp should be ignored?
On the hardware side, do we want to change the definition of ssamoswap and ssp to do this automatically, or do we expect the ABI to be implemented by handling the illegal instruction trap?
The text was updated successfully, but these errors were encountered: