From 719e10037e7eb9a4fd8754766535277de8db4075 Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Sun, 6 Aug 2017 14:33:20 +0200 Subject: [PATCH] Trace external pointers from helpers At this time, a single helper can return a kernel pointer, bpf_get_current_task. --- src/cc/frontends/clang/b_frontend_action.cc | 3 +++ tests/python/test_clang.py | 26 ++++++++++++++++++++- tools/cpuunclaimed.py | 4 ++-- tools/mountsnoop.py | 14 +++++------ tools/runqlen.py | 4 ++-- 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc index b2f9206d..87ed228b 100644 --- a/src/cc/frontends/clang/b_frontend_action.cc +++ b/src/cc/frontends/clang/b_frontend_action.cc @@ -77,6 +77,9 @@ class ProbeChecker : public RecursiveASTVisitor { } bool VisitCallExpr(CallExpr *E) { needs_probe_ = false; + if (VarDecl *V = dyn_cast(E->getCalleeDecl())) { + needs_probe_ = V->getName() == "bpf_get_current_task"; + } return false; } bool VisitParenExpr(ParenExpr *E) { diff --git a/tests/python/test_clang.py b/tests/python/test_clang.py index 5d9f0368..376a5dc5 100755 --- a/tests/python/test_clang.py +++ b/tests/python/test_clang.py @@ -4,10 +4,11 @@ from bcc import BPF import ctypes as ct -from unittest import main, TestCase +from unittest import main, skipUnless, TestCase import os import sys from contextlib import contextmanager +import distutils.version @contextmanager def redirect_stderr(to): @@ -21,6 +22,17 @@ def redirect_stderr(to): sys.stderr.flush() os.dup2(copied.fileno(), stderr_fd) +def kernel_version_ge(major, minor): + # True if running kernel is >= X.Y + version = distutils.version.LooseVersion(os.uname()[2]).version + if version[0] > major: + return True + if version[0] < major: + return False + if minor and version[1] < minor: + return False + return True + class TestClang(TestCase): def test_complex(self): b = BPF(src_file="test_clang_complex.c", debug=0) @@ -454,6 +466,18 @@ int dns_test(struct __sk_buff *skb) { """ b = BPF(text=text) + @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8") + def test_ext_ptr_from_helper(self): + text = """ +#include +int test(struct pt_regs *ctx) { + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + return task->prio; +} +""" + b = BPF(text=text) + fn = b.load_func("test", BPF.KPROBE) + def test_unary_operator(self): text = """ #include diff --git a/tools/cpuunclaimed.py b/tools/cpuunclaimed.py index 364e80e1..58b8e4ac 100755 --- a/tools/cpuunclaimed.py +++ b/tools/cpuunclaimed.py @@ -144,8 +144,8 @@ int do_perf_event(struct bpf_perf_event_data *ctx) struct task_struct *task = NULL; struct cfs_rq_partial *my_q = NULL; task = (struct task_struct *)bpf_get_current_task(); - bpf_probe_read(&my_q, sizeof(my_q), &task->se.cfs_rq); - bpf_probe_read(&len, sizeof(len), &my_q->nr_running); + my_q = (struct cfs_rq_partial *)task->se.cfs_rq; + len = my_q->nr_running; struct data_t data = {.ts = now, .cpu = cpu, .len = len}; events.perf_submit(ctx, &data, sizeof(data)); diff --git a/tools/mountsnoop.py b/tools/mountsnoop.py index a7a3973a..223b2f8d 100755 --- a/tools/mountsnoop.py +++ b/tools/mountsnoop.py @@ -104,10 +104,9 @@ int kprobe__sys_mount(struct pt_regs *ctx, char __user *source, bpf_get_current_comm(event.enter.comm, sizeof(event.enter.comm)); event.enter.flags = flags; task = (struct task_struct *)bpf_get_current_task(); - bpf_probe_read(&nsproxy, sizeof(nsproxy), &task->nsproxy); - bpf_probe_read(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns); - bpf_probe_read(&event.enter.mnt_ns, sizeof(event.enter.mnt_ns), - &mnt_ns->ns.inum); + nsproxy = task->nsproxy; + mnt_ns = nsproxy->mnt_ns; + event.enter.mnt_ns = mnt_ns->ns.inum; events.perf_submit(ctx, &event, sizeof(event)); event.type = EVENT_MOUNT_SOURCE; @@ -160,10 +159,9 @@ int kprobe__sys_umount(struct pt_regs *ctx, char __user *target, int flags) bpf_get_current_comm(event.enter.comm, sizeof(event.enter.comm)); event.enter.flags = flags; task = (struct task_struct *)bpf_get_current_task(); - bpf_probe_read(&nsproxy, sizeof(nsproxy), &task->nsproxy); - bpf_probe_read(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns); - bpf_probe_read(&event.enter.mnt_ns, sizeof(event.enter.mnt_ns), - &mnt_ns->ns.inum); + nsproxy = task->nsproxy; + mnt_ns = nsproxy->mnt_ns; + event.enter.mnt_ns = mnt_ns->ns.inum; events.perf_submit(ctx, &event, sizeof(event)); event.type = EVENT_UMOUNT_TARGET; diff --git a/tools/runqlen.py b/tools/runqlen.py index 4c8a0952..4a6bc48a 100755 --- a/tools/runqlen.py +++ b/tools/runqlen.py @@ -81,8 +81,8 @@ int do_perf_event() // of BPF will support task_rq(p) or something similar as a more reliable // interface. task = (struct task_struct *)bpf_get_current_task(); - bpf_probe_read(&my_q, sizeof(my_q), &task->se.cfs_rq); - bpf_probe_read(&len, sizeof(len), &my_q->nr_running); + my_q = (struct cfs_rq_partial *)task->se.cfs_rq; + len = my_q->nr_running; // Calculate run queue length by subtracting the currently running task, // if present. len 0 == idle, len 1 == one running task. -- 2.34.1