github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/mount/tracer/bpf/mountsnoop.bpf.c (about)

     1  /* SPDX-License-Identifier: GPL-2.0 */
     2  /* Copyright (c) 2021 Hengqi Chen */
     3  #include <vmlinux.h>
     4  #include <bpf/bpf_helpers.h>
     5  #include <bpf/bpf_core_read.h>
     6  #include "mountsnoop.h"
     7  #include <gadget/mntns_filter.h>
     8  
     9  #define MAX_ENTRIES 10240
    10  
    11  const volatile pid_t target_pid = 0;
    12  
    13  // we need this to make sure the compiler doesn't remove our struct
    14  const struct event *unusedevent __attribute__((unused));
    15  
    16  struct {
    17  	__uint(type, BPF_MAP_TYPE_HASH);
    18  	__uint(max_entries, MAX_ENTRIES);
    19  	__type(key, __u32);
    20  	__type(value, struct arg);
    21  } args SEC(".maps");
    22  
    23  struct {
    24  	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
    25  	__uint(max_entries, 1);
    26  	__type(key, int);
    27  	__type(value, struct event);
    28  } heap SEC(".maps");
    29  
    30  struct {
    31  	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
    32  	__uint(key_size, sizeof(__u32));
    33  	__uint(value_size, sizeof(__u32));
    34  } events SEC(".maps");
    35  
    36  // TODO: have to use "inline" to avoid this error:
    37  // bpf/mountsnoop.bpf.c:41:12: error: defined with too many args
    38  // static int probe_entry(const char *src, const char *dest, const char *fs,
    39  static __always_inline int probe_entry(const char *src, const char *dest,
    40  				       const char *fs, __u64 flags,
    41  				       const char *data, enum op op)
    42  {
    43  	__u64 pid_tgid = bpf_get_current_pid_tgid();
    44  	__u32 pid = pid_tgid >> 32;
    45  	__u32 tid = (__u32)pid_tgid;
    46  	struct arg arg = {};
    47  	u64 mntns_id;
    48  
    49  	mntns_id = gadget_get_mntns_id();
    50  
    51  	if (gadget_should_discard_mntns_id(mntns_id))
    52  		return 0;
    53  
    54  	if (target_pid && target_pid != pid)
    55  		return 0;
    56  
    57  	arg.ts = bpf_ktime_get_ns();
    58  	arg.flags = flags;
    59  	arg.src = src;
    60  	arg.dest = dest;
    61  	arg.fs = fs;
    62  	arg.data = data;
    63  	arg.op = op;
    64  	bpf_map_update_elem(&args, &tid, &arg, BPF_ANY);
    65  
    66  	return 0;
    67  };
    68  
    69  static int probe_exit(void *ctx, int ret)
    70  {
    71  	__u64 pid_tgid = bpf_get_current_pid_tgid();
    72  	__u32 pid = pid_tgid >> 32;
    73  	__u32 tid = (__u32)pid_tgid;
    74  	struct arg *argp;
    75  	struct event *eventp;
    76  	int zero = 0;
    77  	u64 mntns_id;
    78  
    79  	argp = bpf_map_lookup_elem(&args, &tid);
    80  	if (!argp)
    81  		return 0;
    82  
    83  	eventp = bpf_map_lookup_elem(&heap, &zero);
    84  	if (!eventp)
    85  		goto cleanup;
    86  
    87  	eventp->mount_ns_id = gadget_get_mntns_id();
    88  	eventp->timestamp = bpf_ktime_get_boot_ns();
    89  	eventp->delta = bpf_ktime_get_ns() - argp->ts;
    90  	eventp->flags = argp->flags;
    91  	eventp->pid = pid;
    92  	eventp->tid = tid;
    93  	eventp->ret = ret;
    94  	eventp->op = argp->op;
    95  	bpf_get_current_comm(&eventp->comm, sizeof(eventp->comm));
    96  	if (argp->src)
    97  		bpf_probe_read_user_str(eventp->src, sizeof(eventp->src),
    98  					argp->src);
    99  	else
   100  		eventp->src[0] = '\0';
   101  	if (argp->dest)
   102  		bpf_probe_read_user_str(eventp->dest, sizeof(eventp->dest),
   103  					argp->dest);
   104  	else
   105  		eventp->dest[0] = '\0';
   106  	if (argp->fs)
   107  		bpf_probe_read_user_str(eventp->fs, sizeof(eventp->fs),
   108  					argp->fs);
   109  	else
   110  		eventp->fs[0] = '\0';
   111  	if (argp->data)
   112  		bpf_probe_read_user_str(eventp->data, sizeof(eventp->data),
   113  					argp->data);
   114  	else
   115  		eventp->data[0] = '\0';
   116  
   117  	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, eventp,
   118  			      sizeof(*eventp));
   119  
   120  cleanup:
   121  	bpf_map_delete_elem(&args, &tid);
   122  	return 0;
   123  }
   124  
   125  SEC("tracepoint/syscalls/sys_enter_mount")
   126  int ig_mount_e(struct syscall_trace_enter *ctx)
   127  {
   128  	const char *src = (const char *)ctx->args[0];
   129  	const char *dest = (const char *)ctx->args[1];
   130  	const char *fs = (const char *)ctx->args[2];
   131  	__u64 flags = (__u64)ctx->args[3];
   132  	const char *data = (const char *)ctx->args[4];
   133  
   134  	return probe_entry(src, dest, fs, flags, data, MOUNT);
   135  }
   136  
   137  SEC("tracepoint/syscalls/sys_exit_mount")
   138  int ig_mount_x(struct syscall_trace_exit *ctx)
   139  {
   140  	return probe_exit(ctx, (int)ctx->ret);
   141  }
   142  
   143  SEC("tracepoint/syscalls/sys_enter_umount")
   144  int ig_umount_e(struct syscall_trace_enter *ctx)
   145  {
   146  	const char *dest = (const char *)ctx->args[0];
   147  	__u64 flags = (__u64)ctx->args[1];
   148  
   149  	return probe_entry(NULL, dest, NULL, flags, NULL, UMOUNT);
   150  }
   151  
   152  SEC("tracepoint/syscalls/sys_exit_umount")
   153  int ig_umount_x(struct syscall_trace_exit *ctx)
   154  {
   155  	return probe_exit(ctx, (int)ctx->ret);
   156  }
   157  
   158  char LICENSE[] SEC("license") = "Dual BSD/GPL";