Skip to content

Instantly share code, notes, and snippets.

@mattnite
Created September 30, 2020 08:32
Show Gist options
  • Save mattnite/200973b660920d8ed87642223d03187a to your computer and use it in GitHub Desktop.
Save mattnite/200973b660920d8ed87642223d03187a to your computer and use it in GitHub Desktop.
opensnoop zig
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Matt Knight
//
// Base on the opensnoop probe as part of libbpf-tools
// Copyright (c) 2019 Facebook
// Copyright (c) 2020 Netflix
usingnamespace BPF.kern;
const std = @import("std");
const BPF = std.os.linux.BPF;
const c = @cImport({
@cInclude("linux/version.h");
@cInclude("linux/limits.h");
});
pub const TASK_COMM_LEN = 16; // not available from linux uapi
pub const NAME_MAX = c.NAME_MAX;
pub const Args = struct {
fname: [*:0]const u8,
flags: usize,
};
pub const Event = struct {
ts: u64,
pid: u32,
uid: u32,
ret: isize,
flags: usize,
comm: [TASK_COMM_LEN]u8,
fname: [NAME_MAX]u8,
};
pub const PidTidTag = enum {
pid,
tid,
};
pub const PidTidFilter = union(PidTidTag) {
pid: i32,
tid: i32,
};
pub const Config = struct {
pid_tid: ?PidTidFilter = null,
uid: ?u32 = null,
flags: u32 = 0,
failed: bool = false,
const Self = @This();
pub fn filter(self: *const Self, pid: u32, tid: u32, uid: u32) !void {
if (self.pid_tid) |tag| {
switch (tag) {
.pid => |p| if (p != pid) return error.Filter,
.tid => |t| if (t != tid) return error.Filter,
}
}
if (self.uid) |u| {
if (u != uid) return error.Filter;
}
}
};
export var config linksection(".rodata") = std.mem.zeroes(Config);
export const start linksection(".maps") = HashMap(u32, Args).init(10240, 0);
export const events linksection(".maps") = PerfEventArray.init(256, 0);
const open_enter = Tracepoint{
.category = "syscalls",
.name = "sys_enter_open",
};
const open_exit = Tracepoint{
.category = "syscalls",
.name = "sys_exit_open",
};
const OpenEnterCtx = comptime blk: {
@setEvalBranchQuota(10000);
break :blk open_enter.Ctx();
};
const OpenExitCtx = comptime blk: {
@setEvalBranchQuota(10000);
break :blk open_exit.Ctx();
};
fn trace_enter(ctx: *OpenEnterCtx) !void {
const id = get_current_pid_tgid();
const tgid = @truncate(u32, id >> 32);
const pid = @truncate(u32, id);
try config.filter(pid, tgid, @truncate(u32, get_current_uid_gid()));
const args = Args{
.fname = @intToPtr([*:0]u8, ctx.filename),
.flags = ctx.flags,
};
try start.update(.any, pid, args);
}
fn trace_exit(ctx: *OpenExitCtx) !void {
const id = get_current_pid_tgid();
const pid = @truncate(u32, id >> 32);
defer start.delete(pid) catch {};
if (config.failed and ctx.ret >= 0) {
return;
}
const args = start.lookup(pid) orelse return error.NotFound;
var event = Event{
.ts = ktime_get_ns(),
.pid = pid,
.uid = @truncate(u32, id),
.flags = args.flags,
.ret = ctx.ret,
.comm = undefined,
.fname = undefined,
};
try get_current_comm(&event.comm);
_ = try probe_read_user_str(&event.fname, args.fname);
try events.event_output(ctx, BPF.F_CURRENT_CPU, std.mem.asBytes(&event));
}
export fn enter_open(ctx: *OpenEnterCtx) linksection(open_enter.section()) c_int {
@call(.{ .modifier = .always_inline }, trace_enter, .{ctx}) catch {};
return 0;
}
// TODO: openat3
export fn exit_open(ctx: *OpenExitCtx) linksection(open_exit.section()) c_int {
@call(.{ .modifier = .always_inline }, trace_exit, .{ctx}) catch {};
return 0;
}
export const _license linksection(".license") = "GPL";
export const _version linksection(".version") = c.LINUX_VERSION_CODE;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment