Adding support to get uprobe_link details through bpf_link_info interface. Adding new struct uprobe_multi to struct bpf_link_info to carry the uprobe_multi link details. The uprobe_multi.count is passed from user space to denote size of array fields (offsets/ref_ctr_offsets/cookies). The actual array size is stored back to uprobe_multi.count (allowing user to find out the actual array size) and array fields are populated up to the user passed size. All the non-array fields (path/count/flags/pid) are always set.
Showing the changes to kernel (1 of 3 files). Show all
Unified · Split
| @@ -3042,6 +3042,7 @@ struct bpf_uprobe_multi_link { · 3041 unmodified lines | ||
| 3042 | 3042 | struct path path; |
| 3043 | 3043 | struct bpf_link link; |
| 3044 | 3044 | u32 cnt; |
| 3045 | + u32 flags; | |
| 3045 | 3046 | struct bpf_uprobe *uprobes; |
| 3046 | 3047 | struct task_struct *task; |
| 3047 | 3048 | }; |
| @@ -3083,9 +3084,79 @@ static void bpf_uprobe_multi_link_dealloc(struct bpf_link *link) · 35 unmodified lines | ||
| 3083 | 3084 | kfree(umulti_link); |
| 3084 | 3085 | } |
| 3085 | 3086 | |
| 3087 | +static int bpf_uprobe_multi_link_fill_link_info(const struct bpf_link *link, | |
| 3088 | + struct bpf_link_info *info) | |
| 3089 | +{ | |
| 3090 | + u64 __user *uref_ctr_offsets = u64_to_user_ptr(info->uprobe_multi.ref_ctr_offsets); | |
| 3091 | + u64 __user *ucookies = u64_to_user_ptr(info->uprobe_multi.cookies); | |
| 3092 | + u64 __user *uoffsets = u64_to_user_ptr(info->uprobe_multi.offsets); | |
| 3093 | + u64 __user *upath = u64_to_user_ptr(info->uprobe_multi.path); | |
| 3094 | + u32 upath_size = info->uprobe_multi.path_size; | |
| 3095 | + struct bpf_uprobe_multi_link *umulti_link; | |
| 3096 | + u32 ucount = info->uprobe_multi.count; | |
| 3097 | + int err = 0, i; | |
| 3098 | + long left; | |
| 3099 | + | |
| 3100 | + if (!upath ^ !upath_size) | |
| 3101 | + return -EINVAL; | |
| 3102 | + | |
| 3103 | + if ((uoffsets || uref_ctr_offsets || ucookies) && !ucount) | |
| 3104 | + return -EINVAL; | |
| 3105 | + | |
| 3106 | + umulti_link = container_of(link, struct bpf_uprobe_multi_link, link); | |
| 3107 | + info->uprobe_multi.count = umulti_link->cnt; | |
| 3108 | + info->uprobe_multi.flags = umulti_link->flags; | |
| 3109 | + info->uprobe_multi.pid = umulti_link->task ? | |
| 3110 | + task_pid_nr_ns(umulti_link->task, task_active_pid_ns(current)) : 0; | |
| 3111 | + | |
| 3112 | + if (upath) { | |
| 3113 | + char *p, *buf; | |
| 3114 | + | |
| 3115 | + upath_size = min_t(u32, upath_size, PATH_MAX); | |
| 3116 | + | |
| 3117 | + buf = kmalloc(upath_size, GFP_KERNEL); | |
| 3118 | + if (!buf) | |
| 3119 | + return -ENOMEM; | |
| 3120 | + p = d_path(&umulti_link->path, buf, upath_size); | |
| 3121 | + if (IS_ERR(p)) { | |
| 3122 | + kfree(buf); | |
| 3123 | + return PTR_ERR(p); | |
| 3124 | + } | |
| 3125 | + upath_size = buf + upath_size - p; | |
| 3126 | + left = copy_to_user(upath, p, upath_size); | |
| 3127 | + kfree(buf); | |
| 3128 | + if (left) | |
| 3129 | + return -EFAULT; | |
| 3130 | + info->uprobe_multi.path_size = upath_size; | |
| 3131 | + } | |
| 3132 | + | |
| 3133 | + if (!uoffsets && !ucookies && !uref_ctr_offsets) | |
| 3134 | + return 0; | |
| 3135 | + | |
| 3136 | + if (ucount < umulti_link->cnt) | |
| 3137 | + err = -ENOSPC; | |
| 3138 | + else | |
| 3139 | + ucount = umulti_link->cnt; | |
| 3140 | + | |
| 3141 | + for (i = 0; i < ucount; i++) { | |
| 3142 | + if (uoffsets && | |
| 3143 | + put_user(umulti_link->uprobes[i].offset, uoffsets + i)) | |
| 3144 | + return -EFAULT; | |
| 3145 | + if (uref_ctr_offsets && | |
| 3146 | + put_user(umulti_link->uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) | |
| 3147 | + return -EFAULT; | |
| 3148 | + if (ucookies && | |
| 3149 | + put_user(umulti_link->uprobes[i].cookie, ucookies + i)) | |
| 3150 | + return -EFAULT; | |
| 3151 | + } | |
| 3152 | + | |
| 3153 | + return err; | |
| 3154 | +} | |
| 3155 | + | |
| 3086 | 3156 | static const struct bpf_link_ops bpf_uprobe_multi_link_lops = { |
| 3087 | 3157 | .release = bpf_uprobe_multi_link_release, |
| 3088 | 3158 | .dealloc = bpf_uprobe_multi_link_dealloc, |
| 3159 | + .fill_link_info = bpf_uprobe_multi_link_fill_link_info, | |
| 3089 | 3160 | }; |
| 3090 | 3161 | |
| 3091 | 3162 | static int uprobe_prog_run(struct bpf_uprobe *uprobe, |
| @@ -3274,6 +3345,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 182 unmodified lines | ||
| 3274 | 3345 | link->uprobes = uprobes; |
| 3275 | 3346 | link->path = path; |
| 3276 | 3347 | link->task = task; |
| 3348 | + link->flags = flags; | |
| 3277 | 3349 | |
| 3278 | 3350 | bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI, |
| 3279 | 3351 | &bpf_uprobe_multi_link_lops, prog); |