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

libbpf: Add bpf_cookie support to bpf_link_create() API

Add ability to specify bpf_cookie value when creating BPF perf link with
bpf_link_create() low-level API.

Given BPF_LINK_CREATE command is growing and keeps getting new fields that are
specific to the type of BPF_LINK, extend libbpf side of bpf_link_create() API
and corresponding OPTS struct to accomodate such changes. Add extra checks to
prevent using incompatible/unexpected combinations of fields.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210815070609.987780-11-andrii@kernel.org

authored by

Andrii Nakryiko and committed by
Daniel Borkmann
3ec84f4b 668ace0e

+54 -18
+25 -7
tools/lib/bpf/bpf.c
··· 684 684 iter_info_len = OPTS_GET(opts, iter_info_len, 0); 685 685 target_btf_id = OPTS_GET(opts, target_btf_id, 0); 686 686 687 - if (iter_info_len && target_btf_id) 688 - return libbpf_err(-EINVAL); 687 + /* validate we don't have unexpected combinations of non-zero fields */ 688 + if (iter_info_len || target_btf_id) { 689 + if (iter_info_len && target_btf_id) 690 + return libbpf_err(-EINVAL); 691 + if (!OPTS_ZEROED(opts, target_btf_id)) 692 + return libbpf_err(-EINVAL); 693 + } 689 694 690 695 memset(&attr, 0, sizeof(attr)); 691 696 attr.link_create.prog_fd = prog_fd; ··· 698 693 attr.link_create.attach_type = attach_type; 699 694 attr.link_create.flags = OPTS_GET(opts, flags, 0); 700 695 701 - if (iter_info_len) { 702 - attr.link_create.iter_info = 703 - ptr_to_u64(OPTS_GET(opts, iter_info, (void *)0)); 704 - attr.link_create.iter_info_len = iter_info_len; 705 - } else if (target_btf_id) { 696 + if (target_btf_id) { 706 697 attr.link_create.target_btf_id = target_btf_id; 698 + goto proceed; 707 699 } 708 700 701 + switch (attach_type) { 702 + case BPF_TRACE_ITER: 703 + attr.link_create.iter_info = ptr_to_u64(OPTS_GET(opts, iter_info, (void *)0)); 704 + attr.link_create.iter_info_len = iter_info_len; 705 + break; 706 + case BPF_PERF_EVENT: 707 + attr.link_create.perf_event.bpf_cookie = OPTS_GET(opts, perf_event.bpf_cookie, 0); 708 + if (!OPTS_ZEROED(opts, perf_event)) 709 + return libbpf_err(-EINVAL); 710 + break; 711 + default: 712 + if (!OPTS_ZEROED(opts, flags)) 713 + return libbpf_err(-EINVAL); 714 + break; 715 + } 716 + proceed: 709 717 fd = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr)); 710 718 return libbpf_err_errno(fd); 711 719 }
+7 -1
tools/lib/bpf/bpf.h
··· 177 177 union bpf_iter_link_info *iter_info; 178 178 __u32 iter_info_len; 179 179 __u32 target_btf_id; 180 + union { 181 + struct { 182 + __u64 bpf_cookie; 183 + } perf_event; 184 + }; 185 + size_t :0; 180 186 }; 181 - #define bpf_link_create_opts__last_field target_btf_id 187 + #define bpf_link_create_opts__last_field perf_event 182 188 183 189 LIBBPF_API int bpf_link_create(int prog_fd, int target_fd, 184 190 enum bpf_attach_type attach_type,
+22 -10
tools/lib/bpf/libbpf_internal.h
··· 196 196 size_t cur_cnt, size_t max_cnt, size_t add_cnt); 197 197 int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt); 198 198 199 + static inline bool libbpf_is_mem_zeroed(const char *p, ssize_t len) 200 + { 201 + while (len > 0) { 202 + if (*p) 203 + return false; 204 + p++; 205 + len--; 206 + } 207 + return true; 208 + } 209 + 199 210 static inline bool libbpf_validate_opts(const char *opts, 200 211 size_t opts_sz, size_t user_sz, 201 212 const char *type_name) ··· 215 204 pr_warn("%s size (%zu) is too small\n", type_name, user_sz); 216 205 return false; 217 206 } 218 - if (user_sz > opts_sz) { 219 - size_t i; 220 - 221 - for (i = opts_sz; i < user_sz; i++) { 222 - if (opts[i]) { 223 - pr_warn("%s has non-zero extra bytes\n", 224 - type_name); 225 - return false; 226 - } 227 - } 207 + if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) { 208 + pr_warn("%s has non-zero extra bytes\n", type_name); 209 + return false; 228 210 } 229 211 return true; 230 212 } ··· 236 232 if (OPTS_HAS(opts, field)) \ 237 233 (opts)->field = value; \ 238 234 } while (0) 235 + 236 + #define OPTS_ZEROED(opts, last_nonzero_field) \ 237 + ({ \ 238 + ssize_t __off = offsetofend(typeof(*(opts)), last_nonzero_field); \ 239 + !(opts) || libbpf_is_mem_zeroed((const void *)opts + __off, \ 240 + (opts)->sz - __off); \ 241 + }) 242 + 239 243 240 244 int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz); 241 245 int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);