Skip to content
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

Make invoking IA2_DEFINE_SIG{ACTION,HANDLER} inside a function a compile-time error #459

Open
kkysen opened this issue Oct 28, 2024 · 7 comments

Comments

@kkysen
Copy link
Contributor

kkysen commented Oct 28, 2024

When I tried to use IA2_DEFINE_SIGHANDLER and IA2_SIGHANDLER in compartmentalizing dav1d, https://github.com/immunant/dav1d/blob/6483e57832c756096acab2c9f458676027cbb3b0/tools/dav1d.c#L287-L293, there was a segfault in IA2_DEFINE_SIGHANDLER that corrupted the stack. Thus, I worked around this by simply commenting out that code and just didn't install the signal handler, as it's not too important for dav1d. Am I doing something wrong here? I was trying to follow the docs at

IA2-Phase2/docs/usage.md

Lines 81 to 86 in 94f890b

### Signal handlers
Signal handlers require special call gate wrappers defined by the
`IA2_DEFINE_SIGACTION` or `IA2_DEFINE_SIGHANDLER` macros. To reference the
special call gate wrapper defined for a given function `foo`, use
`IA2_SIGHANDLER(foo)`.
, though they're not too explanatory.

@fw-immunant
Copy link
Contributor

It's surprising to me that this causes a segfault even in situations where (presumably) these signals are not being received. The macros in question define functions in assembly but should not actually cause any change in control flow until the signal handler runs.

I would try debugging stack-mangling crashes like this using rr to reverse execution up to the point where things first go off the rails.

@kkysen
Copy link
Contributor Author

kkysen commented Oct 28, 2024

I would try debugging stack-mangling crashes like this using rr to reverse execution up to the point where things first go off the rails.

Ah, that's a good idea. Let me try rr.

@ayrtonm
Copy link
Contributor

ayrtonm commented Oct 28, 2024

dav1d uses SA_RESETHAND so we should make sure compartment-aware handlers work as expected with that. My understanding of sigaction(2) is that this replaces our compartment-aware handler with the default.

@ayrtonm
Copy link
Contributor

ayrtonm commented Oct 28, 2024

Turns out the issue was that we had IA2_DEFINE_SIGNAL_HANDLER in a function (so the handler it defines was getting embedded in the middle of the function). Aside from noting that this macro can't be used inside a function, we might be able to make this mistake a compiler error by defining handlers as naked functions on x86 (I'm not sure if there is an equivalent tweak on ARM).

@kkysen
Copy link
Contributor Author

kkysen commented Oct 31, 2024

Turns out the issue was that we had IA2_DEFINE_SIGNAL_HANDLER in a function (so the handler it defines was getting embedded in the middle of the function). Aside from noting that this macro can't be used inside a function, we might be able to make this mistake a compiler error by defining handlers as naked functions on x86 (I'm not sure if there is an equivalent tweak on ARM).

Everything works now that IA2_DEFINE_SIGNAL_HANDLER is called in global scope. I'm adding that to the docs, but I looked into if we can detect if the macro is called inside of a function vs. globally, and I don't think we can (things like using __func__, __FUNCTION__, __builtin_FUNCTION(), etc.). However, I'm not understanding why the macro defines a function prototype and then declares the function in asm, vs. defining the function in C with the function body being asm. What's the difference? I'm assuming this was done for some reason, but I'm not sure what it is.

@ayrtonm
Copy link
Contributor

ayrtonm commented Oct 31, 2024

When the kernel makes a thread start executing from the signal handler it sets the PKRU to not have access to anything so it has to be a naked function. Otherwise the first few instructions accessing the stack will fault.

@ayrtonm ayrtonm changed the title Stack-corrupting segfault in IA2_DEFINE_SIGHANDLER Make invoking IA2_DEFINE_SIG{ACTION,HANDLER} inside a function a compile-time error Nov 5, 2024
@ayrtonm
Copy link
Contributor

ayrtonm commented Nov 5, 2024

Looks like we didn't initially make them naked functions because the asm statement is used for two functions with different signatures. This isn't a hard blocker for making them naked functions and triggering a compile-time error when these macros are invoked outside global scope, but the ARM case may complicate things. I'm not sure we need a wrapper to set x18 on ARM though. I think the kernel should leave x18 as-is (since it's also used for things like shadow call stack which should be all userspace) so it may be a non-issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants