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 | struct path path; | 3042 | struct path path; |
| 3043 | struct bpf_link link; | 3043 | struct bpf_link link; |
| 3044 | u32 cnt; | 3044 | u32 cnt; |
| 3045 | u32 flags; | ||
| 3045 | struct bpf_uprobe *uprobes; | 3046 | struct bpf_uprobe *uprobes; |
| 3046 | struct task_struct *task; | 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 | kfree(umulti_link); | 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 | static const struct bpf_link_ops bpf_uprobe_multi_link_lops = { | 3156 | static const struct bpf_link_ops bpf_uprobe_multi_link_lops = { |
| 3087 | .release = bpf_uprobe_multi_link_release, | 3157 | .release = bpf_uprobe_multi_link_release, |
| 3088 | .dealloc = bpf_uprobe_multi_link_dealloc, | 3158 | .dealloc = bpf_uprobe_multi_link_dealloc, |
| 3159 | .fill_link_info = bpf_uprobe_multi_link_fill_link_info, | ||
| 3089 | }; | 3160 | }; |
| 3090 | 3161 | ||
| 3091 | static int uprobe_prog_run(struct bpf_uprobe *uprobe, | 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 | link->uprobes = uprobes; | 3345 | link->uprobes = uprobes; |
| 3275 | link->path = path; | 3346 | link->path = path; |
| 3276 | link->task = task; | 3347 | link->task = task; |
| 3348 | link->flags = flags; | ||
| 3277 | 3349 | ||
| 3278 | bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI, | 3350 | bpf_link_init(&link->link, BPF_LINK_TYPE_UPROBE_MULTI, |
| 3279 | &bpf_uprobe_multi_link_lops, prog); | 3351 | &bpf_uprobe_multi_link_lops, prog); |