mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-12 22:56:28 +08:00
init with documents from eunomia-bpf
This commit is contained in:
3
7-execsnoop/.gitignore
vendored
Normal file
3
7-execsnoop/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
ecli
|
||||
package.json
|
||||
|
||||
148
7-execsnoop/README.md
Normal file
148
7-execsnoop/README.md
Normal file
@@ -0,0 +1,148 @@
|
||||
---
|
||||
layout: post
|
||||
title: execsnoop
|
||||
date: 2022-11-17 19:57
|
||||
category: bpftools
|
||||
author: yunwei37
|
||||
tags: [bpftools, syscall]
|
||||
summary: execsnoop traces the exec() syscall system-wide, and prints various details.
|
||||
---
|
||||
|
||||
## origin
|
||||
|
||||
origin from:
|
||||
|
||||
https://github.com/iovisor/bcc/blob/master/libbpf-tools/execsnoop.bpf.c
|
||||
|
||||
## Compile and Run
|
||||
|
||||
Compile:
|
||||
|
||||
```shell
|
||||
docker run -it -v `pwd`/:/src/ yunwei37/ebpm:latest
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```
|
||||
$ sudo ./ecli run package.json
|
||||
|
||||
running and waiting for the ebpf events from perf event...
|
||||
time pid ppid uid retval args_count args_size comm args
|
||||
23:07:35 32940 32783 1000 0 1 13 cat /usr/bin/cat
|
||||
23:07:43 32946 24577 1000 0 1 10 bash /bin/bash
|
||||
23:07:43 32948 32946 1000 0 1 18 lesspipe /usr/bin/lesspipe
|
||||
23:07:43 32949 32948 1000 0 2 36 basename /usr/bin/basename
|
||||
23:07:43 32951 32950 1000 0 2 35 dirname /usr/bin/dirname
|
||||
23:07:43 32952 32946 1000 0 2 22 dircolors /usr/bin/dircolors
|
||||
23:07:48 32953 32946 1000 0 2 25 ls /usr/bin/ls
|
||||
23:07:53 32957 32946 1000 0 2 17 sleep /usr/bin/sleep
|
||||
23:07:57 32959 32946 1000 0 1 17 oneko /usr/games/oneko
|
||||
|
||||
```
|
||||
|
||||
## details in bcc
|
||||
|
||||
Demonstrations of execsnoop, the Linux eBPF/bcc version.
|
||||
|
||||
execsnoop traces the exec() syscall system-wide, and prints various details.
|
||||
Example output:
|
||||
|
||||
```
|
||||
# ./execsnoop
|
||||
COMM PID PPID RET ARGS
|
||||
bash 33161 24577 0 /bin/bash
|
||||
lesspipe 33163 33161 0 /usr/bin/lesspipe
|
||||
basename 33164 33163 0 /usr/bin/basename /usr/bin/lesspipe
|
||||
dirname 33166 33165 0 /usr/bin/dirname /usr/bin/lesspipe
|
||||
dircolors 33167 33161 0 /usr/bin/dircolors -b
|
||||
ls 33172 33161 0 /usr/bin/ls --color=auto
|
||||
top 33173 33161 0 /usr/bin/top
|
||||
oneko 33174 33161 0 /usr/games/oneko
|
||||
systemctl 33175 2975 0 /bin/systemctl is-enabled -q whoopsie.path
|
||||
apport-checkrep 33176 2975 0 /usr/share/apport/apport-checkreports
|
||||
apport-checkrep 33177 2975 0 /usr/share/apport/apport-checkreports --system
|
||||
apport-checkrep 33178 2975 0 /usr/share/apport/apport-checkreports --system
|
||||
|
||||
```
|
||||
|
||||
This shows process information when exec system call is called.
|
||||
|
||||
USAGE message:
|
||||
|
||||
```
|
||||
usage: execsnoop [-h] [-T] [-t] [-x] [--cgroupmap CGROUPMAP]
|
||||
[--mntnsmap MNTNSMAP] [-u USER] [-q] [-n NAME]
|
||||
[-l LINE] [-U] [--max-args MAX_ARGS]
|
||||
|
||||
Trace exec() syscalls
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-T, --time include time column on output (HH:MM:SS)
|
||||
-t, --timestamp include timestamp on output
|
||||
-x, --fails include failed exec()s
|
||||
--cgroupmap CGROUPMAP
|
||||
trace cgroups in this BPF map only
|
||||
--mntnsmap MNTNSMAP trace mount namespaces in this BPF map only
|
||||
-u USER, --uid USER trace this UID only
|
||||
-q, --quote Add quotemarks (") around arguments.
|
||||
-n NAME, --name NAME only print commands matching this name (regex), any
|
||||
arg
|
||||
-l LINE, --line LINE only print commands where arg contains this line
|
||||
(regex)
|
||||
-U, --print-uid print UID column
|
||||
--max-args MAX_ARGS maximum number of arguments parsed and displayed,
|
||||
defaults to 20
|
||||
|
||||
examples:
|
||||
./execsnoop # trace all exec() syscalls
|
||||
./execsnoop -x # include failed exec()s
|
||||
./execsnoop -T # include time (HH:MM:SS)
|
||||
./execsnoop -U # include UID
|
||||
./execsnoop -u 1000 # only trace UID 1000
|
||||
./execsnoop -u user # get user UID and trace only them
|
||||
./execsnoop -t # include timestamps
|
||||
./execsnoop -q # add "quotemarks" around arguments
|
||||
./execsnoop -n main # only print command lines containing "main"
|
||||
./execsnoop -l tpkg # only print command where arguments contains "tpkg"
|
||||
./execsnoop --cgroupmap mappath # only trace cgroups in this BPF map
|
||||
./execsnoop --mntnsmap mappath # only trace mount namespaces in the map
|
||||
|
||||
|
||||
```
|
||||
|
||||
The -T and -t option include time and timestamps on output:
|
||||
|
||||
```
|
||||
# ./execsnoop -T -t
|
||||
TIME TIME(s) PCOMM PID PPID RET ARGS
|
||||
23:35:25 4.335 bash 33360 24577 0 /bin/bash
|
||||
23:35:25 4.338 lesspipe 33361 33360 0 /usr/bin/lesspipe
|
||||
23:35:25 4.340 basename 33362 33361 0 /usr/bin/basename /usr/bin/lesspipe
|
||||
23:35:25 4.342 dirname 33364 33363 0 /usr/bin/dirname /usr/bin/lesspipe
|
||||
23:35:25 4.347 dircolors 33365 33360 0 /usr/bin/dircolors -b
|
||||
23:35:40 19.327 touch 33367 33366 0 /usr/bin/touch /run/udev/gdm-machine-has-hardware-gpu
|
||||
23:35:40 19.329 snap-device-hel 33368 33366 0 /usr/lib/snapd/snap-device-helper change snap_firefox_firefox /devices/pci0000:00/0000:00:02.0/drm/card0 226:0
|
||||
23:35:40 19.331 snap-device-hel 33369 33366 0 /usr/lib/snapd/snap-device-helper change snap_firefox_geckodriver /devices/pci0000:00/0000:00:02.0/drm/card0 226:0
|
||||
23:35:40 19.332 snap-device-hel 33370 33366 0 /usr/lib/snapd/snap-device-helper change snap_snap-store_snap-store /devices/pci0000:00/0000:00:02.0/drm/card0 226:0
|
||||
|
||||
```
|
||||
|
||||
The -u option filtering UID:
|
||||
|
||||
```
|
||||
# ./execsnoop -Uu 1000
|
||||
UID PCOMM PID PPID RET ARGS
|
||||
1000 bash 33604 24577 0 /bin/bash
|
||||
1000 lesspipe 33606 33604 0 /usr/bin/lesspipe
|
||||
1000 basename 33607 33606 0 /usr/bin/basename /usr/bin/lesspipe
|
||||
1000 dirname 33609 33608 0 /usr/bin/dirname /usr/bin/lesspipe
|
||||
1000 dircolors 33610 33604 0 /usr/bin/dircolors -b
|
||||
1000 sleep 33615 33604 0 /usr/bin/sleep
|
||||
1000 sleep 33616 33604 0 /usr/bin/sleep 1
|
||||
1000 clear 33617 33604 0 /usr/bin/clear
|
||||
|
||||
```
|
||||
|
||||
Report bugs to https://github.com/iovisor/bcc/tree/master/libbpf-tools.
|
||||
146
7-execsnoop/execsnoop.bpf.c
Normal file
146
7-execsnoop/execsnoop.bpf.c
Normal file
@@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include "execsnoop.bpf.h"
|
||||
|
||||
const volatile bool filter_cg = false;
|
||||
const volatile bool ignore_failed = true;
|
||||
const volatile uid_t targ_uid = INVALID_UID;
|
||||
const volatile int max_args = DEFAULT_MAXARGS;
|
||||
|
||||
static const struct event empty_event = {};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
|
||||
__type(key, u32);
|
||||
__type(value, u32);
|
||||
__uint(max_entries, 1);
|
||||
} cgroup_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 10240);
|
||||
__type(key, pid_t);
|
||||
__type(value, struct event);
|
||||
} execs 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 __always_inline bool valid_uid(uid_t uid) {
|
||||
return uid != INVALID_UID;
|
||||
}
|
||||
|
||||
SEC("tracepoint/syscalls/sys_enter_execve")
|
||||
int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter* ctx)
|
||||
{
|
||||
u64 id;
|
||||
pid_t pid, tgid;
|
||||
unsigned int ret;
|
||||
struct event *event;
|
||||
struct task_struct *task;
|
||||
const char **args = (const char **)(ctx->args[1]);
|
||||
const char *argp;
|
||||
|
||||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||||
return 0;
|
||||
|
||||
uid_t uid = (u32)bpf_get_current_uid_gid();
|
||||
int i;
|
||||
|
||||
if (valid_uid(targ_uid) && targ_uid != uid)
|
||||
return 0;
|
||||
|
||||
id = bpf_get_current_pid_tgid();
|
||||
pid = (pid_t)id;
|
||||
tgid = id >> 32;
|
||||
if (bpf_map_update_elem(&execs, &pid, &empty_event, BPF_NOEXIST))
|
||||
return 0;
|
||||
|
||||
event = bpf_map_lookup_elem(&execs, &pid);
|
||||
if (!event)
|
||||
return 0;
|
||||
|
||||
event->pid = tgid;
|
||||
event->uid = uid;
|
||||
task = (struct task_struct*)bpf_get_current_task();
|
||||
event->ppid = (pid_t)BPF_CORE_READ(task, real_parent, tgid);
|
||||
event->args_count = 0;
|
||||
event->args_size = 0;
|
||||
|
||||
ret = bpf_probe_read_user_str(event->args, ARGSIZE, (const char*)ctx->args[0]);
|
||||
if (ret <= ARGSIZE) {
|
||||
event->args_size += ret;
|
||||
} else {
|
||||
/* write an empty string */
|
||||
event->args[0] = '\0';
|
||||
event->args_size++;
|
||||
}
|
||||
|
||||
event->args_count++;
|
||||
#pragma unroll
|
||||
for (i = 1; i < TOTAL_MAX_ARGS && i < max_args; i++) {
|
||||
bpf_probe_read_user(&argp, sizeof(argp), &args[i]);
|
||||
if (!argp)
|
||||
return 0;
|
||||
|
||||
if (event->args_size > LAST_ARG)
|
||||
return 0;
|
||||
|
||||
ret = bpf_probe_read_user_str(&event->args[event->args_size], ARGSIZE, argp);
|
||||
if (ret > ARGSIZE)
|
||||
return 0;
|
||||
|
||||
event->args_count++;
|
||||
event->args_size += ret;
|
||||
}
|
||||
/* try to read one more argument to check if there is one */
|
||||
bpf_probe_read_user(&argp, sizeof(argp), &args[max_args]);
|
||||
if (!argp)
|
||||
return 0;
|
||||
|
||||
/* pointer to max_args+1 isn't null, asume we have more arguments */
|
||||
event->args_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tracepoint/syscalls/sys_exit_execve")
|
||||
int tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit* ctx)
|
||||
{
|
||||
u64 id;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
struct event *event;
|
||||
|
||||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||||
return 0;
|
||||
|
||||
u32 uid = (u32)bpf_get_current_uid_gid();
|
||||
|
||||
if (valid_uid(targ_uid) && targ_uid != uid)
|
||||
return 0;
|
||||
id = bpf_get_current_pid_tgid();
|
||||
pid = (pid_t)id;
|
||||
event = bpf_map_lookup_elem(&execs, &pid);
|
||||
if (!event)
|
||||
return 0;
|
||||
ret = ctx->ret;
|
||||
if (ignore_failed && ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
event->retval = ret;
|
||||
bpf_get_current_comm(&event->comm, sizeof(event->comm));
|
||||
size_t len =((size_t)(&((struct event*)0)->args) + event->args_size);
|
||||
if (len <= sizeof(*event))
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, len);
|
||||
cleanup:
|
||||
bpf_map_delete_elem(&execs, &pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
|
||||
26
7-execsnoop/execsnoop.bpf.h
Normal file
26
7-execsnoop/execsnoop.bpf.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __EXECSNOOP_H
|
||||
#define __EXECSNOOP_H
|
||||
|
||||
#define ARGSIZE 128
|
||||
#define TASK_COMM_LEN 16
|
||||
#define TOTAL_MAX_ARGS 60
|
||||
#define DEFAULT_MAXARGS 20
|
||||
#define FULL_MAX_ARGS_ARR (TOTAL_MAX_ARGS * ARGSIZE)
|
||||
#define INVALID_UID ((uid_t)-1)
|
||||
#define LAST_ARG (FULL_MAX_ARGS_ARR - ARGSIZE)
|
||||
|
||||
struct event {
|
||||
int pid;
|
||||
int ppid;
|
||||
int uid;
|
||||
int retval;
|
||||
int args_count;
|
||||
unsigned int args_size;
|
||||
char comm[TASK_COMM_LEN];
|
||||
char args[FULL_MAX_ARGS_ARR];
|
||||
};
|
||||
|
||||
#endif /* __EXECSNOOP_H */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user