History

bpf: Add pid filter support for uprobe_multi link

Adding support to specify pid for uprobe_multi link and the uprobes are created only for task with given pid value. Using the consumer.filter filter callback for that, so the task gets filtered during the uprobe installation. We still need to check the task during runtime in the uprobe handler, because the handler could get executed if there's another system wide consumer on the same uprobe (thanks Oleg for the insight).

Jiri Olsa committed 3 years ago

Commit b733eea1 parent 0b779b64 files · +36 −1Browse files

Unified · Split

4 files
  1. include/uapi/linux/bpf.h +1 −0
  2. kernel/bpf/syscall.c +1 −1
  3. kernel/trace/bpf_trace.c +33 −0
  4. tools/include/uapi/linux/bpf.h +1 −0
include/uapi/linux/bpf.h+1−0
@@ -1642,6 +1642,7 @@ union bpf_attr { · 1641 unmodified lines
16421642 __aligned_u64 cookies;
16431643 __u32 cnt;
16441644 __u32 flags;
1645+ __u32 pid;
16451646 } uprobe_multi;
16461647 };
16471648 } link_create;
kernel/bpf/syscall.c+1−1
@@ -4882,7 +4882,7 @@ err_put: · 4881 unmodified lines
48824882 return err;
48834883 }
48844884
4885−#define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.flags
4885+#define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid
48864886 static int link_create(union bpf_attr *attr, bpfptr_t uattr)
48874887 {
48884888 struct bpf_prog *prog;
kernel/trace/bpf_trace.c+33−0
@@ -3003,6 +3003,7 @@ struct bpf_uprobe_multi_link { · 3002 unmodified lines
30033003 struct bpf_link link;
30043004 u32 cnt;
30053005 struct bpf_uprobe *uprobes;
3006+ struct task_struct *task;
30063007 };
30073008
30083009 struct bpf_uprobe_multi_run_ctx {
@@ -3035,6 +3036,8 @@ static void bpf_uprobe_multi_link_dealloc(struct bpf_link *link) · 26 unmodified lines
30353036 struct bpf_uprobe_multi_link *umulti_link;
30363037
30373038 umulti_link = container_of(link, struct bpf_uprobe_multi_link, link);
3039+ if (umulti_link->task)
3040+ put_task_struct(umulti_link->task);
30383041 path_put(&umulti_link->path);
30393042 kvfree(umulti_link->uprobes);
30403043 kfree(umulti_link);
@@ -3059,6 +3062,9 @@ static int uprobe_prog_run(struct bpf_uprobe *uprobe, · 18 unmodified lines
30593062 struct bpf_run_ctx *old_run_ctx;
30603063 int err = 0;
30613064
3065+ if (link->task && current != link->task)
3066+ return 0;
3067+
30623068 if (sleepable)
30633069 rcu_read_lock_trace();
30643070 else
@@ -3079,6 +3085,16 @@ static int uprobe_prog_run(struct bpf_uprobe *uprobe, · 14 unmodified lines
30793085 return err;
30803086 }
30813087
3088+static bool
3089+uprobe_multi_link_filter(struct uprobe_consumer *con, enum uprobe_filter_ctx ctx,
3090+ struct mm_struct *mm)
3091+{
3092+ struct bpf_uprobe *uprobe;
3093+
3094+ uprobe = container_of(con, struct bpf_uprobe, consumer);
3095+ return uprobe->link->task->mm == mm;
3096+}
3097+
30823098 static int
30833099 uprobe_multi_link_handler(struct uprobe_consumer *con, struct pt_regs *regs)
30843100 {
@@ -3112,12 +3128,14 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 27 unmodified lines
31123128 unsigned long *ref_ctr_offsets = NULL;
31133129 struct bpf_link_primer link_primer;
31143130 struct bpf_uprobe *uprobes = NULL;
3131+ struct task_struct *task = NULL;
31153132 unsigned long __user *uoffsets;
31163133 u64 __user *ucookies;
31173134 void __user *upath;
31183135 u32 flags, cnt, i;
31193136 struct path path;
31203137 char *name;
3138+ pid_t pid;
31213139 int err;
31223140
31233141 /* no support for 32bit archs yet */
@@ -3161,6 +3179,15 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 37 unmodified lines
31613179 goto error_path_put;
31623180 }
31633181
3182+ pid = attr->link_create.uprobe_multi.pid;
3183+ if (pid) {
3184+ rcu_read_lock();
3185+ task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
3186+ rcu_read_unlock();
3187+ if (!task)
3188+ goto error_path_put;
3189+ }
3190+
31643191 err = -ENOMEM;
31653192
31663193 link = kzalloc(sizeof(*link), GFP_KERNEL);
@@ -3195,11 +3222,15 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 28 unmodified lines
31953222 uprobes[i].consumer.ret_handler = uprobe_multi_link_ret_handler;
31963223 else
31973224 uprobes[i].consumer.handler = uprobe_multi_link_handler;
3225+
3226+ if (pid)
3227+ uprobes[i].consumer.filter = uprobe_multi_link_filter;
31983228 }
31993229
32003230 link->cnt = cnt;
32013231 link->uprobes = uprobes;
32023232 link->path = path;
3233+ link->task = task;
32033234
32043235 bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI,
32053236 &bpf_uprobe_multi_link_lops, prog);
@@ -3226,6 +3257,8 @@ error_free: · 20 unmodified lines
32263257 kvfree(ref_ctr_offsets);
32273258 kvfree(uprobes);
32283259 kfree(link);
3260+ if (task)
3261+ put_task_struct(task);
32293262 error_path_put:
32303263 path_put(&path);
32313264 return err;
tools/include/uapi/linux/bpf.h+1−0
@@ -1642,6 +1642,7 @@ union bpf_attr { · 1641 unmodified lines
16421642 __aligned_u64 cookies;
16431643 __u32 cnt;
16441644 __u32 flags;
1645+ __u32 pid;
16451646 } uprobe_multi;
16461647 };
16471648 } link_create;