d_real() is about to be able to fail for D_REAL_DATA. So switch bpf_uprobe_multi_link_attach() from d_real_inode() to d_real_data_inode() and deal with the error. Currently, the real inode is resolved again for every single uprobe of the link. There's no point in doing that. Resolve it once right after the d_is_reg() check and fail BPF_LINK_CREATE with the error if the data of the file can't be resolved. Then all uprobes of the link are registered on the same inode. This is a no-op until d_real() can actually fail. Signed-off-by: Christian Brauner (Amutable) --- kernel/trace/bpf_trace.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 2aec56d7f3d3e..15f32b971326e 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -3280,6 +3280,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr struct bpf_uprobe *uprobes = NULL; struct task_struct *task = NULL; unsigned long __user *uoffsets; + struct inode *inode; u64 __user *ucookies; unsigned long size; u32 flags, cnt, i; @@ -3336,6 +3337,12 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr goto error_path_put; } + inode = d_real_data_inode(path.dentry); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error_path_put; + } + if (pid) { rcu_read_lock(); task = get_pid_task(find_vpid(pid), PIDTYPE_TGID); @@ -3394,7 +3401,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr &bpf_uprobe_multi_link_lops, prog, attr->link_create.attach_type); for (i = 0; i < cnt; i++) { - uprobes[i].uprobe = uprobe_register(d_real_inode(link->path.dentry), + uprobes[i].uprobe = uprobe_register(inode, uprobes[i].offset, uprobes[i].ref_ctr_offset, &uprobes[i].consumer); -- 2.53.0