Skip to content

Commit

Permalink
libbpf-tools: add mountsnoop
Browse files Browse the repository at this point in the history
This commit adds a new libbpf tool mountsnoop.
It has the same functionalities just as its
counterpart in BCC tools. The default output
is the same.

```
$ mountsnoop
COMM             PID     TID     MNT_NS      CALL
dockerd          1827    1903    4026531840  mount("overlay", "/data/docker/overlay2/153e6b58322c64cf4b2aac1b9caba42d390481a7d33a2bffe0eb858943d49fb6-init/merged", "overlay", 0x0, "index=off,lowerdir=/data/docker/overlay2/l/GWTHHZ2C3PYGAJ5GLTWLHMHHKR,upperdir=/data/docker/overlay2/153e6b58322c64cf4b2aac1b9caba42d390481a7d33a2bffe0eb858943d49fb6-init/diff,workdir=/data/docker/overlay2/153e6b58322c64cf4b2aac1b9caba42d390481a7d33a2bffe0eb858943d49fb6-init/work") = 0
dockerd          1827    1903    4026531840  umount("/data/docker/overlay2/153e6b58322c64cf4b2aac1b9caba42d390481a7d33a2bffe0eb858943d49fb6-init/merged", MS_NOSUID) = 0
```

Also, we provide a detailed mode enabled by -d
option which displays each mount/umount syscall
vertically with more field. In this way, the
output looks more friendly.

```
$ mountsnoop -d -t
PID:    1827
TID:    1864
COMM:   dockerd
OP:     MOUNT
RET:    0
LAT:    246us
MNT_NS: 4026531840
FS:     overlay
SOURCE: overlay
TARGET: /data/docker/overlay2/5fc51d4e4820082177751a8aadf3f42a751c86aff1e0efbc1a5e6af345ee205a-init/merged
DATA:   index=off,lowerdir=/data/docker/overlay2/l/GWTHHZ2C3PYGAJ5GLTWLHMHHKR,upperdir=/data/docker/overlay2/5fc51d4e4820082177751a8aadf3f42a751c86aff1e0efbc1a5e6af345ee205a-init/diff,workdir=/data/docker/overlay2/5fc51d4e4820082177751a8aadf3f42a751c86aff1e0efbc1a5e6af345ee205a-init/work
FLAGS:  0x0

PID:    1827
TID:    1864
COMM:   dockerd
OP:     UMOUNT
RET:    0
LAT:    95us
MNT_NS: 4026531840
FS:
SOURCE:
TARGET: /data/docker/overlay2/5fc51d4e4820082177751a8aadf3f42a751c86aff1e0efbc1a5e6af345ee205a-init/merged
DATA:
FLAGS:  MS_NOSUID
```

Signed-off-by: Hengqi Chen <[email protected]>
  • Loading branch information
chenhengqi authored and yonghong-song committed Aug 2, 2021
1 parent d567347 commit e4e660d
Show file tree
Hide file tree
Showing 5 changed files with 487 additions and 0 deletions.
1 change: 1 addition & 0 deletions libbpf-tools/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
/llcstat
/nfsdist
/nfsslower
/mountsnoop
/numamove
/offcputime
/opensnoop
Expand Down
1 change: 1 addition & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ APPS = \
gethostlatency \
hardirqs \
llcstat \
mountsnoop \
numamove \
offcputime \
opensnoop \
Expand Down
137 changes: 137 additions & 0 deletions libbpf-tools/mountsnoop.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2021 Hengqi Chen */
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include "mountsnoop.h"

#define MAX_ENTRIES 10240

const volatile pid_t target_pid = 0;

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, __u32);
__type(value, struct arg);
} args SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1);
__type(key, int);
__type(value, struct event);
} heap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
} events SEC(".maps");

static int probe_entry(const char *src, const char *dest, const char *fs,
__u64 flags, const char *data, enum op op)
{
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32)pid_tgid;
struct arg arg = {};

if (target_pid && target_pid != pid)
return 0;

arg.ts = bpf_ktime_get_ns();
arg.flags = flags;
arg.src = src;
arg.dest = dest;
arg.fs = fs;
arg.data= data;
arg.op = op;
bpf_map_update_elem(&args, &tid, &arg, BPF_ANY);
return 0;
};

static int probe_exit(void *ctx, int ret)
{
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32)pid_tgid;
struct arg *argp;
struct event *eventp;
struct task_struct *task;
int zero = 0;

argp = bpf_map_lookup_elem(&args, &tid);
if (!argp)
return 0;

eventp = bpf_map_lookup_elem(&heap, &zero);
if (!eventp)
return 0;

task = (struct task_struct *)bpf_get_current_task();
eventp->delta = bpf_ktime_get_ns() - argp->ts;
eventp->flags = argp->flags;
eventp->pid = pid;
eventp->tid = tid;
eventp->mnt_ns = BPF_CORE_READ(task, nsproxy, mnt_ns, ns.inum);
eventp->ret = ret;
eventp->op = argp->op;
bpf_get_current_comm(&eventp->comm, sizeof(eventp->comm));
if (argp->src)
bpf_probe_read_user_str(eventp->src, sizeof(eventp->src), argp->src);
else
eventp->src[0] = '\0';
if (argp->dest)
bpf_probe_read_user_str(eventp->dest, sizeof(eventp->dest), argp->dest);
else
eventp->dest[0] = '\0';
if (argp->fs)
bpf_probe_read_user_str(eventp->fs, sizeof(eventp->fs), argp->fs);
else
eventp->fs[0] = '\0';
if (argp->data)
bpf_probe_read_user_str(eventp->data, sizeof(eventp->data), argp->data);
else
eventp->data[0] = '\0';
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, eventp, sizeof(*eventp));

bpf_map_delete_elem(&args, &tid);
return 0;
}

SEC("tracepoint/syscalls/sys_enter_mount")
int mount_entry(struct trace_event_raw_sys_enter *ctx)
{
const char *src = (const char *)ctx->args[0];
const char *dest = (const char *)ctx->args[1];
const char *fs = (const char *)ctx->args[2];
__u64 flags = (__u64)ctx->args[3];
const char *data = (const char *)ctx->args[4];

return probe_entry(src, dest, fs, flags, data, MOUNT);
}

SEC("tracepoint/syscalls/sys_exit_mount")
int mount_exit(struct trace_event_raw_sys_exit *ctx)
{
return probe_exit(ctx, (int)ctx->ret);
}

SEC("tracepoint/syscalls/sys_enter_umount")
int umount_entry(struct trace_event_raw_sys_enter *ctx)
{
const char *dest = (const char *)ctx->args[0];
__u64 flags = (__u64)ctx->args[1];

return probe_entry(NULL, dest, NULL, flags, NULL, UMOUNT);
}

SEC("tracepoint/syscalls/sys_exit_umount")
int umount_exit(struct trace_event_raw_sys_exit *ctx)
{
return probe_exit(ctx, (int)ctx->ret);
}

char LICENSE[] SEC("license") = "Dual BSD/GPL";
Loading

0 comments on commit e4e660d

Please sign in to comment.