mirror of
https://github.com/springzfx/cgproxy.git
synced 2026-01-07 13:07:56 +08:00
replace bcc with libbpf to optimize resource usage
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "execsnoop-libbpf/libbpf"]
|
||||
path = execsnoop-libbpf/libbpf
|
||||
url = https://github.com/libbpf/libbpf.git
|
||||
@@ -8,7 +8,7 @@ add_compile_options(-Wall -Wextra -Wpedantic -Wno-unused-result -Wno-unused-para
|
||||
# for clangd
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
option(with_execsnoop "enable program level proxy control feature, need bcc installed" ON)
|
||||
# option(with_execsnoop "enable program level proxy control feature, need bcc installed" ON)
|
||||
option(build_tools OFF)
|
||||
option(build_test OFF)
|
||||
|
||||
|
||||
6
execsnoop-bcc/CMakeLists.txt
Normal file
6
execsnoop-bcc/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(execsnoop MODULE execsnoop.cpp ../src/common.cpp)
|
||||
target_link_libraries(execsnoop bcc)
|
||||
install(TARGETS execsnoop DESTINATION /usr/lib/cgproxy/ PERMISSIONS ${basic_permission})
|
||||
87
execsnoop-libbpf/Makefile
Normal file
87
execsnoop-libbpf/Makefile
Normal file
@@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
OUTPUT := $(abspath build)
|
||||
CLANG ?= clang
|
||||
CFLAGS ?= -g -O2 -Wall
|
||||
LLVM_STRIP ?= llvm-strip
|
||||
BPFTOOL ?= bpftool
|
||||
LIBBPF_DIR := $(abspath libbpf/src)
|
||||
LIBBPF_OBJ := $(OUTPUT)/usr/lib64/libbpf.a
|
||||
LIBBPF_H := $(OUTPUT)/usr/include
|
||||
INCLUDES := -I$(OUTPUT) -I$(LIBBPF_H)
|
||||
ARCH := $(shell uname -m | sed 's/x86_64/x86/')
|
||||
|
||||
APPS = execsnoop
|
||||
LIBSO = libexecsnoop.so
|
||||
|
||||
.PHONY: all
|
||||
all: $(APPS) $(LIBSO)
|
||||
|
||||
ifeq ($(V),1)
|
||||
Q =
|
||||
msg =
|
||||
else
|
||||
Q = @
|
||||
msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
|
||||
MAKEFLAGS += --no-print-directory
|
||||
endif
|
||||
|
||||
COMMON_OBJ = \
|
||||
$(OUTPUT)/trace_helpers.o \
|
||||
$(OUTPUT)/syscall_helpers.o \
|
||||
$(OUTPUT)/errno_helpers.o \
|
||||
|
||||
|
||||
.PHONY: install
|
||||
install: $(LIBSO)
|
||||
install -D $(LIBSO) -t $(DESTDIR)/usr/lib/cgproxy/
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(call msg,CLEAN)
|
||||
$(Q)rm -rf $(OUTPUT) $(APPS) $(LIBSO)
|
||||
|
||||
$(OUTPUT) $(OUTPUT)/libbpf:
|
||||
$(call msg,MKDIR,$@)
|
||||
$(Q)mkdir -p $@
|
||||
|
||||
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(COMMON_OBJ) | $(OUTPUT)
|
||||
$(call msg,BINARY,$@)
|
||||
$(Q)$(CC) $(CFLAGS) $^ -lelf -lz -o $@
|
||||
|
||||
$(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h
|
||||
|
||||
$(OUTPUT)/%.o: %.c $(wildcard %.h) | $(OUTPUT)
|
||||
$(call msg,CC,$@)
|
||||
$(Q)$(CC) $(CFLAGS) $(INCLUDES) -fPIC -c $(filter %.c,$^) -o $@
|
||||
|
||||
$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT)
|
||||
$(call msg,GEN-SKEL,$@)
|
||||
$(Q)$(BPFTOOL) gen skeleton $< > $@
|
||||
|
||||
$(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) vmlinux.h | $(OUTPUT)
|
||||
$(call msg,BPF,$@)
|
||||
$(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \
|
||||
$(INCLUDES) -c $(filter %.c,$^) -o $@ && \
|
||||
$(LLVM_STRIP) -g $@
|
||||
|
||||
vmlinux.h:
|
||||
$(Q)$(BPFTOOL) btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
||||
|
||||
$(LIBBPF_OBJ): patch
|
||||
$(Q)cd $(LIBBPF_DIR) && make DESTDIR=${OUTPUT} prefix=$(OUTPUT) install install_headers
|
||||
|
||||
patch: | $(LIBBPF_DIR)/Makefile
|
||||
@echo "patching libbpf-fPIC.patch"
|
||||
$(Q)cd libbpf/src && patch -p1 --forward -i ../../libbpf-fPIC.patch || true
|
||||
|
||||
# build libexecsnoop.so
|
||||
$(LIBSO): execsnoop_share.cpp $(OUTPUT)/execsnoop.skel.h $(LIBBPF_OBJ) $(COMMON_OBJ) | $(OUTPUT)
|
||||
$(call msg,LIB,$@)
|
||||
$(Q)$(CXX) -std=c++17 $(CFLAGS) $(INCLUDES) -fPIC $< $(COMMON_OBJ) -shared -lelf -lz -Wl,--no-whole-archive,--no-undefined $(LIBBPF_OBJ) -o $@
|
||||
|
||||
|
||||
# delete failed targets
|
||||
.DELETE_ON_ERROR:
|
||||
# keep intermediate (.skel.h, .bpf.o, etc) targets
|
||||
.SECONDARY:
|
||||
|
||||
232
execsnoop-libbpf/errno_helpers.c
Normal file
232
execsnoop-libbpf/errno_helpers.c
Normal file
@@ -0,0 +1,232 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
// Copyright (c) 2020 Anton Protopopov
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define warn(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
#ifdef __x86_64__
|
||||
static int errno_by_name_x86_64(const char *errno_name)
|
||||
{
|
||||
|
||||
#define strcase(X, N) if (!strcmp(errno_name, (X))) return N
|
||||
|
||||
strcase("EPERM", 1);
|
||||
strcase("ENOENT", 2);
|
||||
strcase("ESRCH", 3);
|
||||
strcase("EINTR", 4);
|
||||
strcase("EIO", 5);
|
||||
strcase("ENXIO", 6);
|
||||
strcase("E2BIG", 7);
|
||||
strcase("ENOEXEC", 8);
|
||||
strcase("EBADF", 9);
|
||||
strcase("ECHILD", 10);
|
||||
strcase("EAGAIN", 11);
|
||||
strcase("EWOULDBLOCK", 11);
|
||||
strcase("ENOMEM", 12);
|
||||
strcase("EACCES", 13);
|
||||
strcase("EFAULT", 14);
|
||||
strcase("ENOTBLK", 15);
|
||||
strcase("EBUSY", 16);
|
||||
strcase("EEXIST", 17);
|
||||
strcase("EXDEV", 18);
|
||||
strcase("ENODEV", 19);
|
||||
strcase("ENOTDIR", 20);
|
||||
strcase("EISDIR", 21);
|
||||
strcase("EINVAL", 22);
|
||||
strcase("ENFILE", 23);
|
||||
strcase("EMFILE", 24);
|
||||
strcase("ENOTTY", 25);
|
||||
strcase("ETXTBSY", 26);
|
||||
strcase("EFBIG", 27);
|
||||
strcase("ENOSPC", 28);
|
||||
strcase("ESPIPE", 29);
|
||||
strcase("EROFS", 30);
|
||||
strcase("EMLINK", 31);
|
||||
strcase("EPIPE", 32);
|
||||
strcase("EDOM", 33);
|
||||
strcase("ERANGE", 34);
|
||||
strcase("EDEADLK", 35);
|
||||
strcase("EDEADLOCK", 35);
|
||||
strcase("ENAMETOOLONG", 36);
|
||||
strcase("ENOLCK", 37);
|
||||
strcase("ENOSYS", 38);
|
||||
strcase("ENOTEMPTY", 39);
|
||||
strcase("ELOOP", 40);
|
||||
strcase("ENOMSG", 42);
|
||||
strcase("EIDRM", 43);
|
||||
strcase("ECHRNG", 44);
|
||||
strcase("EL2NSYNC", 45);
|
||||
strcase("EL3HLT", 46);
|
||||
strcase("EL3RST", 47);
|
||||
strcase("ELNRNG", 48);
|
||||
strcase("EUNATCH", 49);
|
||||
strcase("ENOCSI", 50);
|
||||
strcase("EL2HLT", 51);
|
||||
strcase("EBADE", 52);
|
||||
strcase("EBADR", 53);
|
||||
strcase("EXFULL", 54);
|
||||
strcase("ENOANO", 55);
|
||||
strcase("EBADRQC", 56);
|
||||
strcase("EBADSLT", 57);
|
||||
strcase("EBFONT", 59);
|
||||
strcase("ENOSTR", 60);
|
||||
strcase("ENODATA", 61);
|
||||
strcase("ETIME", 62);
|
||||
strcase("ENOSR", 63);
|
||||
strcase("ENONET", 64);
|
||||
strcase("ENOPKG", 65);
|
||||
strcase("EREMOTE", 66);
|
||||
strcase("ENOLINK", 67);
|
||||
strcase("EADV", 68);
|
||||
strcase("ESRMNT", 69);
|
||||
strcase("ECOMM", 70);
|
||||
strcase("EPROTO", 71);
|
||||
strcase("EMULTIHOP", 72);
|
||||
strcase("EDOTDOT", 73);
|
||||
strcase("EBADMSG", 74);
|
||||
strcase("EOVERFLOW", 75);
|
||||
strcase("ENOTUNIQ", 76);
|
||||
strcase("EBADFD", 77);
|
||||
strcase("EREMCHG", 78);
|
||||
strcase("ELIBACC", 79);
|
||||
strcase("ELIBBAD", 80);
|
||||
strcase("ELIBSCN", 81);
|
||||
strcase("ELIBMAX", 82);
|
||||
strcase("ELIBEXEC", 83);
|
||||
strcase("EILSEQ", 84);
|
||||
strcase("ERESTART", 85);
|
||||
strcase("ESTRPIPE", 86);
|
||||
strcase("EUSERS", 87);
|
||||
strcase("ENOTSOCK", 88);
|
||||
strcase("EDESTADDRREQ", 89);
|
||||
strcase("EMSGSIZE", 90);
|
||||
strcase("EPROTOTYPE", 91);
|
||||
strcase("ENOPROTOOPT", 92);
|
||||
strcase("EPROTONOSUPPORT", 93);
|
||||
strcase("ESOCKTNOSUPPORT", 94);
|
||||
strcase("ENOTSUP", 95);
|
||||
strcase("EOPNOTSUPP", 95);
|
||||
strcase("EPFNOSUPPORT", 96);
|
||||
strcase("EAFNOSUPPORT", 97);
|
||||
strcase("EADDRINUSE", 98);
|
||||
strcase("EADDRNOTAVAIL", 99);
|
||||
strcase("ENETDOWN", 100);
|
||||
strcase("ENETUNREACH", 101);
|
||||
strcase("ENETRESET", 102);
|
||||
strcase("ECONNABORTED", 103);
|
||||
strcase("ECONNRESET", 104);
|
||||
strcase("ENOBUFS", 105);
|
||||
strcase("EISCONN", 106);
|
||||
strcase("ENOTCONN", 107);
|
||||
strcase("ESHUTDOWN", 108);
|
||||
strcase("ETOOMANYREFS", 109);
|
||||
strcase("ETIMEDOUT", 110);
|
||||
strcase("ECONNREFUSED", 111);
|
||||
strcase("EHOSTDOWN", 112);
|
||||
strcase("EHOSTUNREACH", 113);
|
||||
strcase("EALREADY", 114);
|
||||
strcase("EINPROGRESS", 115);
|
||||
strcase("ESTALE", 116);
|
||||
strcase("EUCLEAN", 117);
|
||||
strcase("ENOTNAM", 118);
|
||||
strcase("ENAVAIL", 119);
|
||||
strcase("EISNAM", 120);
|
||||
strcase("EREMOTEIO", 121);
|
||||
strcase("EDQUOT", 122);
|
||||
strcase("ENOMEDIUM", 123);
|
||||
strcase("EMEDIUMTYPE", 124);
|
||||
strcase("ECANCELED", 125);
|
||||
strcase("ENOKEY", 126);
|
||||
strcase("EKEYEXPIRED", 127);
|
||||
strcase("EKEYREVOKED", 128);
|
||||
strcase("EKEYREJECTED", 129);
|
||||
strcase("EOWNERDEAD", 130);
|
||||
strcase("ENOTRECOVERABLE", 131);
|
||||
strcase("ERFKILL", 132);
|
||||
strcase("EHWPOISON", 133);
|
||||
|
||||
#undef strcase
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to find the errno number using the errno(1) program */
|
||||
static int errno_by_name_dynamic(const char *errno_name)
|
||||
{
|
||||
int len = strlen(errno_name);
|
||||
int err, number = -1;
|
||||
char buf[128];
|
||||
char cmd[64];
|
||||
char *end;
|
||||
long val;
|
||||
FILE *f;
|
||||
|
||||
/* sanity check to not call popen with random input */
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (errno_name[i] < 'A' || errno_name[i] > 'Z') {
|
||||
warn("errno_name contains invalid char 0x%02x: %s\n",
|
||||
errno_name[i], errno_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "errno %s", errno_name);
|
||||
f = popen(cmd, "r");
|
||||
if (!f) {
|
||||
warn("popen: %s: %s\n", cmd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), f)) {
|
||||
goto close;
|
||||
} else if (ferror(f)) {
|
||||
warn("fgets: %s\n", strerror(errno));
|
||||
goto close;
|
||||
}
|
||||
|
||||
// expecting "<name> <number> <description>"
|
||||
if (strncmp(errno_name, buf, len) || strlen(buf) < len+2) {
|
||||
warn("expected '%s': %s\n", errno_name, buf);
|
||||
goto close;
|
||||
}
|
||||
errno = 0;
|
||||
val = strtol(buf+len+2, &end, 10);
|
||||
if (errno || end == (buf+len+2) || number < 0 || number > INT_MAX) {
|
||||
warn("can't parse the second column, expected int: %s\n", buf);
|
||||
goto close;
|
||||
}
|
||||
number = val;
|
||||
|
||||
close:
|
||||
err = pclose(f);
|
||||
if (err < 0)
|
||||
warn("pclose: %s\n", strerror(errno));
|
||||
#ifndef __x86_64__
|
||||
/* Ignore the error for x86_64 where we have a table compiled in */
|
||||
else if (err && WEXITSTATUS(err) == 127) {
|
||||
warn("errno(1) required for errno name/number mapping\n");
|
||||
} else if (err) {
|
||||
warn("errno(1) exit status (see wait(2)): 0x%x\n", err);
|
||||
}
|
||||
#endif
|
||||
return number;
|
||||
}
|
||||
|
||||
int errno_by_name(const char *errno_name)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
int err;
|
||||
|
||||
err = errno_by_name_x86_64(errno_name);
|
||||
if (err >= 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
return errno_by_name_dynamic(errno_name);
|
||||
}
|
||||
7
execsnoop-libbpf/errno_helpers.h
Normal file
7
execsnoop-libbpf/errno_helpers.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __ERRNO_HELPERS_H
|
||||
#define __ERRNO_HELPERS_H
|
||||
|
||||
int errno_by_name(const char *errno_name);
|
||||
|
||||
#endif /* __ERRNO_HELPERS_H */
|
||||
128
execsnoop-libbpf/execsnoop.bpf.c
Normal file
128
execsnoop-libbpf/execsnoop.bpf.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include "execsnoop.h"
|
||||
|
||||
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_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;
|
||||
uid_t 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;
|
||||
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 = pid;
|
||||
event->tgid = 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_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 (int i = 1; i < TOTAL_MAX_ARGS && i < max_args; i++) {
|
||||
bpf_probe_read(&argp, sizeof(argp), &args[i]);
|
||||
if (!argp)
|
||||
return 0;
|
||||
|
||||
if (event->args_size > LAST_ARG)
|
||||
return 0;
|
||||
|
||||
ret = bpf_probe_read_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(&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;
|
||||
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 = EVENT_SIZE(event);
|
||||
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";
|
||||
329
execsnoop-libbpf/execsnoop.c
Normal file
329
execsnoop-libbpf/execsnoop.c
Normal file
@@ -0,0 +1,329 @@
|
||||
// Based on execsnoop(8) from BCC by Brendan Gregg and others.
|
||||
//
|
||||
#include <argp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include "execsnoop.h"
|
||||
#include "execsnoop.skel.h"
|
||||
#include "trace_helpers.h"
|
||||
|
||||
#define PERF_BUFFER_PAGES 64
|
||||
#define NSEC_PRECISION (NSEC_PER_SEC / 1000)
|
||||
#define MAX_ARGS_KEY 259
|
||||
|
||||
static struct env {
|
||||
bool time;
|
||||
bool timestamp;
|
||||
bool fails;
|
||||
uid_t uid;
|
||||
bool quote;
|
||||
const char *name;
|
||||
const char *line;
|
||||
bool print_uid;
|
||||
bool verbose;
|
||||
int max_args;
|
||||
} env = {
|
||||
.max_args = DEFAULT_MAXARGS,
|
||||
.uid = INVALID_UID
|
||||
};
|
||||
|
||||
static struct timespec start_time;
|
||||
|
||||
const char *argp_program_version = "execsnoop 0.1";
|
||||
const char *argp_program_bug_address = "<bpf@vger.kernel.org>";
|
||||
const char argp_program_doc[] =
|
||||
"Trace open family syscalls\n"
|
||||
"\n"
|
||||
"USAGE: execsnoop [-h] [-T] [-t] [-x] [-u UID] [-q] [-n NAME] [-l LINE] [-U]\n"
|
||||
" [--max-args MAX_ARGS]\n"
|
||||
"\n"
|
||||
"EXAMPLES:\n"
|
||||
" ./execsnoop # trace all exec() syscalls\n"
|
||||
" ./execsnoop -x # include failed exec()s\n"
|
||||
" ./execsnoop -T # include time (HH:MM:SS)\n"
|
||||
" ./execsnoop -U # include UID\n"
|
||||
" ./execsnoop -u 1000 # only trace UID 1000\n"
|
||||
" ./execsnoop -t # include timestamps\n"
|
||||
" ./execsnoop -q # add \"quotemarks\" around arguments\n"
|
||||
" ./execsnoop -n main # only print command lines containing \"main\"\n"
|
||||
" ./execsnoop -l tpkg # only print command where arguments contains \"tpkg\"";
|
||||
|
||||
static const struct argp_option opts[] = {
|
||||
{ "time", 'T', NULL, 0, "include time column on output (HH:MM:SS)"},
|
||||
{ "timestamp", 't', NULL, 0, "include timestamp on output"},
|
||||
{ "fails", 'x', NULL, 0, "include failed exec()s"},
|
||||
{ "uid", 'u', "UID", 0, "trace this UID only"},
|
||||
{ "quote", 'q', NULL, 0, "Add quotemarks (\") around arguments"},
|
||||
{ "name", 'n', "NAME", 0, "only print commands matching this name, any arg"},
|
||||
{ "line", 'l', "LINE", 0, "only print commands where arg contains this line"},
|
||||
{ "print-uid", 'U', NULL, 0, "print UID column"},
|
||||
{ "max-args", MAX_ARGS_KEY, "MAX_ARGS", 0,
|
||||
"maximum number of arguments parsed and displayed, defaults to 20"},
|
||||
{ "verbose", 'v', NULL, 0, "Verbose debug output" },
|
||||
{},
|
||||
};
|
||||
|
||||
static error_t parse_arg(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
long int uid, max_args;
|
||||
|
||||
switch (key) {
|
||||
case 'h':
|
||||
argp_usage(state);
|
||||
break;
|
||||
case 'T':
|
||||
env.time = true;
|
||||
break;
|
||||
case 't':
|
||||
env.timestamp = true;
|
||||
break;
|
||||
case 'x':
|
||||
env.fails = true;
|
||||
break;
|
||||
case 'u':
|
||||
errno = 0;
|
||||
uid = strtol(arg, NULL, 10);
|
||||
if (errno || uid < 0 || uid >= INVALID_UID) {
|
||||
fprintf(stderr, "Invalid UID %s\n", arg);
|
||||
argp_usage(state);
|
||||
}
|
||||
env.uid = uid;
|
||||
break;
|
||||
case 'q':
|
||||
env.quote = true;
|
||||
break;
|
||||
case 'n':
|
||||
env.name = arg;
|
||||
break;
|
||||
case 'l':
|
||||
env.line = arg;
|
||||
break;
|
||||
case 'U':
|
||||
env.print_uid = true;
|
||||
break;
|
||||
case 'v':
|
||||
env.verbose = true;
|
||||
break;
|
||||
case MAX_ARGS_KEY:
|
||||
errno = 0;
|
||||
max_args = strtol(arg, NULL, 10);
|
||||
if (errno || max_args < 1 || max_args > TOTAL_MAX_ARGS) {
|
||||
fprintf(stderr, "Invalid MAX_ARGS %s, should be in [1, %d] range\n",
|
||||
arg, TOTAL_MAX_ARGS);
|
||||
|
||||
argp_usage(state);
|
||||
}
|
||||
env.max_args = max_args;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libbpf_print_fn(enum libbpf_print_level level,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (level == LIBBPF_DEBUG && !env.verbose)
|
||||
return 0;
|
||||
return vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
static void time_since_start()
|
||||
{
|
||||
long nsec, sec;
|
||||
static struct timespec cur_time;
|
||||
double time_diff;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_time);
|
||||
nsec = cur_time.tv_nsec - start_time.tv_nsec;
|
||||
sec = cur_time.tv_sec - start_time.tv_sec;
|
||||
if (nsec < 0) {
|
||||
nsec += NSEC_PER_SEC;
|
||||
sec--;
|
||||
}
|
||||
time_diff = sec + (double)nsec / NSEC_PER_SEC;
|
||||
printf("%-8.3f", time_diff);
|
||||
}
|
||||
|
||||
static void inline quoted_symbol(char c) {
|
||||
switch(c) {
|
||||
case '"':
|
||||
putchar('\\');
|
||||
putchar('"');
|
||||
break;
|
||||
case '\t':
|
||||
putchar('\\');
|
||||
putchar('t');
|
||||
break;
|
||||
case '\n':
|
||||
putchar('\\');
|
||||
putchar('n');
|
||||
break;
|
||||
default:
|
||||
putchar(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_args(const struct event *e, bool quote)
|
||||
{
|
||||
int args_counter = 0;
|
||||
|
||||
if (env.quote)
|
||||
putchar('"');
|
||||
|
||||
for (int i = 0; i < e->args_size && args_counter < e->args_count; i++) {
|
||||
char c = e->args[i];
|
||||
if (env.quote) {
|
||||
if (c == '\0') {
|
||||
args_counter++;
|
||||
putchar('"');
|
||||
putchar(' ');
|
||||
if (args_counter < e->args_count) {
|
||||
putchar('"');
|
||||
}
|
||||
} else {
|
||||
quoted_symbol(c);
|
||||
}
|
||||
} else {
|
||||
if (c == '\0') {
|
||||
args_counter++;
|
||||
putchar(' ');
|
||||
} else {
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e->args_count == env.max_args + 1) {
|
||||
fputs(" ...", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
|
||||
{
|
||||
const struct event *e = data;
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
char ts[32];
|
||||
|
||||
/* TODO: use pcre lib */
|
||||
if (env.name && strstr(e->comm, env.name) == NULL)
|
||||
return;
|
||||
|
||||
/* TODO: use pcre lib */
|
||||
if (env.line && strstr(e->comm, env.line) == NULL)
|
||||
return;
|
||||
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
|
||||
|
||||
if (env.time) {
|
||||
printf("%-8s ", ts);
|
||||
}
|
||||
if (env.timestamp) {
|
||||
time_since_start();
|
||||
}
|
||||
|
||||
if (env.print_uid)
|
||||
printf("%-6d", e->uid);
|
||||
|
||||
printf("%-16s %-6d %-6d %3d ", e->comm, e->pid, e->ppid, e->retval);
|
||||
print_args(e, env.quote);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
|
||||
{
|
||||
fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static const struct argp argp = {
|
||||
.options = opts,
|
||||
.parser = parse_arg,
|
||||
.doc = argp_program_doc,
|
||||
};
|
||||
struct perf_buffer_opts pb_opts;
|
||||
struct perf_buffer *pb = NULL;
|
||||
struct execsnoop_bpf *obj;
|
||||
int err;
|
||||
|
||||
err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
|
||||
err = bump_memlock_rlimit();
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to increase rlimit: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
obj = execsnoop_bpf__open();
|
||||
if (!obj) {
|
||||
fprintf(stderr, "failed to open and/or load BPF object\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* initialize global data (filtering options) */
|
||||
obj->rodata->ignore_failed = !env.fails;
|
||||
obj->rodata->targ_uid = env.uid;
|
||||
obj->rodata->max_args = env.max_args;
|
||||
|
||||
err = execsnoop_bpf__load(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to load BPF object: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
err = execsnoop_bpf__attach(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to attach BPF programs\n");
|
||||
goto cleanup;
|
||||
}
|
||||
/* print headers */
|
||||
if (env.time) {
|
||||
printf("%-9s", "TIME");
|
||||
}
|
||||
if (env.timestamp) {
|
||||
printf("%-8s ", "TIME(s)");
|
||||
}
|
||||
if (env.print_uid) {
|
||||
printf("%-6s ", "UID");
|
||||
}
|
||||
|
||||
printf("%-16s %-6s %-6s %3s %s\n", "PCOMM", "PID", "PPID", "RET", "ARGS");
|
||||
|
||||
/* setup event callbacks */
|
||||
pb_opts.sample_cb = handle_event;
|
||||
pb_opts.lost_cb = handle_lost_events;
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
|
||||
err = libbpf_get_error(pb);
|
||||
if (err) {
|
||||
pb = NULL;
|
||||
fprintf(stderr, "failed to open perf buffer: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* main: poll */
|
||||
while ((err = perf_buffer__poll(pb, 100)) >= 0)
|
||||
;
|
||||
printf("Error polling perf buffer: %d\n", err);
|
||||
|
||||
cleanup:
|
||||
perf_buffer__free(pb);
|
||||
execsnoop_bpf__destroy(obj);
|
||||
|
||||
return err != 0;
|
||||
}
|
||||
27
execsnoop-libbpf/execsnoop.h
Normal file
27
execsnoop-libbpf/execsnoop.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* 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 BASE_EVENT_SIZE (size_t)(&((struct event*)0)->args)
|
||||
#define EVENT_SIZE(e) (BASE_EVENT_SIZE + e->args_size)
|
||||
#define LAST_ARG (FULL_MAX_ARGS_ARR - ARGSIZE)
|
||||
|
||||
struct event {
|
||||
char comm[TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
pid_t tgid;
|
||||
pid_t ppid;
|
||||
uid_t uid;
|
||||
int retval;
|
||||
int args_count;
|
||||
unsigned int args_size;
|
||||
char args[FULL_MAX_ARGS_ARR];
|
||||
};
|
||||
|
||||
#endif /* __EXECSNOOP_H */
|
||||
101
execsnoop-libbpf/execsnoop_share.cpp
Normal file
101
execsnoop-libbpf/execsnoop_share.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// Based on execsnoop(8) from BCC by Brendan Gregg and others.
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
extern "C" {
|
||||
#define typeof(x) decltype(x)
|
||||
#include "execsnoop.h"
|
||||
#include "execsnoop.skel.h"
|
||||
#include "trace_helpers.h"
|
||||
}
|
||||
#include "execsnoop_share.h"
|
||||
|
||||
#define PERF_BUFFER_PAGES 64
|
||||
#define NSEC_PRECISION (NSEC_PER_SEC / 1000)
|
||||
#define MAX_ARGS_KEY 259
|
||||
|
||||
namespace CGPROXY::EXECSNOOP {
|
||||
|
||||
function<int(int)> callback = NULL;
|
||||
promise<void> status;
|
||||
|
||||
void handle_event(void *ctx, int cpu, void *data, __u32 data_sz) {
|
||||
|
||||
auto e = static_cast<event*>(data);
|
||||
int pid = e->pid;
|
||||
if (callback) callback(pid);
|
||||
|
||||
}
|
||||
|
||||
void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) {
|
||||
fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
|
||||
}
|
||||
|
||||
int execsnoop() {
|
||||
struct perf_buffer_opts pb_opts;
|
||||
struct perf_buffer *pb = NULL;
|
||||
struct execsnoop_bpf *obj;
|
||||
int err;
|
||||
|
||||
// libbpf_set_print(libbpf_print_fn);
|
||||
|
||||
err = bump_memlock_rlimit();
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to increase rlimit: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
obj = execsnoop_bpf__open();
|
||||
if (!obj) {
|
||||
fprintf(stderr, "failed to open and/or load BPF object\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* initialize global data (filtering options) */
|
||||
obj->rodata->ignore_failed = true;
|
||||
|
||||
err = execsnoop_bpf__load(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to load BPF object: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = execsnoop_bpf__attach(obj);
|
||||
if (err) {
|
||||
fprintf(stderr, "failed to attach BPF programs\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* setup event callbacks */
|
||||
pb_opts.sample_cb = handle_event;
|
||||
pb_opts.lost_cb = handle_lost_events;
|
||||
pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
|
||||
err = libbpf_get_error(pb);
|
||||
if (err) {
|
||||
pb = NULL;
|
||||
fprintf(stderr, "failed to open perf buffer: %d\n", err);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status.set_value();
|
||||
|
||||
/* main: poll */
|
||||
while ((err = perf_buffer__poll(pb, 100)) >= 0);
|
||||
printf("Error polling perf buffer: %d\n", err);
|
||||
|
||||
cleanup:
|
||||
perf_buffer__free(pb);
|
||||
execsnoop_bpf__destroy(obj);
|
||||
|
||||
return err != 0;
|
||||
}
|
||||
|
||||
|
||||
void startThread(function<int(int)> c, promise<void> _status) {
|
||||
status = move(_status);
|
||||
callback = c;
|
||||
execsnoop();
|
||||
}
|
||||
}
|
||||
16
execsnoop-libbpf/execsnoop_share.h
Normal file
16
execsnoop-libbpf/execsnoop_share.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef EXECSNOOP_SHARE_HPP
|
||||
#define EXECSNOOP_SHARE_HPP 1
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
namespace CGPROXY::EXECSNOOP {
|
||||
extern "C" void startThread(function<int(int)> c, promise<void> _status);
|
||||
// typedef void startThread_t(function<int(int)>, promise<void>);
|
||||
using startThread_t=decltype(startThread);
|
||||
startThread_t *_startThread; // only for dlsym()
|
||||
|
||||
} // namespace CGPROXY::EXECSNOOP
|
||||
#endif
|
||||
1
execsnoop-libbpf/libbpf
Submodule
1
execsnoop-libbpf/libbpf
Submodule
Submodule execsnoop-libbpf/libbpf added at fb27968bf1
21
execsnoop-libbpf/libbpf-fPIC.patch
Normal file
21
execsnoop-libbpf/libbpf-fPIC.patch
Normal file
@@ -0,0 +1,21 @@
|
||||
diff --git src/Makefile src/Makefile
|
||||
index d0308c3..fcc3b6f 100644
|
||||
--- src/Makefile
|
||||
+++ src/Makefile
|
||||
@@ -15,6 +15,7 @@ ifneq ($(FEATURE_REALLOCARRAY),)
|
||||
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||
endif
|
||||
|
||||
+STATIC_CFLAGS += -fPIC
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall
|
||||
@@ -99,7 +100,7 @@ $(SHARED_OBJDIR):
|
||||
mkdir -p $(SHARED_OBJDIR)
|
||||
|
||||
$(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
|
||||
- $(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
+ $(CC) $(ALL_CFLAGS) $(STATIC_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
$(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
|
||||
$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
11
execsnoop-libbpf/readme.md
Normal file
11
execsnoop-libbpf/readme.md
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
## Depency
|
||||
- libbpf
|
||||
- /usr/lib/libbpf.a
|
||||
- some head file
|
||||
- bpf
|
||||
- `/usr/bin/bpftool` to generate skeleton and dump btf
|
||||
|
||||
## Refer
|
||||
|
||||
- https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html
|
||||
526
execsnoop-libbpf/syscall_helpers.c
Normal file
526
execsnoop-libbpf/syscall_helpers.c
Normal file
@@ -0,0 +1,526 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
// Copyright (c) 2020 Anton Protopopov
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char **syscall_names;
|
||||
static size_t syscall_names_size;
|
||||
|
||||
#define warn(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
static const char *parse_syscall(const char *buf, int *number)
|
||||
{
|
||||
char *end;
|
||||
long x;
|
||||
|
||||
errno = 0;
|
||||
x = strtol(buf, &end, 10);
|
||||
if (errno) {
|
||||
warn("strtol(%s): %s\n", buf, strerror(errno));
|
||||
return NULL;
|
||||
} else if (end == buf) {
|
||||
warn("strtol(%s): no digits found\n", buf);
|
||||
return NULL;
|
||||
} else if (x < 0 || x > INT_MAX) {
|
||||
warn("strtol(%s): bad syscall number: %ld\n", buf, x);
|
||||
return NULL;
|
||||
}
|
||||
if (*end != '\t') {
|
||||
warn("bad input: %s (expected <num>\t<name>)\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*number = x;
|
||||
return ++end;
|
||||
}
|
||||
|
||||
void init_syscall_names(void)
|
||||
{
|
||||
size_t old_size, size = 1024;
|
||||
const char *name;
|
||||
char buf[64];
|
||||
int number;
|
||||
int err;
|
||||
FILE *f;
|
||||
|
||||
f = popen("ausyscall --dump 2>/dev/null", "r");
|
||||
if (!f) {
|
||||
warn("popen: ausyscall --dump: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
syscall_names = calloc(size, sizeof(char *));
|
||||
if (!syscall_names) {
|
||||
warn("calloc: %s\n", strerror(errno));
|
||||
goto close;
|
||||
}
|
||||
|
||||
/* skip the header */
|
||||
fgets(buf, sizeof(buf), f);
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
if (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
name = parse_syscall(buf, &number);
|
||||
if (!name || !name[0])
|
||||
goto close;
|
||||
|
||||
/* In a rare case when syscall number is > than initial 1024 */
|
||||
if (number >= size) {
|
||||
old_size = size;
|
||||
size = 1024 * (1 + number / 1024);
|
||||
syscall_names = realloc(syscall_names,
|
||||
size * sizeof(char *));
|
||||
if (!syscall_names) {
|
||||
warn("realloc: %s\n", strerror(errno));
|
||||
goto close;
|
||||
}
|
||||
memset(syscall_names+old_size, 0,
|
||||
(size - old_size) * sizeof(char *));
|
||||
}
|
||||
|
||||
if (syscall_names[number]) {
|
||||
warn("duplicate number: %d (stored: %s)",
|
||||
number, syscall_names[number]);
|
||||
goto close;
|
||||
}
|
||||
|
||||
syscall_names[number] = strdup(name);
|
||||
if (!syscall_names[number]) {
|
||||
warn("strdup: %s\n", strerror(errno));
|
||||
goto close;
|
||||
}
|
||||
syscall_names_size = MAX(number+1, syscall_names_size);
|
||||
}
|
||||
|
||||
if (ferror(f))
|
||||
warn("fgets: %s\n", strerror(errno));
|
||||
close:
|
||||
err = pclose(f);
|
||||
if (err < 0)
|
||||
warn("pclose: %s\n", strerror(errno));
|
||||
#ifndef __x86_64__
|
||||
/* Ignore the error for x86_64 where we have a table compiled in */
|
||||
else if (err && WEXITSTATUS(err) == 127) {
|
||||
warn("ausyscall required for syscalls number/name mapping\n");
|
||||
} else if (err) {
|
||||
warn("ausyscall exit status (see wait(2)): 0x%x\n", err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_syscall_names(void)
|
||||
{
|
||||
for (size_t i = 0; i < syscall_names_size; i++)
|
||||
free((void *) syscall_names[i]);
|
||||
free(syscall_names);
|
||||
}
|
||||
|
||||
/*
|
||||
* Syscall table for Linux x86_64.
|
||||
*
|
||||
* Semi-automatically generated from strace/linux/x86_64/syscallent.h and
|
||||
* linux/syscallent-common.h using the following commands:
|
||||
*
|
||||
* awk -F\" '/SEN/{printf("%d %s\n", substr($0,2,3), $(NF-1));}' syscallent.h
|
||||
* awk '/SEN/ { printf("%d %s\n", $3, $9); }' syscallent-common.h
|
||||
*
|
||||
* (The idea is taken from src/python/bcc/syscall.py.)
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
static const char *syscall_names_x86_64[] = {
|
||||
[0] = "read",
|
||||
[1] = "write",
|
||||
[2] = "open",
|
||||
[3] = "close",
|
||||
[4] = "stat",
|
||||
[5] = "fstat",
|
||||
[6] = "lstat",
|
||||
[7] = "poll",
|
||||
[8] = "lseek",
|
||||
[9] = "mmap",
|
||||
[10] = "mprotect",
|
||||
[11] = "munmap",
|
||||
[12] = "brk",
|
||||
[13] = "rt_sigaction",
|
||||
[14] = "rt_sigprocmask",
|
||||
[15] = "rt_sigreturn",
|
||||
[16] = "ioctl",
|
||||
[17] = "pread64",
|
||||
[18] = "pwrite64",
|
||||
[19] = "readv",
|
||||
[20] = "writev",
|
||||
[21] = "access",
|
||||
[22] = "pipe",
|
||||
[23] = "select",
|
||||
[24] = "sched_yield",
|
||||
[25] = "mremap",
|
||||
[26] = "msync",
|
||||
[27] = "mincore",
|
||||
[28] = "madvise",
|
||||
[29] = "shmget",
|
||||
[30] = "shmat",
|
||||
[31] = "shmctl",
|
||||
[32] = "dup",
|
||||
[33] = "dup2",
|
||||
[34] = "pause",
|
||||
[35] = "nanosleep",
|
||||
[36] = "getitimer",
|
||||
[37] = "alarm",
|
||||
[38] = "setitimer",
|
||||
[39] = "getpid",
|
||||
[40] = "sendfile",
|
||||
[41] = "socket",
|
||||
[42] = "connect",
|
||||
[43] = "accept",
|
||||
[44] = "sendto",
|
||||
[45] = "recvfrom",
|
||||
[46] = "sendmsg",
|
||||
[47] = "recvmsg",
|
||||
[48] = "shutdown",
|
||||
[49] = "bind",
|
||||
[50] = "listen",
|
||||
[51] = "getsockname",
|
||||
[52] = "getpeername",
|
||||
[53] = "socketpair",
|
||||
[54] = "setsockopt",
|
||||
[55] = "getsockopt",
|
||||
[56] = "clone",
|
||||
[57] = "fork",
|
||||
[58] = "vfork",
|
||||
[59] = "execve",
|
||||
[60] = "exit",
|
||||
[61] = "wait4",
|
||||
[62] = "kill",
|
||||
[63] = "uname",
|
||||
[64] = "semget",
|
||||
[65] = "semop",
|
||||
[66] = "semctl",
|
||||
[67] = "shmdt",
|
||||
[68] = "msgget",
|
||||
[69] = "msgsnd",
|
||||
[70] = "msgrcv",
|
||||
[71] = "msgctl",
|
||||
[72] = "fcntl",
|
||||
[73] = "flock",
|
||||
[74] = "fsync",
|
||||
[75] = "fdatasync",
|
||||
[76] = "truncate",
|
||||
[77] = "ftruncate",
|
||||
[78] = "getdents",
|
||||
[79] = "getcwd",
|
||||
[80] = "chdir",
|
||||
[81] = "fchdir",
|
||||
[82] = "rename",
|
||||
[83] = "mkdir",
|
||||
[84] = "rmdir",
|
||||
[85] = "creat",
|
||||
[86] = "link",
|
||||
[87] = "unlink",
|
||||
[88] = "symlink",
|
||||
[89] = "readlink",
|
||||
[90] = "chmod",
|
||||
[91] = "fchmod",
|
||||
[92] = "chown",
|
||||
[93] = "fchown",
|
||||
[94] = "lchown",
|
||||
[95] = "umask",
|
||||
[96] = "gettimeofday",
|
||||
[97] = "getrlimit",
|
||||
[98] = "getrusage",
|
||||
[99] = "sysinfo",
|
||||
[100] = "times",
|
||||
[101] = "ptrace",
|
||||
[102] = "getuid",
|
||||
[103] = "syslog",
|
||||
[104] = "getgid",
|
||||
[105] = "setuid",
|
||||
[106] = "setgid",
|
||||
[107] = "geteuid",
|
||||
[108] = "getegid",
|
||||
[109] = "setpgid",
|
||||
[110] = "getppid",
|
||||
[111] = "getpgrp",
|
||||
[112] = "setsid",
|
||||
[113] = "setreuid",
|
||||
[114] = "setregid",
|
||||
[115] = "getgroups",
|
||||
[116] = "setgroups",
|
||||
[117] = "setresuid",
|
||||
[118] = "getresuid",
|
||||
[119] = "setresgid",
|
||||
[120] = "getresgid",
|
||||
[121] = "getpgid",
|
||||
[122] = "setfsuid",
|
||||
[123] = "setfsgid",
|
||||
[124] = "getsid",
|
||||
[125] = "capget",
|
||||
[126] = "capset",
|
||||
[127] = "rt_sigpending",
|
||||
[128] = "rt_sigtimedwait",
|
||||
[129] = "rt_sigqueueinfo",
|
||||
[130] = "rt_sigsuspend",
|
||||
[131] = "sigaltstack",
|
||||
[132] = "utime",
|
||||
[133] = "mknod",
|
||||
[134] = "uselib",
|
||||
[135] = "personality",
|
||||
[136] = "ustat",
|
||||
[137] = "statfs",
|
||||
[138] = "fstatfs",
|
||||
[139] = "sysfs",
|
||||
[140] = "getpriority",
|
||||
[141] = "setpriority",
|
||||
[142] = "sched_setparam",
|
||||
[143] = "sched_getparam",
|
||||
[144] = "sched_setscheduler",
|
||||
[145] = "sched_getscheduler",
|
||||
[146] = "sched_get_priority_max",
|
||||
[147] = "sched_get_priority_min",
|
||||
[148] = "sched_rr_get_interval",
|
||||
[149] = "mlock",
|
||||
[150] = "munlock",
|
||||
[151] = "mlockall",
|
||||
[152] = "munlockall",
|
||||
[153] = "vhangup",
|
||||
[154] = "modify_ldt",
|
||||
[155] = "pivot_root",
|
||||
[156] = "_sysctl",
|
||||
[157] = "prctl",
|
||||
[158] = "arch_prctl",
|
||||
[159] = "adjtimex",
|
||||
[160] = "setrlimit",
|
||||
[161] = "chroot",
|
||||
[162] = "sync",
|
||||
[163] = "acct",
|
||||
[164] = "settimeofday",
|
||||
[165] = "mount",
|
||||
[166] = "umount2",
|
||||
[167] = "swapon",
|
||||
[168] = "swapoff",
|
||||
[169] = "reboot",
|
||||
[170] = "sethostname",
|
||||
[171] = "setdomainname",
|
||||
[172] = "iopl",
|
||||
[173] = "ioperm",
|
||||
[174] = "create_module",
|
||||
[175] = "init_module",
|
||||
[176] = "delete_module",
|
||||
[177] = "get_kernel_syms",
|
||||
[178] = "query_module",
|
||||
[179] = "quotactl",
|
||||
[180] = "nfsservctl",
|
||||
[181] = "getpmsg",
|
||||
[182] = "putpmsg",
|
||||
[183] = "afs_syscall",
|
||||
[184] = "tuxcall",
|
||||
[185] = "security",
|
||||
[186] = "gettid",
|
||||
[187] = "readahead",
|
||||
[188] = "setxattr",
|
||||
[189] = "lsetxattr",
|
||||
[190] = "fsetxattr",
|
||||
[191] = "getxattr",
|
||||
[192] = "lgetxattr",
|
||||
[193] = "fgetxattr",
|
||||
[194] = "listxattr",
|
||||
[195] = "llistxattr",
|
||||
[196] = "flistxattr",
|
||||
[197] = "removexattr",
|
||||
[198] = "lremovexattr",
|
||||
[199] = "fremovexattr",
|
||||
[200] = "tkill",
|
||||
[201] = "time",
|
||||
[202] = "futex",
|
||||
[203] = "sched_setaffinity",
|
||||
[204] = "sched_getaffinity",
|
||||
[205] = "set_thread_area",
|
||||
[206] = "io_setup",
|
||||
[207] = "io_destroy",
|
||||
[208] = "io_getevents",
|
||||
[209] = "io_submit",
|
||||
[210] = "io_cancel",
|
||||
[211] = "get_thread_area",
|
||||
[212] = "lookup_dcookie",
|
||||
[213] = "epoll_create",
|
||||
[214] = "epoll_ctl_old",
|
||||
[215] = "epoll_wait_old",
|
||||
[216] = "remap_file_pages",
|
||||
[217] = "getdents64",
|
||||
[218] = "set_tid_address",
|
||||
[219] = "restart_syscall",
|
||||
[220] = "semtimedop",
|
||||
[221] = "fadvise64",
|
||||
[222] = "timer_create",
|
||||
[223] = "timer_settime",
|
||||
[224] = "timer_gettime",
|
||||
[225] = "timer_getoverrun",
|
||||
[226] = "timer_delete",
|
||||
[227] = "clock_settime",
|
||||
[228] = "clock_gettime",
|
||||
[229] = "clock_getres",
|
||||
[230] = "clock_nanosleep",
|
||||
[231] = "exit_group",
|
||||
[232] = "epoll_wait",
|
||||
[233] = "epoll_ctl",
|
||||
[234] = "tgkill",
|
||||
[235] = "utimes",
|
||||
[236] = "vserver",
|
||||
[237] = "mbind",
|
||||
[238] = "set_mempolicy",
|
||||
[239] = "get_mempolicy",
|
||||
[240] = "mq_open",
|
||||
[241] = "mq_unlink",
|
||||
[242] = "mq_timedsend",
|
||||
[243] = "mq_timedreceive",
|
||||
[244] = "mq_notify",
|
||||
[245] = "mq_getsetattr",
|
||||
[246] = "kexec_load",
|
||||
[247] = "waitid",
|
||||
[248] = "add_key",
|
||||
[249] = "request_key",
|
||||
[250] = "keyctl",
|
||||
[251] = "ioprio_set",
|
||||
[252] = "ioprio_get",
|
||||
[253] = "inotify_init",
|
||||
[254] = "inotify_add_watch",
|
||||
[255] = "inotify_rm_watch",
|
||||
[256] = "migrate_pages",
|
||||
[257] = "openat",
|
||||
[258] = "mkdirat",
|
||||
[259] = "mknodat",
|
||||
[260] = "fchownat",
|
||||
[261] = "futimesat",
|
||||
[262] = "newfstatat",
|
||||
[263] = "unlinkat",
|
||||
[264] = "renameat",
|
||||
[265] = "linkat",
|
||||
[266] = "symlinkat",
|
||||
[267] = "readlinkat",
|
||||
[268] = "fchmodat",
|
||||
[269] = "faccessat",
|
||||
[270] = "pselect6",
|
||||
[271] = "ppoll",
|
||||
[272] = "unshare",
|
||||
[273] = "set_robust_list",
|
||||
[274] = "get_robust_list",
|
||||
[275] = "splice",
|
||||
[276] = "tee",
|
||||
[277] = "sync_file_range",
|
||||
[278] = "vmsplice",
|
||||
[279] = "move_pages",
|
||||
[280] = "utimensat",
|
||||
[281] = "epoll_pwait",
|
||||
[282] = "signalfd",
|
||||
[283] = "timerfd_create",
|
||||
[284] = "eventfd",
|
||||
[285] = "fallocate",
|
||||
[286] = "timerfd_settime",
|
||||
[287] = "timerfd_gettime",
|
||||
[288] = "accept4",
|
||||
[289] = "signalfd4",
|
||||
[290] = "eventfd2",
|
||||
[291] = "epoll_create1",
|
||||
[292] = "dup3",
|
||||
[293] = "pipe2",
|
||||
[294] = "inotify_init1",
|
||||
[295] = "preadv",
|
||||
[296] = "pwritev",
|
||||
[297] = "rt_tgsigqueueinfo",
|
||||
[298] = "perf_event_open",
|
||||
[299] = "recvmmsg",
|
||||
[300] = "fanotify_init",
|
||||
[301] = "fanotify_mark",
|
||||
[302] = "prlimit64",
|
||||
[303] = "name_to_handle_at",
|
||||
[304] = "open_by_handle_at",
|
||||
[305] = "clock_adjtime",
|
||||
[306] = "syncfs",
|
||||
[307] = "sendmmsg",
|
||||
[308] = "setns",
|
||||
[309] = "getcpu",
|
||||
[310] = "process_vm_readv",
|
||||
[311] = "process_vm_writev",
|
||||
[312] = "kcmp",
|
||||
[313] = "finit_module",
|
||||
[314] = "sched_setattr",
|
||||
[315] = "sched_getattr",
|
||||
[316] = "renameat2",
|
||||
[317] = "seccomp",
|
||||
[318] = "getrandom",
|
||||
[319] = "memfd_create",
|
||||
[320] = "kexec_file_load",
|
||||
[321] = "bpf",
|
||||
[322] = "execveat",
|
||||
[323] = "userfaultfd",
|
||||
[324] = "membarrier",
|
||||
[325] = "mlock2",
|
||||
[326] = "copy_file_range",
|
||||
[327] = "preadv2",
|
||||
[328] = "pwritev2",
|
||||
[329] = "pkey_mprotect",
|
||||
[330] = "pkey_alloc",
|
||||
[331] = "pkey_free",
|
||||
[332] = "statx",
|
||||
[333] = "io_pgetevents",
|
||||
[334] = "rseq",
|
||||
[424] = "pidfd_send_signal",
|
||||
[425] = "io_uring_setup",
|
||||
[426] = "io_uring_enter",
|
||||
[427] = "io_uring_register",
|
||||
[428] = "open_tree",
|
||||
[429] = "move_mount",
|
||||
[430] = "fsopen",
|
||||
[431] = "fsconfig",
|
||||
[432] = "fsmount",
|
||||
[433] = "fspick",
|
||||
[434] = "pidfd_open",
|
||||
[435] = "clone3",
|
||||
[437] = "openat2",
|
||||
[438] = "pidfd_getfd",
|
||||
};
|
||||
size_t syscall_names_x86_64_size = sizeof(syscall_names_x86_64)/sizeof(char*);
|
||||
#endif
|
||||
|
||||
void syscall_name(unsigned n, char *buf, size_t size)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
if (n < syscall_names_size)
|
||||
name = syscall_names[n];
|
||||
#ifdef __x86_64__
|
||||
else if (n < syscall_names_x86_64_size)
|
||||
name = syscall_names_x86_64[n];
|
||||
#endif
|
||||
|
||||
if (name)
|
||||
strncpy(buf, name, size-1);
|
||||
else
|
||||
snprintf(buf, size, "[unknown: %u]", n);
|
||||
}
|
||||
|
||||
int list_syscalls(void)
|
||||
{
|
||||
const char **list = syscall_names;
|
||||
size_t size = syscall_names_size;
|
||||
|
||||
#ifdef __x86_64__
|
||||
if (!size) {
|
||||
size = syscall_names_x86_64_size;
|
||||
list = syscall_names_x86_64;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (list[i])
|
||||
printf("%3zd: %s\n", i, list[i]);
|
||||
}
|
||||
|
||||
return (!list || !size);
|
||||
}
|
||||
|
||||
12
execsnoop-libbpf/syscall_helpers.h
Normal file
12
execsnoop-libbpf/syscall_helpers.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __SYSCALL_HELPERS_H
|
||||
#define __SYSCALL_HELPERS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void init_syscall_names(void);
|
||||
void free_syscall_names(void);
|
||||
void list_syscalls(void);
|
||||
void syscall_name(unsigned n, char *buf, size_t size);
|
||||
|
||||
#endif /* __SYSCALL_HELPERS_H */
|
||||
234
execsnoop-libbpf/trace_helpers.c
Normal file
234
execsnoop-libbpf/trace_helpers.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
#include "trace_helpers.h"
|
||||
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
struct ksyms {
|
||||
struct ksym *syms;
|
||||
int syms_sz;
|
||||
int syms_cap;
|
||||
char *strs;
|
||||
int strs_sz;
|
||||
int strs_cap;
|
||||
};
|
||||
|
||||
static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned long addr)
|
||||
{
|
||||
size_t new_cap, name_len = strlen(name) + 1;
|
||||
struct ksym *ksym;
|
||||
void *tmp;
|
||||
|
||||
if (ksyms->strs_sz + name_len > ksyms->strs_cap) {
|
||||
new_cap = ksyms->strs_cap * 4 / 3;
|
||||
if (new_cap < ksyms->strs_sz + name_len)
|
||||
new_cap = ksyms->strs_sz + name_len;
|
||||
if (new_cap < 1024)
|
||||
new_cap = 1024;
|
||||
tmp = realloc(ksyms->strs, new_cap);
|
||||
if (!tmp)
|
||||
return -1;
|
||||
ksyms->strs = tmp;
|
||||
ksyms->strs_cap = new_cap;
|
||||
}
|
||||
if (ksyms->syms_sz + 1 > ksyms->syms_cap) {
|
||||
new_cap = ksyms->syms_cap * 4 / 3;
|
||||
if (new_cap < 1024)
|
||||
new_cap = 1024;
|
||||
tmp = realloc(ksyms->syms, sizeof(*ksyms->syms) * new_cap);
|
||||
if (!tmp)
|
||||
return -1;
|
||||
ksyms->syms = tmp;
|
||||
ksyms->syms_cap = new_cap;
|
||||
}
|
||||
|
||||
ksym = &ksyms->syms[ksyms->syms_sz];
|
||||
/* while constructing, re-use pointer as just a plain offset */
|
||||
ksym->name = (void *)(unsigned long)ksyms->strs_sz;
|
||||
ksym->addr = addr;
|
||||
|
||||
memcpy(ksyms->strs + ksyms->strs_sz, name, name_len);
|
||||
ksyms->strs_sz += name_len;
|
||||
ksyms->syms_sz++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ksym_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct ksym *s1 = p1, *s2 = p2;
|
||||
|
||||
if (s1->addr == s2->addr)
|
||||
return strcmp(s1->name, s2->name);
|
||||
return s1->addr < s2->addr ? -1 : 1;
|
||||
}
|
||||
|
||||
struct ksyms *ksyms__load(void)
|
||||
{
|
||||
char sym_type, sym_name[256];
|
||||
struct ksyms *ksyms;
|
||||
unsigned long sym_addr;
|
||||
int i, ret;
|
||||
FILE *f;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
ksyms = calloc(1, sizeof(*ksyms));
|
||||
if (!ksyms)
|
||||
goto err_out;
|
||||
|
||||
while (true) {
|
||||
ret = fscanf(f, "%lx %c %s%*[^\n]\n",
|
||||
&sym_addr, &sym_type, sym_name);
|
||||
if (ret == EOF && feof(f))
|
||||
break;
|
||||
if (ret != 3)
|
||||
goto err_out;
|
||||
if (ksyms__add_symbol(ksyms, sym_name, sym_addr))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* now when strings are finalized, adjust pointers properly */
|
||||
for (i = 0; i < ksyms->syms_sz; i++)
|
||||
ksyms->syms[i].name += (unsigned long)ksyms->strs;
|
||||
|
||||
qsort(ksyms->syms, ksyms->syms_sz, sizeof(*ksyms->syms), ksym_cmp);
|
||||
|
||||
fclose(f);
|
||||
return ksyms;
|
||||
|
||||
err_out:
|
||||
ksyms__free(ksyms);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ksyms__free(struct ksyms *ksyms)
|
||||
{
|
||||
if (!ksyms)
|
||||
return;
|
||||
|
||||
free(ksyms->syms);
|
||||
free(ksyms->strs);
|
||||
free(ksyms);
|
||||
}
|
||||
|
||||
const struct ksym *ksyms__map_addr(const struct ksyms *ksyms,
|
||||
unsigned long addr)
|
||||
{
|
||||
int start = 0, end = ksyms->syms_sz - 1, mid;
|
||||
unsigned long sym_addr;
|
||||
|
||||
/* find largest sym_addr <= addr using binary search */
|
||||
while (start < end) {
|
||||
mid = start + (end - start + 1) / 2;
|
||||
sym_addr = ksyms->syms[mid].addr;
|
||||
|
||||
if (sym_addr <= addr)
|
||||
start = mid;
|
||||
else
|
||||
end = mid - 1;
|
||||
}
|
||||
|
||||
if (start == end && ksyms->syms[start].addr <= addr)
|
||||
return &ksyms->syms[start];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ksyms->syms_sz; i++) {
|
||||
if (strcmp(ksyms->syms[i].name, name) == 0)
|
||||
return &ksyms->syms[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void print_stars(unsigned int val, unsigned int val_max, int width)
|
||||
{
|
||||
int num_stars, num_spaces, i;
|
||||
bool need_plus;
|
||||
|
||||
num_stars = min(val, val_max) * width / val_max;
|
||||
num_spaces = width - num_stars;
|
||||
need_plus = val > val_max;
|
||||
|
||||
for (i = 0; i < num_stars; i++)
|
||||
printf("*");
|
||||
for (i = 0; i < num_spaces; i++)
|
||||
printf(" ");
|
||||
if (need_plus)
|
||||
printf("+");
|
||||
}
|
||||
|
||||
void print_log2_hist(unsigned int *vals, int vals_size, char *val_type)
|
||||
{
|
||||
int stars_max = 40, idx_max = -1;
|
||||
unsigned int val, val_max = 0;
|
||||
unsigned long long low, high;
|
||||
int stars, width, i;
|
||||
|
||||
for (i = 0; i < vals_size; i++) {
|
||||
val = vals[i];
|
||||
if (val > 0)
|
||||
idx_max = i;
|
||||
if (val > val_max)
|
||||
val_max = val;
|
||||
}
|
||||
|
||||
if (idx_max < 0)
|
||||
return;
|
||||
|
||||
printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "",
|
||||
idx_max <= 32 ? 19 : 29, val_type);
|
||||
|
||||
if (idx_max <= 32)
|
||||
stars = stars_max;
|
||||
else
|
||||
stars = stars_max / 2;
|
||||
|
||||
for (i = 0; i <= idx_max; i++) {
|
||||
low = (1ULL << (i + 1)) >> 1;
|
||||
high = (1ULL << (i + 1)) - 1;
|
||||
if (low == high)
|
||||
low -= 1;
|
||||
val = vals[i];
|
||||
width = idx_max <= 32 ? 10 : 20;
|
||||
printf("%*lld -> %-*lld : %-8d |", width, low, width, high, val);
|
||||
print_stars(val, val_max, stars);
|
||||
printf("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long get_ktime_ns(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
|
||||
}
|
||||
|
||||
int bump_memlock_rlimit(void)
|
||||
{
|
||||
struct rlimit rlim_new = {
|
||||
.rlim_cur = RLIM_INFINITY,
|
||||
.rlim_max = RLIM_INFINITY,
|
||||
};
|
||||
|
||||
return setrlimit(RLIMIT_MEMLOCK, &rlim_new);
|
||||
}
|
||||
26
execsnoop-libbpf/trace_helpers.h
Normal file
26
execsnoop-libbpf/trace_helpers.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
#ifndef __TRACE_HELPERS_H
|
||||
#define __TRACE_HELPERS_H
|
||||
|
||||
#define NSEC_PER_SEC 1000000000ULL
|
||||
|
||||
struct ksym {
|
||||
const char *name;
|
||||
unsigned long addr;
|
||||
};
|
||||
|
||||
struct ksyms;
|
||||
|
||||
struct ksyms *ksyms__load(void);
|
||||
void ksyms__free(struct ksyms *ksyms);
|
||||
const struct ksym *ksyms__map_addr(const struct ksyms *ksyms,
|
||||
unsigned long addr);
|
||||
const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms,
|
||||
const char *name);
|
||||
|
||||
void print_log2_hist(unsigned int *vals, int vals_size, char *val_type);
|
||||
|
||||
unsigned long long get_ktime_ns(void);
|
||||
int bump_memlock_rlimit(void);
|
||||
|
||||
#endif /* __TRACE_HELPERS_H */
|
||||
106795
execsnoop-libbpf/vmlinux.h
Normal file
106795
execsnoop-libbpf/vmlinux.h
Normal file
File diff suppressed because it is too large
Load Diff
15
readme.md
15
readme.md
@@ -55,7 +55,8 @@ Main feature:
|
||||
## How to install
|
||||
|
||||
```bash
|
||||
mkdir build && cd build && cmake .. && make && make install
|
||||
cd execsnoop-libbpf && make install
|
||||
mkdir build && cd build && cmake .. && make install
|
||||
```
|
||||
|
||||
- It is alreay in [archlinux AUR](https://aur.archlinux.org/packages/?K=cgproxy).
|
||||
@@ -109,7 +110,7 @@ Config file: **/etc/cgproxy/config.json**
|
||||
|
||||
- **port** tproxy listenning port
|
||||
|
||||
- program level proxy control, need `bcc/libbpfcc` and `linux-headers` installed to work
|
||||
- program level proxy control:
|
||||
|
||||
- **program_proxy** program need to be proxied
|
||||
- **program_noproxy** program that won't be proxied
|
||||
@@ -181,16 +182,6 @@ sudo systemctl restart cgproxy.service
|
||||
cgnoproxy [--debug] --pid <PID>
|
||||
```
|
||||
|
||||
- `cgattach` attach specific process pid to specific cgroup which will create if not exist , cgroup can be only one level down exist cgroup, otherwise created fail.
|
||||
|
||||
You need to set `set(build_tools ON)` in *CmakeLists.txt* to build this.
|
||||
|
||||
```bash
|
||||
cgattch <pid> <cgroup>
|
||||
# example
|
||||
cgattch 9999 /proxy.slice
|
||||
```
|
||||
|
||||
- For more detail command usage, see `man cgproxyd` `man cgproxy` `man cgnoproxy`
|
||||
|
||||
## NOTES
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/execsnoop-libbpf/)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if (with_execsnoop)
|
||||
add_library(execsnoop MODULE execsnoop.cpp common.cpp)
|
||||
target_link_libraries(execsnoop bcc)
|
||||
install(TARGETS execsnoop DESTINATION /usr/lib/cgproxy/ PERMISSIONS ${basic_permission})
|
||||
endif()
|
||||
|
||||
add_executable(main main.cpp
|
||||
common.cpp config.cpp cgroup_attach.cpp
|
||||
socket_client.cpp socket_server.cpp)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "cgroup_attach.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "execsnoop.h"
|
||||
#include "execsnoop_share.h"
|
||||
#include "socket_server.h"
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
|
||||
Reference in New Issue
Block a user