{"id":8159,"date":"2024-01-05T01:41:56","date_gmt":"2024-01-04T17:41:56","guid":{"rendered":"https:\/\/yanjingang.com\/blog\/?p=8159"},"modified":"2024-01-15T14:48:46","modified_gmt":"2024-01-15T06:48:46","slug":"ebpf-%e6%8d%95%e8%8e%b7%e8%bf%9b%e7%a8%8b%e5%90%af%e5%8a%a8-%e9%80%80%e5%87%ba%e4%ba%8b%e4%bb%b6","status":"publish","type":"post","link":"https:\/\/yanjingang.com\/blog\/?p=8159","title":{"rendered":"eBPF\u2014\u6355\u83b7\u8fdb\u7a0b\u542f\u52a8\/\u9000\u51fa\u4e8b\u4ef6"},"content":{"rendered":"<p>\u4e0a\u4e00\u6b21\uff0c\u6211\u4eec\u5c1d\u8bd5\u4e86\u7528\u6237\u7a7a\u95f4\u81ea\u5b9a\u4e49\u51fd\u6570\u63a2\u6d4b\uff0c\u91cc\u8fb9\u4f1a\u7528\u5230\u8fdb\u7a0bID\u53c2\u6570\uff0c\u90a3\u4e48\u5b9e\u9645\u4f7f\u7528\u573a\u666f\u4e0b\uff0c\u6211\u4eec\u53ef\u80fd\u9700\u8981\u80fd\u68c0\u6d4b\u5230\u8fdb\u7a0b\u7684\u62c9\u8d77\u548c<span style=\"font-size: 1rem;\">\u9000<\/span>\u51fa\uff0c\u4eca\u5929\u5c31\u4e00\u8d77\u6765\u5b9e\u73b0\u4e0b\u8fd9\u4e2a\u5c0f\u529f\u80fd\u3002<\/p>\n<h1><span id=\"lwptoc\">\u4e00\u3001\u6982\u8ff0<\/span><\/h1>\n<p>eBPF (Extended Berkeley Packet Filter) \u662f Linux \u5185\u6838\u4e0a\u7684\u4e00\u4e2a\u5f3a\u5927\u7684\u7f51\u7edc\u548c\u6027\u80fd\u5206\u6790\u5de5\u5177\uff0c\u5b83\u5141\u8bb8\u5f00\u53d1\u8005\u5728\u5185\u6838\u8fd0\u884c\u65f6\u52a8\u6001\u52a0\u8f7d\u3001\u66f4\u65b0\u548c\u8fd0\u884c\u7528\u6237\u5b9a\u4e49\u7684\u4ee3\u7801\u3002<\/p>\n<p>\u672c\u6587\u4e3b\u8981\u5c1d\u8bd5\u901a\u8fc7\u63a2\u6d4b\u5185\u6838\u7684<span style=\"font-size: 1rem;\">sys_enter_execve\u3001<\/span><span style=\"font-size: 1rem;\">sched_process_exit\u4e8b\u4ef6\uff0c\u6355\u83b7\u8fdb\u7a0b\u7684\u62c9\u8d77\u548c\u9000\u51fa\u4e8b\u4ef6\u3002\u5e76\u901a\u8fc7ring buffer\u8f93\u51fa\u5230\u7528\u6237\u7a7a\u95f4\u7a0b\u5e8f\u4e2d\u3002<\/span><\/p>\n<p>\u4e8b\u5b9e\u4e0a\u6211\u4eec\u8fd8\u53ef\u4ee5\u6355\u83b7\u4e00\u4e9b\u5173\u4e8e\u65b0\u8fdb\u7a0b\u7684\u6709\u8da3\u4fe1\u606f\uff0c\u4f8b\u5982\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u6587\u4ef6\u540d\u3001\u6d4b\u91cf\u8fdb\u7a0b\u7684\u751f\u547d\u5468\u671f\u3001\u6d88\u8017\u7684\u8d44\u6e90\u91cf\u7b49\u3002\u8fd9\u662f\u6df1\u5165\u4e86\u89e3\u5185\u6838\u5185\u90e8\u5e76\u89c2\u5bdf\u4e8b\u7269\u5982\u4f55\u8fd0\u4f5c\u7684\u826f\u597d\u8d77\u70b9\u3002<\/p>\n<h1><span id=\"lwptoc\">\u4e8c\u3001\u63a2\u6d4b\u5b9e\u73b0<\/span><\/h1>\n<h4>1.\u5b9a\u4e49\u4e8b\u4ef6\u4fe1\u606f\u7ed3\u6784\u4f53<\/h4>\n<p>\u6211\u4eec\u65b0\u5efa\u4e00\u4e2aexec.h\u7528\u4e8e\u5b9a\u4e49\u5b58\u50a8\u4e8b\u4ef6\u7684\u7ed3\u6784\u4f53\uff0c\u4ee5\u65b9\u4fbf\u5185\u548c\u7a7a\u95f4\u548c\u7528\u6237\u7a7a\u95f4\u90fd\u53ef\u4ee5\u65b9\u4fbf\u7684\u4f7f\u7528\u5b83\u3002<\/p>\n<pre class=\"pure-highlightjs\"><code class=\"\">#ifndef __EXEC_H\r\n#define __EXEC_H\r\n\r\n#define EXEC_CMD_LEN 128\r\n\r\nstruct event {\r\n    int pid;\r\n    int ppid;\r\n    int uid;\r\n    int retval;\r\n    bool is_exit;\r\n    char cmd[EXEC_CMD_LEN];\r\n    unsigned long long ns;\r\n};\r\n\r\n#endif \/* __EXEC_H *\/<\/code><\/pre>\n<h4>2.ebpf\u63a2\u6d4b\u7a0b\u5e8f\u5b9e\u73b0<\/h4>\n<p>\u5b9a\u4e49ebpf\u7a0b\u5e8fexec.bpf.c\uff0c\u7528\u4e8e\u63a2\u6d4b\u8fdb\u7a0b\u7684\u542f\u52a8\u548c\u9000\u51fa\u4e8b\u4ef6\u3002<\/p>\n<pre class=\"pure-highlightjs\"><code class=\"\">\/**\r\n * \u6355\u83b7 Linux \u5185\u6838\u4e2d\u8fdb\u7a0b\u6267\u884c\u7684\u4e8b\u4ef6\r\n*\/\r\n#include &lt;vmlinux.h&gt;\r\n#include &lt;bpf\/bpf_helpers.h&gt;\r\n#include &lt;bpf\/bpf_core_read.h&gt;\r\n#include \"exec.h\"\r\n\r\n\/\/ \u5b9a\u4e49ring buffer Map\r\nstruct {\r\n    __uint(type, BPF_MAP_TYPE_RINGBUF);\r\n    __uint(max_entries, 256 * 1024);    \/\/ 256 KB\r\n} rb SEC(\".maps\");\r\n\r\n\r\n\/\/ \u6355\u83b7\u8fdb\u7a0b\u6267\u884c\u4e8b\u4ef6\uff0c\u4f7f\u7528 ring buffer \u5411\u7528\u6237\u6001\u6253\u5370\u8f93\u51fa\r\nSEC(\"tracepoint\/syscalls\/sys_enter_execve\")\r\nint snoop_process_start(struct trace_event_raw_sys_enter* ctx)\r\n{\r\n    u64 id;\r\n    pid_t pid;\r\n    struct event *e;\r\n    struct task_struct *task;\r\n\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684\u7528\u6237ID\r\n    uid_t uid = (u32)bpf_get_current_uid_gid();\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0bID\r\n    id = bpf_get_current_pid_tgid();\r\n    pid = id &gt;&gt; 32;\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684task_struct\u7ed3\u6784\u4f53\r\n    task = (struct task_struct*)bpf_get_current_task();\r\n    \/\/ \u8bfb\u53d6\u8fdb\u7a0b\u540d\u79f0\r\n    char *cmd = (char *) BPF_CORE_READ(ctx, args[0]);\r\n\r\n    \/\/ \u9884\u8ba2\u4e00\u4e2aringbuf\u6837\u672c\u7a7a\u95f4\r\n    e = bpf_ringbuf_reserve(&amp;rb, sizeof(*e), 0);\r\n    if (!e)\r\n        return 0;\r\n    \/\/ \u8bbe\u7f6e\u6570\u636e\r\n    e-&gt;pid = pid;\r\n    e-&gt;uid = uid;\r\n    e-&gt;ppid = BPF_CORE_READ(task, real_parent, pid);\r\n    bpf_probe_read_str(&amp;e-&gt;cmd, EXEC_CMD_LEN, cmd);\r\n    e-&gt;ns = bpf_ktime_get_ns();\r\n    \/\/ \u63d0\u4ea4\u5230ringbuf\u7528\u6237\u7a7a\u95f4\u8fdb\u884c\u540e\u5904\u7406\r\n    bpf_ringbuf_submit(e, 0);\r\n\r\n    \/\/ \u4f7f\u7528bpf_printk\u51fd\u6570\u5728\u5185\u6838\u65e5\u5fd7\u4e2d\u6253\u5370 PID \u548c\u6587\u4ef6\u540d\r\n    \/\/ bpf_printk(\"TRACEPOINT EXEC pid = %d, uid = %d, cmd = %s\\n\", pid, uid, e-&gt;cmd);\r\n    return 0;\r\n}\r\n\r\n\/\/ \u76d1\u63a7\u8fdb\u7a0b\u9000\u51fa\u4e8b\u4ef6\uff0c\u4f7f\u7528 ring buffer \u5411\u7528\u6237\u6001\u6253\u5370\u8f93\u51fa\r\nSEC(\"tp\/sched\/sched_process_exit\")\r\nint snoop_process_exit(struct trace_event_raw_sched_process_template* ctx)\r\n{\r\n    struct task_struct *task;\r\n    struct event *e;\r\n    pid_t pid, tid;\r\n    u64 id, ts, *start_ts, start_time = 0;\r\n\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684\u7528\u6237ID\r\n    uid_t uid = (u32)bpf_get_current_uid_gid();\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\/\u7ebf\u7a0bID\r\n    id = bpf_get_current_pid_tgid();\r\n    pid = id &gt;&gt; 32;\r\n    tid = (u32)id;\r\n    \/\/ \u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684task_struct\u7ed3\u6784\u4f53\r\n    task = (struct task_struct *)bpf_get_current_task();\r\n    start_time = BPF_CORE_READ(task, start_time);\r\n\r\n    \/* ignore thread exits *\/\r\n    if (pid != tid)\r\n        return 0;\r\n\r\n    \/\/ \u9884\u8ba2\u4e00\u4e2aringbuf\u6837\u672c\u7a7a\u95f4\r\n    e = bpf_ringbuf_reserve(&amp;rb, sizeof(*e), 0);\r\n    if (!e)\r\n        return 0;\r\n    \/\/ \u8bbe\u7f6e\u6570\u636e\r\n    e-&gt;ns = bpf_ktime_get_ns() - start_time;\r\n    e-&gt;pid = pid;\r\n    e-&gt;uid = uid;\r\n    e-&gt;ppid = BPF_CORE_READ(task, real_parent, tgid);\r\n    e-&gt;is_exit = true;\r\n    e-&gt;retval = (BPF_CORE_READ(task, exit_code) &gt;&gt; 8) &amp; 0xff;\r\n    bpf_get_current_comm(&amp;e-&gt;cmd, sizeof(e-&gt;cmd));\r\n    \/\/ \u63d0\u4ea4\u5230ringbuf\u7528\u6237\u7a7a\u95f4\u8fdb\u884c\u540e\u5904\u7406\r\n    bpf_ringbuf_submit(e, 0);\r\n\r\n    \/\/ \u4f7f\u7528bpf_printk\u51fd\u6570\u5728\u5185\u6838\u65e5\u5fd7\u4e2d\u6253\u5370 PID \u548c\u6587\u4ef6\u540d\r\n    \/\/ bpf_printk(\"TRACEPOINT EXIT pid = %d, uid = %d, cmd = %s\\n\", pid, uid, e-&gt;cmd);\r\n    return 0;\r\n}\r\n\r\nchar LICENSE[] SEC(\"license\") = \"GPL\";<\/code><\/pre>\n<h4>3.\u7528\u6237\u7a7a\u95f4\u7a0b\u5e8f\u5b9e\u73b0<\/h4>\n<p>\u7f16\u5199\u7528\u6237\u7a7a\u95f4\u7a0b\u5e8fexec.cc\uff0c\u52a0\u8f7debpf\u7a0b\u5e8f\u5230\u5185\u6838\u5e76\u8bfb\u53d6ringbuffer\u4e2d\u7684\u63a2\u6d4b\u6570\u636e\u3002<\/p>\n<pre class=\"pure-highlightjs\"><code class=\"\">\/**\r\n * ebpf \u7528\u6237\u7a7a\u95f4\u7a0b\u5e8f(loader\u3001read perf buffer)\r\n*\/\r\n#include &lt;stdio.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;signal.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;time.h&gt;\r\n#include &lt;errno.h&gt;\r\n#include &lt;sys\/resource.h&gt;\r\n#include &lt;bpf\/libbpf.h&gt;\r\n#include \"exec.skel.h\"\r\n#include \"exec.h\"\r\n\r\nint libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)\r\n{\r\n\t\/* Ignore debug-level libbpf logs *\/\r\n\tif (level &gt; LIBBPF_INFO)\r\n\t\treturn 0;\r\n\treturn vfprintf(stderr, format, args);\r\n}\r\n\r\n\/\/ Control-C process\r\nstatic volatile bool exiting = false;\r\nstatic void sig_handler(int sig)\r\n{\r\n\texiting = true;\r\n}\r\n\r\n\/\/ ring buffer data process\r\nstatic int handle_event(void *ctx, void *data, size_t data_sz)\r\n{\r\n    const struct event *e = reinterpret_cast&lt;struct event *&gt;(data);\r\n    struct tm *tm;\r\n    char ts[32];\r\n    time_t t;\r\n\r\n    time(&amp;t);\r\n    tm = localtime(&amp;t);\r\n    strftime(ts, sizeof(ts), \"%H:%M:%S\", tm);\r\n\r\n    if (e-&gt;is_exit) {\r\n        printf(\"%s %-5s %d %d %s %d %llums\\n\", ts, \"EXIT\", e-&gt;pid, e-&gt;uid, e-&gt;cmd, e-&gt;retval, e-&gt;ns \/ 1000000);\r\n    } else {\r\n        printf(\"%s %-5s %d %d %s\\n\", ts, \"EXEC\", e-&gt;pid, e-&gt;uid, e-&gt;cmd);\r\n    }\r\n\r\n    return 0;\r\n}\r\n\r\nint main(int argc, char **argv)\r\n{\r\n    struct exec_bpf *skel;\r\n    int err;\r\n    struct ring_buffer *rb = NULL;\r\n\r\n    \/* \u8bbe\u7f6elibbpf\u9519\u8bef\u548c\u8c03\u8bd5\u4fe1\u606f\u56de\u8c03 *\/\r\n    libbpf_set_print(libbpf_print_fn);\r\n\r\n    \/* Control-C \u505c\u6b62\u4fe1\u53f7 *\/\r\n\tsignal(SIGINT, sig_handler);\r\n\tsignal(SIGTERM, sig_handler);\r\n\r\n    \/* \u52a0\u8f7d\u5e76\u9a8c\u8bc1 exec.bpf.c \u5e94\u7528\u7a0b\u5e8f *\/\r\n    skel = exec_bpf__open_and_load();\r\n    if (!skel) {\r\n        fprintf(stderr, \"Failed to open BPF skeleton\\n\");\r\n        return 1;\r\n    }\r\n\r\n    \/* \u9644\u52a0 exec.bpf.c \u7a0b\u5e8f\u5230\u8ddf\u8e2a\u70b9 *\/\r\n    err = exec_bpf__attach(skel);\r\n    if (err) {\r\n        fprintf(stderr, \"Failed to attach BPF skeleton\\n\");\r\n        exec_bpf__destroy(skel);\r\n        return -err;\r\n    }\r\n    \/\/ printf(\"Successfully started! Please run `sudo cat \/sys\/kernel\/debug\/tracing\/trace_pipe` to see output of the BPF programs.\\n\");\r\n\r\n    \/* \u8bbe\u7f6e\u73af\u5f62\u7f13\u51b2\u533a\u8f6e\u8be2 *\/\r\n    rb = ring_buffer__new(bpf_map__fd(skel-&gt;maps.rb), handle_event, NULL, NULL);\r\n    if (!rb) {\r\n        err = -1;\r\n        fprintf(stderr, \"Failed to create ring buffer\\n\");\r\n        exec_bpf__destroy(skel);\r\n        return -err;\r\n    }\r\n\r\n    \/* \u5904\u7406\u6536\u5230\u7684\u5185\u6838\u6570\u636e *\/\r\n    printf(\"%-8s %-8s %-7s %-7s %-16s %-8s %-8s\\n\", \"TIME\", \"TYPE\", \"PID\", \"UID\", \"CMD\", \"RET\", \"DURATION\");\r\n    while (!exiting) {\r\n        \/\/ \u8f6e\u8be2\u5185\u6838\u6570\u636e\r\n        err = ring_buffer__poll(rb, 100 \/* timeout, ms *\/);\r\n        if (err == -EINTR) {    \/* Ctrl-C will cause -EINTR *\/\r\n            err = 0;\r\n            break;\r\n        }\r\n        if (err &lt; 0) {\r\n            printf(\"Error polling perf buffer: %d\\n\", err);\r\n            break;\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<h4>4.\u7f16\u8bd1\u6d4b\u8bd5<\/h4>\n<pre class=\"pure-highlightjs\"><code class=\"\">cd build\r\ncmake ..\r\nmake\r\n\r\nsudo .\/exec\r\n    TIME     TYPE     PID     UID     CMD              RET      DURATION\r\n    10:37:29 EXEC  459980 1000 \/usr\/bin\/ls\r\n    10:37:29 EXIT  459980 1000 ls 0 3ms<\/code><\/pre>\n<h1>\u4e09\u3001\u603b\u7ed3<\/h1>\n<p>\u672c\u6587\u4e3b\u8981\u5c1d\u8bd5\u901a\u8fc7\u63a2\u6d4b\u5185\u6838\u7684<span style=\"font-size: 1rem;\">sys_enter_execve\u3001<\/span><span style=\"font-size: 1rem;\">sched_process_exit\u4e8b\u4ef6\uff0c\u6355\u83b7\u8fdb\u7a0b\u7684\u62c9\u8d77\u548c\u9000\u51fa\u4e8b\u4ef6\uff0c\u5e76\u901a\u8fc7ring buffer\u8f93\u51fa\u5230\u7528\u6237\u7a7a\u95f4\u7a0b\u5e8f\u4e2d\u4f9b\u4f7f\u7528\u6216\u5206\u6790\u3002<\/span><\/p>\n<p>\u597d\u4e86\uff0c\u672c\u6587\u76f8\u5bf9\u6bd4\u8f83\u7b80\u5355\uff0c\u5927\u5bb6\u6709\u5bf9\u54ea\u4e9b\u5185\u5bb9\u611f\u5174\u8da3\u5e0c\u671b\u6211\u4ecb\u7ecd\u7684\uff0c\u53ef\u4ee5\u7559\u8a00\u544a\u8bc9\u6211\uff5e<\/p>\n<p>&nbsp;<\/p>\n<p>yan 23.1.5<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e0a\u4e00\u6b21\uff0c\u6211\u4eec\u5c1d\u8bd5\u4e86\u7528\u6237\u7a7a\u95f4\u81ea\u5b9a\u4e49\u51fd\u6570\u63a2\u6d4b\uff0c\u91cc\u8fb9\u4f1a\u7528\u5230\u8fdb\u7a0bID\u53c2\u6570\uff0c\u90a3\u4e48\u5b9e\u9645\u4f7f\u7528\u573a\u666f\u4e0b\uff0c\u6211\u4eec\u53ef\u80fd\u9700\u8981\u80fd\u68c0\u6d4b\u5230\u8fdb\u7a0b [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1317],"tags":[1318,1334,1335],"_links":{"self":[{"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/8159"}],"collection":[{"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8159"}],"version-history":[{"count":3,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/8159\/revisions"}],"predecessor-version":[{"id":8194,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/8159\/revisions\/8194"}],"wp:attachment":[{"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8159"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8159"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yanjingang.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8159"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}