support rt_sigreturn

This commit is contained in:
2025-12-16 11:14:10 +01:00
parent 08f21c06fb
commit 3633346d53
4 changed files with 67 additions and 3 deletions

View File

@@ -15,8 +15,8 @@ IvyBridge(2012) and AMD Zen 2 Family 17H(2019) and Linux 5.9(2020).
- [x] `clone`: with and without stack switching
- [x] `clone3`: with and without stack switching
- [x] `fork`: likely there is nothing to be done here but just to be sure, check again
- [ ] `sigretun`/`rt_sigreturn`: we can't use the normal `syscall` interception because we push
something onto the stack, so `ucontext` isn't on top anymore.
- [x] `rt_sigreturn`: we can't use the normal `syscall` interception because we push something onto
the stack, so `ucontext` isn't on top anymore.
- [x] `/proc/self/exe`: intercept calls to `readlink`/`readlinkat` with that as argument
- [ ] `auxv`: check if that is setup correctly and completely
- [ ] JIT support: intercept `mmap`, `mprotect` and `mremap` that change pages to be executable

View File

@@ -376,6 +376,19 @@ test "nolibc_pie_fork" {
// );
// }
test "nolibc_nopie_signal_handler" {
try testHelper(
&.{ flicker_path, getTestExePath("nolibc_nopie_signal_handler") },
"In signal handler\nSignal handled successfully\n",
);
}
test "nolibc_pie_signal_handler" {
try testHelper(
&.{ flicker_path, getTestExePath("nolibc_pie_signal_handler") },
"In signal handler\nSignal handled successfully\n",
);
}
fn testPrintArgs(comptime name: []const u8) !void {
const exe_path = getTestExePath(name);
const loader_argv: []const []const u8 = &.{ flicker_path, exe_path, "foo", "bar", "baz hi" };

View File

@@ -64,7 +64,23 @@ export fn syscall_handler(ctx: *SavedContext) callconv(.c) void {
return;
},
.rt_sigreturn => {
@panic("sigreturn is not supported yet");
// The kernel expects the stack pointer to point to the `ucontext` structure. But in our
// case `syscallEntry` pushed the `SavedContext` onto the stack.
// So we just need to reset the stack pointer to what it was before `syscallEntry` was
// called. The `SavedContext` includes the return address pushed by the trampoline, so
// the original stack pointer is exactly at the end of `SavedContext`.
const rsp_orig = @intFromPtr(ctx) + @sizeOf(SavedContext);
asm volatile (
\\ mov %[rsp], %%rsp
\\ syscall
\\ ud2
:
: [rsp] "r" (rsp_orig),
[number] "{rax}" (ctx.rax),
: .{ .memory = true }
);
unreachable;
},
.execve, .execveat => |s| {
// TODO: option to persist across new processes

View File

@@ -0,0 +1,35 @@
const std = @import("std");
const linux = std.os.linux;
var handled = false;
fn handler(sig: i32, _: *const linux.siginfo_t, _: ?*anyopaque) callconv(.c) void {
if (sig == linux.SIG.USR1) {
handled = true;
const msg = "In signal handler\n";
_ = linux.syscall3(.write, 1, @intFromPtr(msg.ptr), msg.len);
}
}
pub fn main() !void {
const act = linux.Sigaction{
.handler = .{ .sigaction = handler },
.mask = std.mem.zeroes(linux.sigset_t),
.flags = linux.SA.SIGINFO | linux.SA.RESTART,
};
if (linux.sigaction(linux.SIG.USR1, &act, null) != 0) {
return error.SigactionFailed;
}
_ = linux.kill(linux.getpid(), linux.SIG.USR1);
if (handled) {
const msg = "Signal handled successfully\n";
_ = linux.syscall3(.write, 1, @intFromPtr(msg.ptr), msg.len);
} else {
const msg = "Signal NOT handled\n";
_ = linux.syscall3(.write, 1, @intFromPtr(msg.ptr), msg.len);
std.process.exit(1);
}
}