support rt_sigreturn
This commit is contained in:
@@ -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] `clone`: with and without stack switching
|
||||||
- [x] `clone3`: 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
|
- [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
|
- [x] `rt_sigreturn`: we can't use the normal `syscall` interception because we push something onto
|
||||||
something onto the stack, so `ucontext` isn't on top anymore.
|
the stack, so `ucontext` isn't on top anymore.
|
||||||
- [x] `/proc/self/exe`: intercept calls to `readlink`/`readlinkat` with that as argument
|
- [x] `/proc/self/exe`: intercept calls to `readlink`/`readlinkat` with that as argument
|
||||||
- [ ] `auxv`: check if that is setup correctly and completely
|
- [ ] `auxv`: check if that is setup correctly and completely
|
||||||
- [ ] JIT support: intercept `mmap`, `mprotect` and `mremap` that change pages to be executable
|
- [ ] JIT support: intercept `mmap`, `mprotect` and `mremap` that change pages to be executable
|
||||||
|
|||||||
13
src/main.zig
13
src/main.zig
@@ -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 {
|
fn testPrintArgs(comptime name: []const u8) !void {
|
||||||
const exe_path = getTestExePath(name);
|
const exe_path = getTestExePath(name);
|
||||||
const loader_argv: []const []const u8 = &.{ flicker_path, exe_path, "foo", "bar", "baz hi" };
|
const loader_argv: []const []const u8 = &.{ flicker_path, exe_path, "foo", "bar", "baz hi" };
|
||||||
|
|||||||
@@ -64,7 +64,23 @@ export fn syscall_handler(ctx: *SavedContext) callconv(.c) void {
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.rt_sigreturn => {
|
.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| {
|
.execve, .execveat => |s| {
|
||||||
// TODO: option to persist across new processes
|
// TODO: option to persist across new processes
|
||||||
|
|||||||
35
src/test/signal_handler.zig
Normal file
35
src/test/signal_handler.zig
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user