-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Zig Version
0.9.0
Steps to Reproduce
For this to work you must have a Linux kernel with CONFIG_BPF_KPROBE_OVERRIDE=y. Apparently this is the default on Arch Linux, but for NixOS I had to add:
boot.kernelPatches = [ {
name = "kprobe-bpf-override-config";
patch = null;
extraConfig = ''
FUNCTION_ERROR_INJECTION y
BPF_KPROBE_OVERRIDE y
'';
} ];and build a kernel.
Once that is done you can run:
git clone --recursive https://github.com/trailofbits/ebpfault
cd ebpfault/libraries/ebpf-common/src
git fetch https://github.com/trailofbits/ebpf-common.git
git cherry-pick b20da60eec9c5bd051c5570950e72a34b3244c30 f75a900af068a2751c85c1332dade3167114400f
cd ../../..
nix-shell -E 'with import <nixpkgs> { }; llvmPackages_8.stdenv.mkDerivation { name = "ebpfault"; buildInputs = [ cmake llvmPackages_8.llvm zig ]; cmakeFlags = ["-DEBPFAULT_ENABLE_INSTALL:BOOL=true" "-DEBPF_COMMON_ENABLE_TESTS:BOOL=true" "-DEBPF_COMMON_ENABLE_SANITIZERS:BOOL=false" "-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo"]; }'Then in the shell:
cmakeConfigurePhase
buildPhase
cat > efault.json <<EOF
{"fault_injectors": [
{
"syscall_name": "chdir",
"error_list": [
{
"exit_code": "-EFAULT",
"probability": 100
}
]
}
]
}
EOF
cat > einval.json <<EOF
{"fault_injectors": [
{
"syscall_name": "chdir",
"error_list": [
{
"exit_code": "-EINVAL",
"probability": 100
}
]
}
]
}
EOF
cat > chdir.zig <<EOF
const std = @import("std");
pub fn main() !void {
try std.os.chdir(".");
}
EOF
zig build-exe chdir.zig
sudo ./ebpfault --config efault.json --exec ./chdir
sudo ./ebpfault --config einval.json --exec ./chdirThis is only the easiest way to get rare kernel errors to show up. As Matthew Wilcox writes, there are 70+ filesystems and also hooks such as Linux Security Modules. These can all return their own error codes under the correct conditions. Simply do git grep -ho '\-E[A-Z]*' fs or git grep -ho '\-E[A-Z]*' security in a kernel git repo to see the wide variety of error codes - nearly all error codes are in use. Furthermore a new release of the kernel may return new error codes. Figuring out the actual set of error codes each system call may return is a "Sisyphean" task that is best left unattempted.
Expected Behavior
I expect Zig to allow writing robust programs, so crashing with a panic is definitely not what I expected. I should be able to see the exact error code such as EINVAL or EFAULT when it comes up in practice, in the stack trace - the message for Unexpected doesn't count because it only shows up in debug mode. I should be able to handle the error code in a way appropriate to the application, without modifying Zig's standard library.
Actual Behavior
On running sudo ./ebpfault --config efault.json --exec ./chdir:
timestamp: 4844456200127 syscall: chdir process_id: 11026 thread_id: 11026 injected_error: -EFAULT
r15 0000000000000000 r14 0000000000000000 r13 0000000000000000
r12 ffffa821812e7f58 rbp ffffa821812e7f48 rbx 0000000000000000
r11 0000000000000000 r10 0000000000000000 r9 0000000000000000
r8 0000000000000000 rax ffffffffb62d3040 rcx 0000000000000000
rdx ffffffffffffffff rsi 0000000000000050 rdi ffffa821812e7f58
orig_rax 0000000000000000 rip ffffffffb62d3041 cs 0000000000000010
eflags 0000000000000206 rsp ffffa821812e7f38 ss 0000000000000018
thread 11026 panic: reached unreachable code
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2625:19: 0x2349ee in std.os.chdirZ (chdir)
.FAULT => unreachable,
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2610:22: 0x234916 in std.os.chdir (chdir)
return chdirZ(&dir_path_c);
^
ebpfault/build/chdir.zig:4:21: 0x22d19a in main (chdir)
try std.os.chdir(".");
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:553:37: 0x225e4a in std.start.callMain (chdir)
const result = root.main() catch |err| {
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:495:12: 0x2071fe in std.start.callMainWithArgs (chdir)
return @call(.{ .modifier = .always_inline }, callMain, .{});
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:409:17: 0x206296 in std.start.posixCallMainAndExit (chdir)
std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:322:5: 0x2060a2 in std.start._start (chdir)
@call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
^
On running sudo ./ebpfault --config einval.json --exec ./chdir:
timestamp: 4918261533081 syscall: chdir process_id: 11058 thread_id: 11058 injected_error: -EINVAL
r15 0000000000000000 r14 0000000000000000 r13 0000000000000000
r12 ffffa8218127ff58 rbp ffffa8218127ff48 rbx 0000000000000000
r11 0000000000000000 r10 0000000000000000 r9 0000000000000000
r8 0000000000000000 rax ffffffffb62d3040 rcx 0000000000000000
rdx ffffffffffffffff rsi 0000000000000050 rdi ffffa8218127ff58
orig_rax 0000000000000000 rip ffffffffb62d3041 cs 0000000000000010
eflags 0000000000000206 rsp ffffa8218127ff38 ss 0000000000000018
unexpected errno: 22
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/debug.zig:458:19: 0x208048 in std.debug.writeCurrentStackTrace (chdir)
while (it.next()) |return_address| {
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/debug.zig:115:31: 0x206aca in std.debug.dumpCurrentStackTrace (chdir)
writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:4985:40: 0x209682 in std.os.unexpectedErrno (chdir)
std.debug.dumpCurrentStackTrace(null);
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2632:45: 0x23499b in std.os.chdirZ (chdir)
else => |err| return unexpectedErrno(err),
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2610:22: 0x234916 in std.os.chdir (chdir)
return chdirZ(&dir_path_c);
^
ebpfault/build/chdir.zig:4:21: 0x22d19a in main (chdir)
try std.os.chdir(".");
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:553:37: 0x225e4a in std.start.callMain (chdir)
const result = root.main() catch |err| {
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:495:12: 0x2071fe in std.start.callMainWithArgs (chdir)
return @call(.{ .modifier = .always_inline }, callMain, .{});
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:409:17: 0x206296 in std.start.posixCallMainAndExit (chdir)
std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/start.zig:322:5: 0x2060a2 in std.start._start (chdir)
@call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
^
error: Unexpected
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:4987:5: 0x209691 in std.os.unexpectedErrno (chdir)
return error.Unexpected;
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2632:23: 0x2349a8 in std.os.chdirZ (chdir)
else => |err| return unexpectedErrno(err),
^
/nix/store/xnvnk2dpcig6xcx55xd8bvwdznsd0h9h-zig-0.9.0/lib/zig/std/os.zig:2610:9: 0x23492c in std.os.chdir (chdir)
return chdirZ(&dir_path_c);
^
ebpfault/build/chdir.zig:4:5: 0x22d1b9 in main (chdir)
try std.os.chdir(".");
^