Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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).

Cc: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20230809083440.3209381-6-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Jiri Olsa and committed by
Alexei Starovoitov
b733eead 0b779b61

+36 -1
+1
include/uapi/linux/bpf.h
··· 1642 1642 __aligned_u64 cookies; 1643 1643 __u32 cnt; 1644 1644 __u32 flags; 1645 + __u32 pid; 1645 1646 } uprobe_multi; 1646 1647 }; 1647 1648 } link_create;
+1 -1
kernel/bpf/syscall.c
··· 4882 4882 return err; 4883 4883 } 4884 4884 4885 - #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.flags 4885 + #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid 4886 4886 static int link_create(union bpf_attr *attr, bpfptr_t uattr) 4887 4887 { 4888 4888 struct bpf_prog *prog;
+33
kernel/trace/bpf_trace.c
··· 3003 3003 struct bpf_link link; 3004 3004 u32 cnt; 3005 3005 struct bpf_uprobe *uprobes; 3006 + struct task_struct *task; 3006 3007 }; 3007 3008 3008 3009 struct bpf_uprobe_multi_run_ctx { ··· 3036 3035 struct bpf_uprobe_multi_link *umulti_link; 3037 3036 3038 3037 umulti_link = container_of(link, struct bpf_uprobe_multi_link, link); 3038 + if (umulti_link->task) 3039 + put_task_struct(umulti_link->task); 3039 3040 path_put(&umulti_link->path); 3040 3041 kvfree(umulti_link->uprobes); 3041 3042 kfree(umulti_link); ··· 3062 3059 struct bpf_run_ctx *old_run_ctx; 3063 3060 int err = 0; 3064 3061 3062 + if (link->task && current != link->task) 3063 + return 0; 3064 + 3065 3065 if (sleepable) 3066 3066 rcu_read_lock_trace(); 3067 3067 else ··· 3083 3077 else 3084 3078 rcu_read_unlock(); 3085 3079 return err; 3080 + } 3081 + 3082 + static bool 3083 + uprobe_multi_link_filter(struct uprobe_consumer *con, enum uprobe_filter_ctx ctx, 3084 + struct mm_struct *mm) 3085 + { 3086 + struct bpf_uprobe *uprobe; 3087 + 3088 + uprobe = container_of(con, struct bpf_uprobe, consumer); 3089 + return uprobe->link->task->mm == mm; 3086 3090 } 3087 3091 3088 3092 static int ··· 3128 3112 unsigned long *ref_ctr_offsets = NULL; 3129 3113 struct bpf_link_primer link_primer; 3130 3114 struct bpf_uprobe *uprobes = NULL; 3115 + struct task_struct *task = NULL; 3131 3116 unsigned long __user *uoffsets; 3132 3117 u64 __user *ucookies; 3133 3118 void __user *upath; 3134 3119 u32 flags, cnt, i; 3135 3120 struct path path; 3136 3121 char *name; 3122 + pid_t pid; 3137 3123 int err; 3138 3124 3139 3125 /* no support for 32bit archs yet */ ··· 3179 3161 goto error_path_put; 3180 3162 } 3181 3163 3164 + pid = attr->link_create.uprobe_multi.pid; 3165 + if (pid) { 3166 + rcu_read_lock(); 3167 + task = get_pid_task(find_vpid(pid), PIDTYPE_PID); 3168 + rcu_read_unlock(); 3169 + if (!task) 3170 + goto error_path_put; 3171 + } 3172 + 3182 3173 err = -ENOMEM; 3183 3174 3184 3175 link = kzalloc(sizeof(*link), GFP_KERNEL); ··· 3222 3195 uprobes[i].consumer.ret_handler = uprobe_multi_link_ret_handler; 3223 3196 else 3224 3197 uprobes[i].consumer.handler = uprobe_multi_link_handler; 3198 + 3199 + if (pid) 3200 + uprobes[i].consumer.filter = uprobe_multi_link_filter; 3225 3201 } 3226 3202 3227 3203 link->cnt = cnt; 3228 3204 link->uprobes = uprobes; 3229 3205 link->path = path; 3206 + link->task = task; 3230 3207 3231 3208 bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI, 3232 3209 &bpf_uprobe_multi_link_lops, prog); ··· 3257 3226 kvfree(ref_ctr_offsets); 3258 3227 kvfree(uprobes); 3259 3228 kfree(link); 3229 + if (task) 3230 + put_task_struct(task); 3260 3231 error_path_put: 3261 3232 path_put(&path); 3262 3233 return err;
+1
tools/include/uapi/linux/bpf.h
··· 1642 1642 __aligned_u64 cookies; 1643 1643 __u32 cnt; 1644 1644 __u32 flags; 1645 + __u32 pid; 1645 1646 } uprobe_multi; 1646 1647 }; 1647 1648 } link_create;