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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'Introduce composable bpf types'

Hao Luo says:

====================
This patch set consists of two changes:

- a cleanup of arg_type, ret_type and reg_type which try to make those
types composable. (patch 1/9 - patch 6/9)
- a bug fix that prevents bpf programs from writing kernel memory.
(patch 7/9 - patch 9/9)

The purpose of the cleanup is to find a scalable way to express type
nullness and read-onliness. This patchset introduces two flags that
can be applied on all three types: PTR_MAYBE_NULL and MEM_RDONLY.
Previous types such as ARG_XXX_OR_NULL can now be written as

ARG_XXX | PTR_MAYBE_NULL

Similarly, PTR_TO_RDONLY_BUF is now "PTR_TO_BUF | MEM_RDONLY".

Flags can be composed, as ARGs can be both MEM_RDONLY and MAYBE_NULL.

ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY

Based on this new composable types, patch 7/9 applies MEM_RDONLY on
PTR_TO_MEM, in order to tag the returned memory from per_cpu_ptr as
read-only. Therefore fixing a previous bug that one can leverage
per_cpu_ptr to modify kernel memory within BPF programs.

Patch 8/9 generalizes the use of MEM_RDONLY further by tagging a set of
helper arguments ARG_PTR_TO_MEM with MEM_RDONLY. Some helper functions
may override their arguments, such as bpf_d_path, bpf_snprintf. In this
patch, we narrow the ARG_PTR_TO_MEM to be compatible with only a subset
of memory types. This prevents these helpers from writing read-only
memories. For the helpers that do not write its arguments, we add tag
MEM_RDONLY to allow taking a RDONLY memory as argument.

Changes since v1:
- use %u to print base_type(type) instead of %lu. (Andrii, patch 3/9)
- improve reg_type_str() by appending '_or_null' and prepending 'rdonly_'.
use preallocated buffer in 'bpf_env'.
- unified handling of the previous XXX_OR_NULL in adjust_ptr_min_max_vals
(Andrii, patch 4/9)
- move PTR_TO_MAP_KEY up to PTR_TO_MAP_VALUE so that we don't have
to change to drivers that assume the numeric values of bpf_reg.
(patch 4/9)
- reintroduce the typo from previous commits in fixes tags (Andrii, patch 7/9)
- extensive comments on the reason behind folding flags in
check_reg_type (Andrii, patch 8/9)

Changes since RFC v2:
- renamed BPF_BASE_TYPE to a more succinct name base_type and move its
definition to bpf_verifier.h. Same for BPF_TYPE_FLAG. (Alexei)
- made checking MEM_RDONLY in check_reg_type() universal (Alexei)
- ran through majority of test_progs and fixed bugs in RFC v2:
- fixed incorrect BPF_BASE_TYPE_MASK. The high bit of GENMASK should
be BITS - 1, rather than BITS. patch 1/9.
- fixed incorrect conditions when checking ARG_PTR_TO_MAP_VALUE in
check_func_arg(). See patch 2/9.
- fixed a bug where PTR_TO_BTF_ID may be combined with MEM_RDONLY,
causing the check in check_mem_access() to fall through to the
'else' branch. See check_helper_call() in patch 7/9.
- fixed build failure on netronome driver. Entries in bpf_reg_type have
been ordered. patch 4/9.
- fixed build warnings of using '%d' to print base_type. patch 4/9
- unify arg_type_may_be_null() and reg_type_may_be_null() into a single
type_may_be_null().

Previous versions:

v1:
https://lwn.net/Articles/877938/

RFC v2:
https://lwn.net/Articles/877171/

RFC v1:
https://lore.kernel.org/bpf/20211109003052.3499225-1-haoluo@google.com/T/
https://lore.kernel.org/bpf/20211109021624.1140446-8-haoluo@google.com/T/
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+443 -335
+77 -24
include/linux/bpf.h
··· 297 297 298 298 extern const struct bpf_map_ops bpf_map_offload_ops; 299 299 300 + /* bpf_type_flag contains a set of flags that are applicable to the values of 301 + * arg_type, ret_type and reg_type. For example, a pointer value may be null, 302 + * or a memory is read-only. We classify types into two categories: base types 303 + * and extended types. Extended types are base types combined with a type flag. 304 + * 305 + * Currently there are no more than 32 base types in arg_type, ret_type and 306 + * reg_types. 307 + */ 308 + #define BPF_BASE_TYPE_BITS 8 309 + 310 + enum bpf_type_flag { 311 + /* PTR may be NULL. */ 312 + PTR_MAYBE_NULL = BIT(0 + BPF_BASE_TYPE_BITS), 313 + 314 + /* MEM is read-only. When applied on bpf_arg, it indicates the arg is 315 + * compatible with both mutable and immutable memory. 316 + */ 317 + MEM_RDONLY = BIT(1 + BPF_BASE_TYPE_BITS), 318 + 319 + __BPF_TYPE_LAST_FLAG = MEM_RDONLY, 320 + }; 321 + 322 + /* Max number of base types. */ 323 + #define BPF_BASE_TYPE_LIMIT (1UL << BPF_BASE_TYPE_BITS) 324 + 325 + /* Max number of all types. */ 326 + #define BPF_TYPE_LIMIT (__BPF_TYPE_LAST_FLAG | (__BPF_TYPE_LAST_FLAG - 1)) 327 + 300 328 /* function argument constraints */ 301 329 enum bpf_arg_type { 302 330 ARG_DONTCARE = 0, /* unused argument in helper function */ ··· 336 308 ARG_PTR_TO_MAP_KEY, /* pointer to stack used as map key */ 337 309 ARG_PTR_TO_MAP_VALUE, /* pointer to stack used as map value */ 338 310 ARG_PTR_TO_UNINIT_MAP_VALUE, /* pointer to valid memory used to store a map value */ 339 - ARG_PTR_TO_MAP_VALUE_OR_NULL, /* pointer to stack used as map value or NULL */ 340 311 341 312 /* the following constraints used to prototype bpf_memcmp() and other 342 313 * functions that access data on eBPF program stack 343 314 */ 344 315 ARG_PTR_TO_MEM, /* pointer to valid memory (stack, packet, map value) */ 345 - ARG_PTR_TO_MEM_OR_NULL, /* pointer to valid memory or NULL */ 346 316 ARG_PTR_TO_UNINIT_MEM, /* pointer to memory does not need to be initialized, 347 317 * helper function must fill all bytes or clear 348 318 * them in error case. ··· 350 324 ARG_CONST_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */ 351 325 352 326 ARG_PTR_TO_CTX, /* pointer to context */ 353 - ARG_PTR_TO_CTX_OR_NULL, /* pointer to context or NULL */ 354 327 ARG_ANYTHING, /* any (initialized) argument is ok */ 355 328 ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */ 356 329 ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */ 357 330 ARG_PTR_TO_INT, /* pointer to int */ 358 331 ARG_PTR_TO_LONG, /* pointer to long */ 359 332 ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */ 360 - ARG_PTR_TO_SOCKET_OR_NULL, /* pointer to bpf_sock (fullsock) or NULL */ 361 333 ARG_PTR_TO_BTF_ID, /* pointer to in-kernel struct */ 362 334 ARG_PTR_TO_ALLOC_MEM, /* pointer to dynamically allocated memory */ 363 - ARG_PTR_TO_ALLOC_MEM_OR_NULL, /* pointer to dynamically allocated memory or NULL */ 364 335 ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */ 365 336 ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */ 366 337 ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */ 367 338 ARG_PTR_TO_FUNC, /* pointer to a bpf program function */ 368 - ARG_PTR_TO_STACK_OR_NULL, /* pointer to stack or NULL */ 339 + ARG_PTR_TO_STACK, /* pointer to stack */ 369 340 ARG_PTR_TO_CONST_STR, /* pointer to a null terminated read-only string */ 370 341 ARG_PTR_TO_TIMER, /* pointer to bpf_timer */ 371 342 __BPF_ARG_TYPE_MAX, 343 + 344 + /* Extended arg_types. */ 345 + ARG_PTR_TO_MAP_VALUE_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_MAP_VALUE, 346 + ARG_PTR_TO_MEM_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_MEM, 347 + ARG_PTR_TO_CTX_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_CTX, 348 + ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET, 349 + ARG_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_ALLOC_MEM, 350 + ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK, 351 + 352 + /* This must be the last entry. Its purpose is to ensure the enum is 353 + * wide enough to hold the higher bits reserved for bpf_type_flag. 354 + */ 355 + __BPF_ARG_TYPE_LIMIT = BPF_TYPE_LIMIT, 372 356 }; 357 + static_assert(__BPF_ARG_TYPE_MAX <= BPF_BASE_TYPE_LIMIT); 373 358 374 359 /* type of values returned from helper functions */ 375 360 enum bpf_return_type { 376 361 RET_INTEGER, /* function returns integer */ 377 362 RET_VOID, /* function doesn't return anything */ 378 363 RET_PTR_TO_MAP_VALUE, /* returns a pointer to map elem value */ 379 - RET_PTR_TO_MAP_VALUE_OR_NULL, /* returns a pointer to map elem value or NULL */ 380 - RET_PTR_TO_SOCKET_OR_NULL, /* returns a pointer to a socket or NULL */ 381 - RET_PTR_TO_TCP_SOCK_OR_NULL, /* returns a pointer to a tcp_sock or NULL */ 382 - RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ 383 - RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ 384 - RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ 385 - RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */ 364 + RET_PTR_TO_SOCKET, /* returns a pointer to a socket */ 365 + RET_PTR_TO_TCP_SOCK, /* returns a pointer to a tcp_sock */ 366 + RET_PTR_TO_SOCK_COMMON, /* returns a pointer to a sock_common */ 367 + RET_PTR_TO_ALLOC_MEM, /* returns a pointer to dynamically allocated memory */ 386 368 RET_PTR_TO_MEM_OR_BTF_ID, /* returns a pointer to a valid memory or a btf_id */ 387 369 RET_PTR_TO_BTF_ID, /* returns a pointer to a btf_id */ 370 + __BPF_RET_TYPE_MAX, 371 + 372 + /* Extended ret_types. */ 373 + RET_PTR_TO_MAP_VALUE_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_MAP_VALUE, 374 + RET_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_SOCKET, 375 + RET_PTR_TO_TCP_SOCK_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_TCP_SOCK, 376 + RET_PTR_TO_SOCK_COMMON_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_SOCK_COMMON, 377 + RET_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_ALLOC_MEM, 378 + RET_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_BTF_ID, 379 + 380 + /* This must be the last entry. Its purpose is to ensure the enum is 381 + * wide enough to hold the higher bits reserved for bpf_type_flag. 382 + */ 383 + __BPF_RET_TYPE_LIMIT = BPF_TYPE_LIMIT, 388 384 }; 385 + static_assert(__BPF_RET_TYPE_MAX <= BPF_BASE_TYPE_LIMIT); 389 386 390 387 /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs 391 388 * to in-kernel helper functions and for adjusting imm32 field in BPF_CALL ··· 470 421 PTR_TO_CTX, /* reg points to bpf_context */ 471 422 CONST_PTR_TO_MAP, /* reg points to struct bpf_map */ 472 423 PTR_TO_MAP_VALUE, /* reg points to map element value */ 473 - PTR_TO_MAP_VALUE_OR_NULL,/* points to map elem value or NULL */ 424 + PTR_TO_MAP_KEY, /* reg points to a map element key */ 474 425 PTR_TO_STACK, /* reg == frame_pointer + offset */ 475 426 PTR_TO_PACKET_META, /* skb->data - meta_len */ 476 427 PTR_TO_PACKET, /* reg points to skb->data */ 477 428 PTR_TO_PACKET_END, /* skb->data + headlen */ 478 429 PTR_TO_FLOW_KEYS, /* reg points to bpf_flow_keys */ 479 430 PTR_TO_SOCKET, /* reg points to struct bpf_sock */ 480 - PTR_TO_SOCKET_OR_NULL, /* reg points to struct bpf_sock or NULL */ 481 431 PTR_TO_SOCK_COMMON, /* reg points to sock_common */ 482 - PTR_TO_SOCK_COMMON_OR_NULL, /* reg points to sock_common or NULL */ 483 432 PTR_TO_TCP_SOCK, /* reg points to struct tcp_sock */ 484 - PTR_TO_TCP_SOCK_OR_NULL, /* reg points to struct tcp_sock or NULL */ 485 433 PTR_TO_TP_BUFFER, /* reg points to a writable raw tp's buffer */ 486 434 PTR_TO_XDP_SOCK, /* reg points to struct xdp_sock */ 487 435 /* PTR_TO_BTF_ID points to a kernel struct that does not need ··· 496 450 * been checked for null. Used primarily to inform the verifier 497 451 * an explicit null check is required for this struct. 498 452 */ 499 - PTR_TO_BTF_ID_OR_NULL, 500 453 PTR_TO_MEM, /* reg points to valid memory region */ 501 - PTR_TO_MEM_OR_NULL, /* reg points to valid memory region or NULL */ 502 - PTR_TO_RDONLY_BUF, /* reg points to a readonly buffer */ 503 - PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */ 504 - PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */ 505 - PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */ 454 + PTR_TO_BUF, /* reg points to a read/write buffer */ 506 455 PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */ 507 456 PTR_TO_FUNC, /* reg points to a bpf program function */ 508 - PTR_TO_MAP_KEY, /* reg points to a map element key */ 509 457 __BPF_REG_TYPE_MAX, 458 + 459 + /* Extended reg_types. */ 460 + PTR_TO_MAP_VALUE_OR_NULL = PTR_MAYBE_NULL | PTR_TO_MAP_VALUE, 461 + PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | PTR_TO_SOCKET, 462 + PTR_TO_SOCK_COMMON_OR_NULL = PTR_MAYBE_NULL | PTR_TO_SOCK_COMMON, 463 + PTR_TO_TCP_SOCK_OR_NULL = PTR_MAYBE_NULL | PTR_TO_TCP_SOCK, 464 + PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | PTR_TO_BTF_ID, 465 + 466 + /* This must be the last entry. Its purpose is to ensure the enum is 467 + * wide enough to hold the higher bits reserved for bpf_type_flag. 468 + */ 469 + __BPF_REG_TYPE_LIMIT = BPF_TYPE_LIMIT, 510 470 }; 471 + static_assert(__BPF_REG_TYPE_MAX <= BPF_BASE_TYPE_LIMIT); 511 472 512 473 /* The information passed from prog-specific *_is_valid_access 513 474 * back to the verifier.
+17
include/linux/bpf_verifier.h
··· 18 18 * that converting umax_value to int cannot overflow. 19 19 */ 20 20 #define BPF_MAX_VAR_SIZ (1 << 29) 21 + /* size of type_str_buf in bpf_verifier. */ 22 + #define TYPE_STR_BUF_LEN 64 21 23 22 24 /* Liveness marks, used for registers and spilled-regs (in stack slots). 23 25 * Read marks propagate upwards until they find a write mark; they record that ··· 486 484 /* Same as scratched_regs but for stack slots */ 487 485 u64 scratched_stack_slots; 488 486 u32 prev_log_len, prev_insn_print_len; 487 + /* buffer used in reg_type_str() to generate reg_type string */ 488 + char type_str_buf[TYPE_STR_BUF_LEN]; 489 489 }; 490 490 491 491 __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, ··· 550 546 struct bpf_attach_target_info *tgt_info); 551 547 void bpf_free_kfunc_btf_tab(struct bpf_kfunc_btf_tab *tab); 552 548 549 + #define BPF_BASE_TYPE_MASK GENMASK(BPF_BASE_TYPE_BITS - 1, 0) 550 + 551 + /* extract base type from bpf_{arg, return, reg}_type. */ 552 + static inline u32 base_type(u32 type) 553 + { 554 + return type & BPF_BASE_TYPE_MASK; 555 + } 556 + 557 + /* extract flags from an extended type. See bpf_type_flag in bpf.h. */ 558 + static inline u32 type_flag(u32 type) 559 + { 560 + return type & ~BPF_BASE_TYPE_MASK; 561 + } 553 562 554 563 #endif /* _LINUX_BPF_VERIFIER_H */
+7 -5
kernel/bpf/btf.c
··· 4940 4940 /* check for PTR_TO_RDONLY_BUF_OR_NULL or PTR_TO_RDWR_BUF_OR_NULL */ 4941 4941 for (i = 0; i < prog->aux->ctx_arg_info_size; i++) { 4942 4942 const struct bpf_ctx_arg_aux *ctx_arg_info = &prog->aux->ctx_arg_info[i]; 4943 + u32 type, flag; 4943 4944 4944 - if (ctx_arg_info->offset == off && 4945 - (ctx_arg_info->reg_type == PTR_TO_RDONLY_BUF_OR_NULL || 4946 - ctx_arg_info->reg_type == PTR_TO_RDWR_BUF_OR_NULL)) { 4945 + type = base_type(ctx_arg_info->reg_type); 4946 + flag = type_flag(ctx_arg_info->reg_type); 4947 + if (ctx_arg_info->offset == off && type == PTR_TO_BUF && 4948 + (flag & PTR_MAYBE_NULL)) { 4947 4949 info->reg_type = ctx_arg_info->reg_type; 4948 4950 return true; 4949 4951 } ··· 5859 5857 return -EINVAL; 5860 5858 } 5861 5859 5862 - reg->type = PTR_TO_MEM_OR_NULL; 5860 + reg->type = PTR_TO_MEM | PTR_MAYBE_NULL; 5863 5861 reg->id = ++env->id_gen; 5864 5862 5865 5863 continue; ··· 6353 6351 .func = bpf_btf_find_by_name_kind, 6354 6352 .gpl_only = false, 6355 6353 .ret_type = RET_INTEGER, 6356 - .arg1_type = ARG_PTR_TO_MEM, 6354 + .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6357 6355 .arg2_type = ARG_CONST_SIZE, 6358 6356 .arg3_type = ARG_ANYTHING, 6359 6357 .arg4_type = ARG_ANYTHING,
+1 -1
kernel/bpf/cgroup.c
··· 1789 1789 .gpl_only = false, 1790 1790 .ret_type = RET_INTEGER, 1791 1791 .arg1_type = ARG_PTR_TO_CTX, 1792 - .arg2_type = ARG_PTR_TO_MEM, 1792 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1793 1793 .arg3_type = ARG_CONST_SIZE, 1794 1794 }; 1795 1795
+6 -6
kernel/bpf/helpers.c
··· 531 531 .func = bpf_strtol, 532 532 .gpl_only = false, 533 533 .ret_type = RET_INTEGER, 534 - .arg1_type = ARG_PTR_TO_MEM, 534 + .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 535 535 .arg2_type = ARG_CONST_SIZE, 536 536 .arg3_type = ARG_ANYTHING, 537 537 .arg4_type = ARG_PTR_TO_LONG, ··· 559 559 .func = bpf_strtoul, 560 560 .gpl_only = false, 561 561 .ret_type = RET_INTEGER, 562 - .arg1_type = ARG_PTR_TO_MEM, 562 + .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 563 563 .arg2_type = ARG_CONST_SIZE, 564 564 .arg3_type = ARG_ANYTHING, 565 565 .arg4_type = ARG_PTR_TO_LONG, ··· 645 645 .arg1_type = ARG_PTR_TO_CTX, 646 646 .arg2_type = ARG_CONST_MAP_PTR, 647 647 .arg3_type = ARG_ANYTHING, 648 - .arg4_type = ARG_PTR_TO_MEM, 648 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 649 649 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 650 650 }; 651 651 ··· 682 682 const struct bpf_func_proto bpf_per_cpu_ptr_proto = { 683 683 .func = bpf_per_cpu_ptr, 684 684 .gpl_only = false, 685 - .ret_type = RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, 685 + .ret_type = RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY, 686 686 .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, 687 687 .arg2_type = ARG_ANYTHING, 688 688 }; ··· 695 695 const struct bpf_func_proto bpf_this_cpu_ptr_proto = { 696 696 .func = bpf_this_cpu_ptr, 697 697 .gpl_only = false, 698 - .ret_type = RET_PTR_TO_MEM_OR_BTF_ID, 698 + .ret_type = RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY, 699 699 .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, 700 700 }; 701 701 ··· 1026 1026 .arg1_type = ARG_PTR_TO_MEM_OR_NULL, 1027 1027 .arg2_type = ARG_CONST_SIZE_OR_ZERO, 1028 1028 .arg3_type = ARG_PTR_TO_CONST_STR, 1029 - .arg4_type = ARG_PTR_TO_MEM_OR_NULL, 1029 + .arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 1030 1030 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 1031 1031 }; 1032 1032
+2 -2
kernel/bpf/map_iter.c
··· 174 174 .ctx_arg_info_size = 2, 175 175 .ctx_arg_info = { 176 176 { offsetof(struct bpf_iter__bpf_map_elem, key), 177 - PTR_TO_RDONLY_BUF_OR_NULL }, 177 + PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY }, 178 178 { offsetof(struct bpf_iter__bpf_map_elem, value), 179 - PTR_TO_RDWR_BUF_OR_NULL }, 179 + PTR_TO_BUF | PTR_MAYBE_NULL }, 180 180 }, 181 181 }; 182 182
+1 -1
kernel/bpf/ringbuf.c
··· 444 444 .func = bpf_ringbuf_output, 445 445 .ret_type = RET_INTEGER, 446 446 .arg1_type = ARG_CONST_MAP_PTR, 447 - .arg2_type = ARG_PTR_TO_MEM, 447 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 448 448 .arg3_type = ARG_CONST_SIZE_OR_ZERO, 449 449 .arg4_type = ARG_ANYTHING, 450 450 };
+1 -1
kernel/bpf/syscall.c
··· 4773 4773 .gpl_only = false, 4774 4774 .ret_type = RET_INTEGER, 4775 4775 .arg1_type = ARG_ANYTHING, 4776 - .arg2_type = ARG_PTR_TO_MEM, 4776 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4777 4777 .arg3_type = ARG_CONST_SIZE, 4778 4778 }; 4779 4779
+241 -248
kernel/bpf/verifier.c
··· 442 442 type == PTR_TO_SOCK_COMMON; 443 443 } 444 444 445 - static bool reg_type_may_be_null(enum bpf_reg_type type) 446 - { 447 - return type == PTR_TO_MAP_VALUE_OR_NULL || 448 - type == PTR_TO_SOCKET_OR_NULL || 449 - type == PTR_TO_SOCK_COMMON_OR_NULL || 450 - type == PTR_TO_TCP_SOCK_OR_NULL || 451 - type == PTR_TO_BTF_ID_OR_NULL || 452 - type == PTR_TO_MEM_OR_NULL || 453 - type == PTR_TO_RDONLY_BUF_OR_NULL || 454 - type == PTR_TO_RDWR_BUF_OR_NULL; 455 - } 456 - 457 445 static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) 458 446 { 459 447 return reg->type == PTR_TO_MAP_VALUE && ··· 450 462 451 463 static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type) 452 464 { 453 - return type == PTR_TO_SOCKET || 454 - type == PTR_TO_SOCKET_OR_NULL || 455 - type == PTR_TO_TCP_SOCK || 456 - type == PTR_TO_TCP_SOCK_OR_NULL || 457 - type == PTR_TO_MEM || 458 - type == PTR_TO_MEM_OR_NULL; 465 + return base_type(type) == PTR_TO_SOCKET || 466 + base_type(type) == PTR_TO_TCP_SOCK || 467 + base_type(type) == PTR_TO_MEM; 468 + } 469 + 470 + static bool type_is_rdonly_mem(u32 type) 471 + { 472 + return type & MEM_RDONLY; 459 473 } 460 474 461 475 static bool arg_type_may_be_refcounted(enum bpf_arg_type type) ··· 465 475 return type == ARG_PTR_TO_SOCK_COMMON; 466 476 } 467 477 468 - static bool arg_type_may_be_null(enum bpf_arg_type type) 478 + static bool type_may_be_null(u32 type) 469 479 { 470 - return type == ARG_PTR_TO_MAP_VALUE_OR_NULL || 471 - type == ARG_PTR_TO_MEM_OR_NULL || 472 - type == ARG_PTR_TO_CTX_OR_NULL || 473 - type == ARG_PTR_TO_SOCKET_OR_NULL || 474 - type == ARG_PTR_TO_ALLOC_MEM_OR_NULL || 475 - type == ARG_PTR_TO_STACK_OR_NULL; 480 + return type & PTR_MAYBE_NULL; 476 481 } 477 482 478 483 /* Determine whether the function releases some resources allocated by another ··· 527 542 insn->imm == BPF_CMPXCHG; 528 543 } 529 544 530 - /* string representation of 'enum bpf_reg_type' */ 531 - static const char * const reg_type_str[] = { 532 - [NOT_INIT] = "?", 533 - [SCALAR_VALUE] = "inv", 534 - [PTR_TO_CTX] = "ctx", 535 - [CONST_PTR_TO_MAP] = "map_ptr", 536 - [PTR_TO_MAP_VALUE] = "map_value", 537 - [PTR_TO_MAP_VALUE_OR_NULL] = "map_value_or_null", 538 - [PTR_TO_STACK] = "fp", 539 - [PTR_TO_PACKET] = "pkt", 540 - [PTR_TO_PACKET_META] = "pkt_meta", 541 - [PTR_TO_PACKET_END] = "pkt_end", 542 - [PTR_TO_FLOW_KEYS] = "flow_keys", 543 - [PTR_TO_SOCKET] = "sock", 544 - [PTR_TO_SOCKET_OR_NULL] = "sock_or_null", 545 - [PTR_TO_SOCK_COMMON] = "sock_common", 546 - [PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null", 547 - [PTR_TO_TCP_SOCK] = "tcp_sock", 548 - [PTR_TO_TCP_SOCK_OR_NULL] = "tcp_sock_or_null", 549 - [PTR_TO_TP_BUFFER] = "tp_buffer", 550 - [PTR_TO_XDP_SOCK] = "xdp_sock", 551 - [PTR_TO_BTF_ID] = "ptr_", 552 - [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_", 553 - [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", 554 - [PTR_TO_MEM] = "mem", 555 - [PTR_TO_MEM_OR_NULL] = "mem_or_null", 556 - [PTR_TO_RDONLY_BUF] = "rdonly_buf", 557 - [PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null", 558 - [PTR_TO_RDWR_BUF] = "rdwr_buf", 559 - [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null", 560 - [PTR_TO_FUNC] = "func", 561 - [PTR_TO_MAP_KEY] = "map_key", 562 - }; 545 + /* string representation of 'enum bpf_reg_type' 546 + * 547 + * Note that reg_type_str() can not appear more than once in a single verbose() 548 + * statement. 549 + */ 550 + static const char *reg_type_str(struct bpf_verifier_env *env, 551 + enum bpf_reg_type type) 552 + { 553 + char postfix[16] = {0}, prefix[16] = {0}; 554 + static const char * const str[] = { 555 + [NOT_INIT] = "?", 556 + [SCALAR_VALUE] = "inv", 557 + [PTR_TO_CTX] = "ctx", 558 + [CONST_PTR_TO_MAP] = "map_ptr", 559 + [PTR_TO_MAP_VALUE] = "map_value", 560 + [PTR_TO_STACK] = "fp", 561 + [PTR_TO_PACKET] = "pkt", 562 + [PTR_TO_PACKET_META] = "pkt_meta", 563 + [PTR_TO_PACKET_END] = "pkt_end", 564 + [PTR_TO_FLOW_KEYS] = "flow_keys", 565 + [PTR_TO_SOCKET] = "sock", 566 + [PTR_TO_SOCK_COMMON] = "sock_common", 567 + [PTR_TO_TCP_SOCK] = "tcp_sock", 568 + [PTR_TO_TP_BUFFER] = "tp_buffer", 569 + [PTR_TO_XDP_SOCK] = "xdp_sock", 570 + [PTR_TO_BTF_ID] = "ptr_", 571 + [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", 572 + [PTR_TO_MEM] = "mem", 573 + [PTR_TO_BUF] = "buf", 574 + [PTR_TO_FUNC] = "func", 575 + [PTR_TO_MAP_KEY] = "map_key", 576 + }; 577 + 578 + if (type & PTR_MAYBE_NULL) { 579 + if (base_type(type) == PTR_TO_BTF_ID || 580 + base_type(type) == PTR_TO_PERCPU_BTF_ID) 581 + strncpy(postfix, "or_null_", 16); 582 + else 583 + strncpy(postfix, "_or_null", 16); 584 + } 585 + 586 + if (type & MEM_RDONLY) 587 + strncpy(prefix, "rdonly_", 16); 588 + 589 + snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s", 590 + prefix, str[base_type(type)], postfix); 591 + return env->type_str_buf; 592 + } 563 593 564 594 static char slot_type_char[] = { 565 595 [STACK_INVALID] = '?', ··· 680 680 continue; 681 681 verbose(env, " R%d", i); 682 682 print_liveness(env, reg->live); 683 - verbose(env, "=%s", reg_type_str[t]); 683 + verbose(env, "=%s", reg_type_str(env, t)); 684 684 if (t == SCALAR_VALUE && reg->precise) 685 685 verbose(env, "P"); 686 686 if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && ··· 688 688 /* reg->off should be 0 for SCALAR_VALUE */ 689 689 verbose(env, "%lld", reg->var_off.value + reg->off); 690 690 } else { 691 - if (t == PTR_TO_BTF_ID || 692 - t == PTR_TO_BTF_ID_OR_NULL || 693 - t == PTR_TO_PERCPU_BTF_ID) 691 + if (base_type(t) == PTR_TO_BTF_ID || 692 + base_type(t) == PTR_TO_PERCPU_BTF_ID) 694 693 verbose(env, "%s", kernel_type_name(reg->btf, reg->btf_id)); 695 694 verbose(env, "(id=%d", reg->id); 696 695 if (reg_type_may_be_refcounted_or_null(t)) ··· 698 699 verbose(env, ",off=%d", reg->off); 699 700 if (type_is_pkt_pointer(t)) 700 701 verbose(env, ",r=%d", reg->range); 701 - else if (t == CONST_PTR_TO_MAP || 702 - t == PTR_TO_MAP_KEY || 703 - t == PTR_TO_MAP_VALUE || 704 - t == PTR_TO_MAP_VALUE_OR_NULL) 702 + else if (base_type(t) == CONST_PTR_TO_MAP || 703 + base_type(t) == PTR_TO_MAP_KEY || 704 + base_type(t) == PTR_TO_MAP_VALUE) 705 705 verbose(env, ",ks=%d,vs=%d", 706 706 reg->map_ptr->key_size, 707 707 reg->map_ptr->value_size); ··· 772 774 if (is_spilled_reg(&state->stack[i])) { 773 775 reg = &state->stack[i].spilled_ptr; 774 776 t = reg->type; 775 - verbose(env, "=%s", reg_type_str[t]); 777 + verbose(env, "=%s", reg_type_str(env, t)); 776 778 if (t == SCALAR_VALUE && reg->precise) 777 779 verbose(env, "P"); 778 780 if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) ··· 1205 1207 1206 1208 static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) 1207 1209 { 1208 - switch (reg->type) { 1209 - case PTR_TO_MAP_VALUE_OR_NULL: { 1210 + if (base_type(reg->type) == PTR_TO_MAP_VALUE) { 1210 1211 const struct bpf_map *map = reg->map_ptr; 1211 1212 1212 1213 if (map->inner_map_meta) { ··· 1224 1227 } else { 1225 1228 reg->type = PTR_TO_MAP_VALUE; 1226 1229 } 1227 - break; 1230 + return; 1228 1231 } 1229 - case PTR_TO_SOCKET_OR_NULL: 1230 - reg->type = PTR_TO_SOCKET; 1231 - break; 1232 - case PTR_TO_SOCK_COMMON_OR_NULL: 1233 - reg->type = PTR_TO_SOCK_COMMON; 1234 - break; 1235 - case PTR_TO_TCP_SOCK_OR_NULL: 1236 - reg->type = PTR_TO_TCP_SOCK; 1237 - break; 1238 - case PTR_TO_BTF_ID_OR_NULL: 1239 - reg->type = PTR_TO_BTF_ID; 1240 - break; 1241 - case PTR_TO_MEM_OR_NULL: 1242 - reg->type = PTR_TO_MEM; 1243 - break; 1244 - case PTR_TO_RDONLY_BUF_OR_NULL: 1245 - reg->type = PTR_TO_RDONLY_BUF; 1246 - break; 1247 - case PTR_TO_RDWR_BUF_OR_NULL: 1248 - reg->type = PTR_TO_RDWR_BUF; 1249 - break; 1250 - default: 1251 - WARN_ONCE(1, "unknown nullable register type"); 1252 - } 1232 + 1233 + reg->type &= ~PTR_MAYBE_NULL; 1253 1234 } 1254 1235 1255 1236 static bool reg_is_pkt_pointer(const struct bpf_reg_state *reg) ··· 2083 2108 break; 2084 2109 if (parent->live & REG_LIVE_DONE) { 2085 2110 verbose(env, "verifier BUG type %s var_off %lld off %d\n", 2086 - reg_type_str[parent->type], 2111 + reg_type_str(env, parent->type), 2087 2112 parent->var_off.value, parent->off); 2088 2113 return -EFAULT; 2089 2114 } ··· 2748 2773 2749 2774 static bool is_spillable_regtype(enum bpf_reg_type type) 2750 2775 { 2751 - switch (type) { 2776 + switch (base_type(type)) { 2752 2777 case PTR_TO_MAP_VALUE: 2753 - case PTR_TO_MAP_VALUE_OR_NULL: 2754 2778 case PTR_TO_STACK: 2755 2779 case PTR_TO_CTX: 2756 2780 case PTR_TO_PACKET: ··· 2758 2784 case PTR_TO_FLOW_KEYS: 2759 2785 case CONST_PTR_TO_MAP: 2760 2786 case PTR_TO_SOCKET: 2761 - case PTR_TO_SOCKET_OR_NULL: 2762 2787 case PTR_TO_SOCK_COMMON: 2763 - case PTR_TO_SOCK_COMMON_OR_NULL: 2764 2788 case PTR_TO_TCP_SOCK: 2765 - case PTR_TO_TCP_SOCK_OR_NULL: 2766 2789 case PTR_TO_XDP_SOCK: 2767 2790 case PTR_TO_BTF_ID: 2768 - case PTR_TO_BTF_ID_OR_NULL: 2769 - case PTR_TO_RDONLY_BUF: 2770 - case PTR_TO_RDONLY_BUF_OR_NULL: 2771 - case PTR_TO_RDWR_BUF: 2772 - case PTR_TO_RDWR_BUF_OR_NULL: 2791 + case PTR_TO_BUF: 2773 2792 case PTR_TO_PERCPU_BTF_ID: 2774 2793 case PTR_TO_MEM: 2775 - case PTR_TO_MEM_OR_NULL: 2776 2794 case PTR_TO_FUNC: 2777 2795 case PTR_TO_MAP_KEY: 2778 2796 return true; ··· 3604 3638 */ 3605 3639 *reg_type = info.reg_type; 3606 3640 3607 - if (*reg_type == PTR_TO_BTF_ID || *reg_type == PTR_TO_BTF_ID_OR_NULL) { 3641 + if (base_type(*reg_type) == PTR_TO_BTF_ID) { 3608 3642 *btf = info.btf; 3609 3643 *btf_id = info.btf_id; 3610 3644 } else { ··· 3672 3706 } 3673 3707 3674 3708 verbose(env, "R%d invalid %s access off=%d size=%d\n", 3675 - regno, reg_type_str[reg->type], off, size); 3709 + regno, reg_type_str(env, reg->type), off, size); 3676 3710 3677 3711 return -EACCES; 3678 3712 } ··· 4399 4433 mark_reg_unknown(env, regs, value_regno); 4400 4434 } 4401 4435 } 4402 - } else if (reg->type == PTR_TO_MEM) { 4436 + } else if (base_type(reg->type) == PTR_TO_MEM) { 4437 + bool rdonly_mem = type_is_rdonly_mem(reg->type); 4438 + 4439 + if (type_may_be_null(reg->type)) { 4440 + verbose(env, "R%d invalid mem access '%s'\n", regno, 4441 + reg_type_str(env, reg->type)); 4442 + return -EACCES; 4443 + } 4444 + 4445 + if (t == BPF_WRITE && rdonly_mem) { 4446 + verbose(env, "R%d cannot write into %s\n", 4447 + regno, reg_type_str(env, reg->type)); 4448 + return -EACCES; 4449 + } 4450 + 4403 4451 if (t == BPF_WRITE && value_regno >= 0 && 4404 4452 is_pointer_value(env, value_regno)) { 4405 4453 verbose(env, "R%d leaks addr into mem\n", value_regno); 4406 4454 return -EACCES; 4407 4455 } 4456 + 4408 4457 err = check_mem_region_access(env, regno, off, size, 4409 4458 reg->mem_size, false); 4410 - if (!err && t == BPF_READ && value_regno >= 0) 4459 + if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem)) 4411 4460 mark_reg_unknown(env, regs, value_regno); 4412 4461 } else if (reg->type == PTR_TO_CTX) { 4413 4462 enum bpf_reg_type reg_type = SCALAR_VALUE; ··· 4452 4471 } else { 4453 4472 mark_reg_known_zero(env, regs, 4454 4473 value_regno); 4455 - if (reg_type_may_be_null(reg_type)) 4474 + if (type_may_be_null(reg_type)) 4456 4475 regs[value_regno].id = ++env->id_gen; 4457 4476 /* A load of ctx field could have different 4458 4477 * actual load size with the one encoded in the ··· 4460 4479 * a sub-register. 4461 4480 */ 4462 4481 regs[value_regno].subreg_def = DEF_NOT_SUBREG; 4463 - if (reg_type == PTR_TO_BTF_ID || 4464 - reg_type == PTR_TO_BTF_ID_OR_NULL) { 4482 + if (base_type(reg_type) == PTR_TO_BTF_ID) { 4465 4483 regs[value_regno].btf = btf; 4466 4484 regs[value_regno].btf_id = btf_id; 4467 4485 } ··· 4513 4533 } else if (type_is_sk_pointer(reg->type)) { 4514 4534 if (t == BPF_WRITE) { 4515 4535 verbose(env, "R%d cannot write into %s\n", 4516 - regno, reg_type_str[reg->type]); 4536 + regno, reg_type_str(env, reg->type)); 4517 4537 return -EACCES; 4518 4538 } 4519 4539 err = check_sock_access(env, insn_idx, regno, off, size, t); ··· 4529 4549 } else if (reg->type == CONST_PTR_TO_MAP) { 4530 4550 err = check_ptr_to_map_access(env, regs, regno, off, size, t, 4531 4551 value_regno); 4532 - } else if (reg->type == PTR_TO_RDONLY_BUF) { 4533 - if (t == BPF_WRITE) { 4534 - verbose(env, "R%d cannot write into %s\n", 4535 - regno, reg_type_str[reg->type]); 4536 - return -EACCES; 4552 + } else if (base_type(reg->type) == PTR_TO_BUF) { 4553 + bool rdonly_mem = type_is_rdonly_mem(reg->type); 4554 + const char *buf_info; 4555 + u32 *max_access; 4556 + 4557 + if (rdonly_mem) { 4558 + if (t == BPF_WRITE) { 4559 + verbose(env, "R%d cannot write into %s\n", 4560 + regno, reg_type_str(env, reg->type)); 4561 + return -EACCES; 4562 + } 4563 + buf_info = "rdonly"; 4564 + max_access = &env->prog->aux->max_rdonly_access; 4565 + } else { 4566 + buf_info = "rdwr"; 4567 + max_access = &env->prog->aux->max_rdwr_access; 4537 4568 } 4569 + 4538 4570 err = check_buffer_access(env, reg, regno, off, size, false, 4539 - "rdonly", 4540 - &env->prog->aux->max_rdonly_access); 4541 - if (!err && value_regno >= 0) 4542 - mark_reg_unknown(env, regs, value_regno); 4543 - } else if (reg->type == PTR_TO_RDWR_BUF) { 4544 - err = check_buffer_access(env, reg, regno, off, size, false, 4545 - "rdwr", 4546 - &env->prog->aux->max_rdwr_access); 4547 - if (!err && t == BPF_READ && value_regno >= 0) 4571 + buf_info, max_access); 4572 + 4573 + if (!err && value_regno >= 0 && (rdonly_mem || t == BPF_READ)) 4548 4574 mark_reg_unknown(env, regs, value_regno); 4549 4575 } else { 4550 4576 verbose(env, "R%d invalid mem access '%s'\n", regno, 4551 - reg_type_str[reg->type]); 4577 + reg_type_str(env, reg->type)); 4552 4578 return -EACCES; 4553 4579 } 4554 4580 ··· 4621 4635 is_sk_reg(env, insn->dst_reg)) { 4622 4636 verbose(env, "BPF_ATOMIC stores into R%d %s is not allowed\n", 4623 4637 insn->dst_reg, 4624 - reg_type_str[reg_state(env, insn->dst_reg)->type]); 4638 + reg_type_str(env, reg_state(env, insn->dst_reg)->type)); 4625 4639 return -EACCES; 4626 4640 } 4627 4641 ··· 4798 4812 struct bpf_call_arg_meta *meta) 4799 4813 { 4800 4814 struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno]; 4815 + const char *buf_info; 4816 + u32 *max_access; 4801 4817 4802 - switch (reg->type) { 4818 + switch (base_type(reg->type)) { 4803 4819 case PTR_TO_PACKET: 4804 4820 case PTR_TO_PACKET_META: 4805 4821 return check_packet_access(env, regno, reg->off, access_size, ··· 4820 4832 return check_mem_region_access(env, regno, reg->off, 4821 4833 access_size, reg->mem_size, 4822 4834 zero_size_allowed); 4823 - case PTR_TO_RDONLY_BUF: 4824 - if (meta && meta->raw_mode) 4825 - return -EACCES; 4835 + case PTR_TO_BUF: 4836 + if (type_is_rdonly_mem(reg->type)) { 4837 + if (meta && meta->raw_mode) 4838 + return -EACCES; 4839 + 4840 + buf_info = "rdonly"; 4841 + max_access = &env->prog->aux->max_rdonly_access; 4842 + } else { 4843 + buf_info = "rdwr"; 4844 + max_access = &env->prog->aux->max_rdwr_access; 4845 + } 4826 4846 return check_buffer_access(env, reg, regno, reg->off, 4827 4847 access_size, zero_size_allowed, 4828 - "rdonly", 4829 - &env->prog->aux->max_rdonly_access); 4830 - case PTR_TO_RDWR_BUF: 4831 - return check_buffer_access(env, reg, regno, reg->off, 4832 - access_size, zero_size_allowed, 4833 - "rdwr", 4834 - &env->prog->aux->max_rdwr_access); 4848 + buf_info, max_access); 4835 4849 case PTR_TO_STACK: 4836 4850 return check_stack_range_initialized( 4837 4851 env, ··· 4845 4855 register_is_null(reg)) 4846 4856 return 0; 4847 4857 4848 - verbose(env, "R%d type=%s expected=%s\n", regno, 4849 - reg_type_str[reg->type], 4850 - reg_type_str[PTR_TO_STACK]); 4858 + verbose(env, "R%d type=%s ", regno, 4859 + reg_type_str(env, reg->type)); 4860 + verbose(env, "expected=%s\n", reg_type_str(env, PTR_TO_STACK)); 4851 4861 return -EACCES; 4852 4862 } 4853 4863 } ··· 4858 4868 if (register_is_null(reg)) 4859 4869 return 0; 4860 4870 4861 - if (reg_type_may_be_null(reg->type)) { 4871 + if (type_may_be_null(reg->type)) { 4862 4872 /* Assuming that the register contains a value check if the memory 4863 4873 * access is safe. Temporarily save and restore the register's state as 4864 4874 * the conversion shouldn't be visible to a caller. ··· 5006 5016 5007 5017 static bool arg_type_is_mem_ptr(enum bpf_arg_type type) 5008 5018 { 5009 - return type == ARG_PTR_TO_MEM || 5010 - type == ARG_PTR_TO_MEM_OR_NULL || 5011 - type == ARG_PTR_TO_UNINIT_MEM; 5019 + return base_type(type) == ARG_PTR_TO_MEM || 5020 + base_type(type) == ARG_PTR_TO_UNINIT_MEM; 5012 5021 } 5013 5022 5014 5023 static bool arg_type_is_mem_size(enum bpf_arg_type type) ··· 5112 5123 PTR_TO_MAP_KEY, 5113 5124 PTR_TO_MAP_VALUE, 5114 5125 PTR_TO_MEM, 5115 - PTR_TO_RDONLY_BUF, 5116 - PTR_TO_RDWR_BUF, 5126 + PTR_TO_BUF, 5117 5127 }, 5118 5128 }; 5119 5129 ··· 5143 5155 [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, 5144 5156 [ARG_PTR_TO_MAP_VALUE] = &map_key_value_types, 5145 5157 [ARG_PTR_TO_UNINIT_MAP_VALUE] = &map_key_value_types, 5146 - [ARG_PTR_TO_MAP_VALUE_OR_NULL] = &map_key_value_types, 5147 5158 [ARG_CONST_SIZE] = &scalar_types, 5148 5159 [ARG_CONST_SIZE_OR_ZERO] = &scalar_types, 5149 5160 [ARG_CONST_ALLOC_SIZE_OR_ZERO] = &scalar_types, 5150 5161 [ARG_CONST_MAP_PTR] = &const_map_ptr_types, 5151 5162 [ARG_PTR_TO_CTX] = &context_types, 5152 - [ARG_PTR_TO_CTX_OR_NULL] = &context_types, 5153 5163 [ARG_PTR_TO_SOCK_COMMON] = &sock_types, 5154 5164 #ifdef CONFIG_NET 5155 5165 [ARG_PTR_TO_BTF_ID_SOCK_COMMON] = &btf_id_sock_common_types, 5156 5166 #endif 5157 5167 [ARG_PTR_TO_SOCKET] = &fullsock_types, 5158 - [ARG_PTR_TO_SOCKET_OR_NULL] = &fullsock_types, 5159 5168 [ARG_PTR_TO_BTF_ID] = &btf_ptr_types, 5160 5169 [ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types, 5161 5170 [ARG_PTR_TO_MEM] = &mem_types, 5162 - [ARG_PTR_TO_MEM_OR_NULL] = &mem_types, 5163 5171 [ARG_PTR_TO_UNINIT_MEM] = &mem_types, 5164 5172 [ARG_PTR_TO_ALLOC_MEM] = &alloc_mem_types, 5165 - [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types, 5166 5173 [ARG_PTR_TO_INT] = &int_ptr_types, 5167 5174 [ARG_PTR_TO_LONG] = &int_ptr_types, 5168 5175 [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types, 5169 5176 [ARG_PTR_TO_FUNC] = &func_ptr_types, 5170 - [ARG_PTR_TO_STACK_OR_NULL] = &stack_ptr_types, 5177 + [ARG_PTR_TO_STACK] = &stack_ptr_types, 5171 5178 [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types, 5172 5179 [ARG_PTR_TO_TIMER] = &timer_types, 5173 5180 }; ··· 5176 5193 const struct bpf_reg_types *compatible; 5177 5194 int i, j; 5178 5195 5179 - compatible = compatible_reg_types[arg_type]; 5196 + compatible = compatible_reg_types[base_type(arg_type)]; 5180 5197 if (!compatible) { 5181 5198 verbose(env, "verifier internal error: unsupported arg type %d\n", arg_type); 5182 5199 return -EFAULT; 5183 5200 } 5201 + 5202 + /* ARG_PTR_TO_MEM + RDONLY is compatible with PTR_TO_MEM and PTR_TO_MEM + RDONLY, 5203 + * but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM and NOT with PTR_TO_MEM + RDONLY 5204 + * 5205 + * Same for MAYBE_NULL: 5206 + * 5207 + * ARG_PTR_TO_MEM + MAYBE_NULL is compatible with PTR_TO_MEM and PTR_TO_MEM + MAYBE_NULL, 5208 + * but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM but NOT with PTR_TO_MEM + MAYBE_NULL 5209 + * 5210 + * Therefore we fold these flags depending on the arg_type before comparison. 5211 + */ 5212 + if (arg_type & MEM_RDONLY) 5213 + type &= ~MEM_RDONLY; 5214 + if (arg_type & PTR_MAYBE_NULL) 5215 + type &= ~PTR_MAYBE_NULL; 5184 5216 5185 5217 for (i = 0; i < ARRAY_SIZE(compatible->types); i++) { 5186 5218 expected = compatible->types[i]; ··· 5206 5208 goto found; 5207 5209 } 5208 5210 5209 - verbose(env, "R%d type=%s expected=", regno, reg_type_str[type]); 5211 + verbose(env, "R%d type=%s expected=", regno, reg_type_str(env, reg->type)); 5210 5212 for (j = 0; j + 1 < i; j++) 5211 - verbose(env, "%s, ", reg_type_str[compatible->types[j]]); 5212 - verbose(env, "%s\n", reg_type_str[compatible->types[j]]); 5213 + verbose(env, "%s, ", reg_type_str(env, compatible->types[j])); 5214 + verbose(env, "%s\n", reg_type_str(env, compatible->types[j])); 5213 5215 return -EACCES; 5214 5216 5215 5217 found: 5216 - if (type == PTR_TO_BTF_ID) { 5218 + if (reg->type == PTR_TO_BTF_ID) { 5217 5219 if (!arg_btf_id) { 5218 5220 if (!compatible->btf_id) { 5219 5221 verbose(env, "verifier internal error: missing arg compatible BTF ID\n"); ··· 5272 5274 return -EACCES; 5273 5275 } 5274 5276 5275 - if (arg_type == ARG_PTR_TO_MAP_VALUE || 5276 - arg_type == ARG_PTR_TO_UNINIT_MAP_VALUE || 5277 - arg_type == ARG_PTR_TO_MAP_VALUE_OR_NULL) { 5277 + if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE || 5278 + base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) { 5278 5279 err = resolve_map_arg_type(env, meta, &arg_type); 5279 5280 if (err) 5280 5281 return err; 5281 5282 } 5282 5283 5283 - if (register_is_null(reg) && arg_type_may_be_null(arg_type)) 5284 + if (register_is_null(reg) && type_may_be_null(arg_type)) 5284 5285 /* A NULL register has a SCALAR_VALUE type, so skip 5285 5286 * type checking. 5286 5287 */ ··· 5348 5351 err = check_helper_mem_access(env, regno, 5349 5352 meta->map_ptr->key_size, false, 5350 5353 NULL); 5351 - } else if (arg_type == ARG_PTR_TO_MAP_VALUE || 5352 - (arg_type == ARG_PTR_TO_MAP_VALUE_OR_NULL && 5353 - !register_is_null(reg)) || 5354 - arg_type == ARG_PTR_TO_UNINIT_MAP_VALUE) { 5354 + } else if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE || 5355 + base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) { 5356 + if (type_may_be_null(arg_type) && register_is_null(reg)) 5357 + return 0; 5358 + 5355 5359 /* bpf_map_xxx(..., map_ptr, ..., value) call: 5356 5360 * check [value, value + map->value_size) validity 5357 5361 */ ··· 6482 6484 int *insn_idx_p) 6483 6485 { 6484 6486 const struct bpf_func_proto *fn = NULL; 6487 + enum bpf_return_type ret_type; 6488 + enum bpf_type_flag ret_flag; 6485 6489 struct bpf_reg_state *regs; 6486 6490 struct bpf_call_arg_meta meta; 6487 6491 int insn_idx = *insn_idx_p; ··· 6623 6623 regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG; 6624 6624 6625 6625 /* update return register (already marked as written above) */ 6626 - if (fn->ret_type == RET_INTEGER) { 6626 + ret_type = fn->ret_type; 6627 + ret_flag = type_flag(fn->ret_type); 6628 + if (ret_type == RET_INTEGER) { 6627 6629 /* sets type to SCALAR_VALUE */ 6628 6630 mark_reg_unknown(env, regs, BPF_REG_0); 6629 - } else if (fn->ret_type == RET_VOID) { 6631 + } else if (ret_type == RET_VOID) { 6630 6632 regs[BPF_REG_0].type = NOT_INIT; 6631 - } else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL || 6632 - fn->ret_type == RET_PTR_TO_MAP_VALUE) { 6633 + } else if (base_type(ret_type) == RET_PTR_TO_MAP_VALUE) { 6633 6634 /* There is no offset yet applied, variable or fixed */ 6634 6635 mark_reg_known_zero(env, regs, BPF_REG_0); 6635 6636 /* remember map_ptr, so that check_map_access() ··· 6644 6643 } 6645 6644 regs[BPF_REG_0].map_ptr = meta.map_ptr; 6646 6645 regs[BPF_REG_0].map_uid = meta.map_uid; 6647 - if (fn->ret_type == RET_PTR_TO_MAP_VALUE) { 6648 - regs[BPF_REG_0].type = PTR_TO_MAP_VALUE; 6649 - if (map_value_has_spin_lock(meta.map_ptr)) 6650 - regs[BPF_REG_0].id = ++env->id_gen; 6651 - } else { 6652 - regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL; 6646 + regs[BPF_REG_0].type = PTR_TO_MAP_VALUE | ret_flag; 6647 + if (!type_may_be_null(ret_type) && 6648 + map_value_has_spin_lock(meta.map_ptr)) { 6649 + regs[BPF_REG_0].id = ++env->id_gen; 6653 6650 } 6654 - } else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) { 6651 + } else if (base_type(ret_type) == RET_PTR_TO_SOCKET) { 6655 6652 mark_reg_known_zero(env, regs, BPF_REG_0); 6656 - regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL; 6657 - } else if (fn->ret_type == RET_PTR_TO_SOCK_COMMON_OR_NULL) { 6653 + regs[BPF_REG_0].type = PTR_TO_SOCKET | ret_flag; 6654 + } else if (base_type(ret_type) == RET_PTR_TO_SOCK_COMMON) { 6658 6655 mark_reg_known_zero(env, regs, BPF_REG_0); 6659 - regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON_OR_NULL; 6660 - } else if (fn->ret_type == RET_PTR_TO_TCP_SOCK_OR_NULL) { 6656 + regs[BPF_REG_0].type = PTR_TO_SOCK_COMMON | ret_flag; 6657 + } else if (base_type(ret_type) == RET_PTR_TO_TCP_SOCK) { 6661 6658 mark_reg_known_zero(env, regs, BPF_REG_0); 6662 - regs[BPF_REG_0].type = PTR_TO_TCP_SOCK_OR_NULL; 6663 - } else if (fn->ret_type == RET_PTR_TO_ALLOC_MEM_OR_NULL) { 6659 + regs[BPF_REG_0].type = PTR_TO_TCP_SOCK | ret_flag; 6660 + } else if (base_type(ret_type) == RET_PTR_TO_ALLOC_MEM) { 6664 6661 mark_reg_known_zero(env, regs, BPF_REG_0); 6665 - regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; 6662 + regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag; 6666 6663 regs[BPF_REG_0].mem_size = meta.mem_size; 6667 - } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL || 6668 - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) { 6664 + } else if (base_type(ret_type) == RET_PTR_TO_MEM_OR_BTF_ID) { 6669 6665 const struct btf_type *t; 6670 6666 6671 6667 mark_reg_known_zero(env, regs, BPF_REG_0); ··· 6680 6682 tname, PTR_ERR(ret)); 6681 6683 return -EINVAL; 6682 6684 } 6683 - regs[BPF_REG_0].type = 6684 - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? 6685 - PTR_TO_MEM : PTR_TO_MEM_OR_NULL; 6685 + regs[BPF_REG_0].type = PTR_TO_MEM | ret_flag; 6686 6686 regs[BPF_REG_0].mem_size = tsize; 6687 6687 } else { 6688 - regs[BPF_REG_0].type = 6689 - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? 6690 - PTR_TO_BTF_ID : PTR_TO_BTF_ID_OR_NULL; 6688 + /* MEM_RDONLY may be carried from ret_flag, but it 6689 + * doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise 6690 + * it will confuse the check of PTR_TO_BTF_ID in 6691 + * check_mem_access(). 6692 + */ 6693 + ret_flag &= ~MEM_RDONLY; 6694 + 6695 + regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag; 6691 6696 regs[BPF_REG_0].btf = meta.ret_btf; 6692 6697 regs[BPF_REG_0].btf_id = meta.ret_btf_id; 6693 6698 } 6694 - } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL || 6695 - fn->ret_type == RET_PTR_TO_BTF_ID) { 6699 + } else if (base_type(ret_type) == RET_PTR_TO_BTF_ID) { 6696 6700 int ret_btf_id; 6697 6701 6698 6702 mark_reg_known_zero(env, regs, BPF_REG_0); 6699 - regs[BPF_REG_0].type = fn->ret_type == RET_PTR_TO_BTF_ID ? 6700 - PTR_TO_BTF_ID : 6701 - PTR_TO_BTF_ID_OR_NULL; 6703 + regs[BPF_REG_0].type = PTR_TO_BTF_ID | ret_flag; 6702 6704 ret_btf_id = *fn->ret_btf_id; 6703 6705 if (ret_btf_id == 0) { 6704 - verbose(env, "invalid return type %d of func %s#%d\n", 6705 - fn->ret_type, func_id_name(func_id), func_id); 6706 + verbose(env, "invalid return type %u of func %s#%d\n", 6707 + base_type(ret_type), func_id_name(func_id), 6708 + func_id); 6706 6709 return -EINVAL; 6707 6710 } 6708 6711 /* current BPF helper definitions are only coming from ··· 6712 6713 regs[BPF_REG_0].btf = btf_vmlinux; 6713 6714 regs[BPF_REG_0].btf_id = ret_btf_id; 6714 6715 } else { 6715 - verbose(env, "unknown return type %d of func %s#%d\n", 6716 - fn->ret_type, func_id_name(func_id), func_id); 6716 + verbose(env, "unknown return type %u of func %s#%d\n", 6717 + base_type(ret_type), func_id_name(func_id), func_id); 6717 6718 return -EINVAL; 6718 6719 } 6719 6720 6720 - if (reg_type_may_be_null(regs[BPF_REG_0].type)) 6721 + if (type_may_be_null(regs[BPF_REG_0].type)) 6721 6722 regs[BPF_REG_0].id = ++env->id_gen; 6722 6723 6723 6724 if (is_ptr_cast_function(func_id)) { ··· 6926 6927 6927 6928 if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) { 6928 6929 verbose(env, "math between %s pointer and %lld is not allowed\n", 6929 - reg_type_str[type], val); 6930 + reg_type_str(env, type), val); 6930 6931 return false; 6931 6932 } 6932 6933 6933 6934 if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) { 6934 6935 verbose(env, "%s pointer offset %d is not allowed\n", 6935 - reg_type_str[type], reg->off); 6936 + reg_type_str(env, type), reg->off); 6936 6937 return false; 6937 6938 } 6938 6939 6939 6940 if (smin == S64_MIN) { 6940 6941 verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n", 6941 - reg_type_str[type]); 6942 + reg_type_str(env, type)); 6942 6943 return false; 6943 6944 } 6944 6945 6945 6946 if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { 6946 6947 verbose(env, "value %lld makes %s pointer be out of bounds\n", 6947 - smin, reg_type_str[type]); 6948 + smin, reg_type_str(env, type)); 6948 6949 return false; 6949 6950 } 6950 6951 ··· 7321 7322 return -EACCES; 7322 7323 } 7323 7324 7324 - switch (ptr_reg->type) { 7325 - case PTR_TO_MAP_VALUE_OR_NULL: 7325 + if (ptr_reg->type & PTR_MAYBE_NULL) { 7326 7326 verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n", 7327 - dst, reg_type_str[ptr_reg->type]); 7327 + dst, reg_type_str(env, ptr_reg->type)); 7328 7328 return -EACCES; 7329 + } 7330 + 7331 + switch (base_type(ptr_reg->type)) { 7329 7332 case CONST_PTR_TO_MAP: 7330 7333 /* smin_val represents the known value */ 7331 7334 if (known && smin_val == 0 && opcode == BPF_ADD) ··· 7335 7334 fallthrough; 7336 7335 case PTR_TO_PACKET_END: 7337 7336 case PTR_TO_SOCKET: 7338 - case PTR_TO_SOCKET_OR_NULL: 7339 7337 case PTR_TO_SOCK_COMMON: 7340 - case PTR_TO_SOCK_COMMON_OR_NULL: 7341 7338 case PTR_TO_TCP_SOCK: 7342 - case PTR_TO_TCP_SOCK_OR_NULL: 7343 7339 case PTR_TO_XDP_SOCK: 7344 7340 verbose(env, "R%d pointer arithmetic on %s prohibited\n", 7345 - dst, reg_type_str[ptr_reg->type]); 7341 + dst, reg_type_str(env, ptr_reg->type)); 7346 7342 return -EACCES; 7347 7343 default: 7348 7344 break; ··· 9058 9060 struct bpf_reg_state *reg, u32 id, 9059 9061 bool is_null) 9060 9062 { 9061 - if (reg_type_may_be_null(reg->type) && reg->id == id && 9063 + if (type_may_be_null(reg->type) && reg->id == id && 9062 9064 !WARN_ON_ONCE(!reg->id)) { 9063 9065 /* Old offset (both fixed and variable parts) should 9064 9066 * have been known-zero, because we don't allow pointer ··· 9436 9438 */ 9437 9439 if (!is_jmp32 && BPF_SRC(insn->code) == BPF_K && 9438 9440 insn->imm == 0 && (opcode == BPF_JEQ || opcode == BPF_JNE) && 9439 - reg_type_may_be_null(dst_reg->type)) { 9441 + type_may_be_null(dst_reg->type)) { 9440 9442 /* Mark all identical registers in each branch as either 9441 9443 * safe or unknown depending R == 0 or R != 0 conditional. 9442 9444 */ ··· 9491 9493 mark_reg_known_zero(env, regs, insn->dst_reg); 9492 9494 9493 9495 dst_reg->type = aux->btf_var.reg_type; 9494 - switch (dst_reg->type) { 9496 + switch (base_type(dst_reg->type)) { 9495 9497 case PTR_TO_MEM: 9496 9498 dst_reg->mem_size = aux->btf_var.mem_size; 9497 9499 break; ··· 9690 9692 /* enforce return zero from async callbacks like timer */ 9691 9693 if (reg->type != SCALAR_VALUE) { 9692 9694 verbose(env, "In async callback the register R0 is not a known value (%s)\n", 9693 - reg_type_str[reg->type]); 9695 + reg_type_str(env, reg->type)); 9694 9696 return -EINVAL; 9695 9697 } 9696 9698 ··· 9704 9706 if (is_subprog) { 9705 9707 if (reg->type != SCALAR_VALUE) { 9706 9708 verbose(env, "At subprogram exit the register R0 is not a scalar value (%s)\n", 9707 - reg_type_str[reg->type]); 9709 + reg_type_str(env, reg->type)); 9708 9710 return -EINVAL; 9709 9711 } 9710 9712 return 0; ··· 9768 9770 9769 9771 if (reg->type != SCALAR_VALUE) { 9770 9772 verbose(env, "At program exit the register R0 is not a known value (%s)\n", 9771 - reg_type_str[reg->type]); 9773 + reg_type_str(env, reg->type)); 9772 9774 return -EINVAL; 9773 9775 } 9774 9776 ··· 10625 10627 return true; 10626 10628 if (rcur->type == NOT_INIT) 10627 10629 return false; 10628 - switch (rold->type) { 10630 + switch (base_type(rold->type)) { 10629 10631 case SCALAR_VALUE: 10630 10632 if (env->explore_alu_limits) 10631 10633 return false; ··· 10647 10649 } 10648 10650 case PTR_TO_MAP_KEY: 10649 10651 case PTR_TO_MAP_VALUE: 10652 + /* a PTR_TO_MAP_VALUE could be safe to use as a 10653 + * PTR_TO_MAP_VALUE_OR_NULL into the same map. 10654 + * However, if the old PTR_TO_MAP_VALUE_OR_NULL then got NULL- 10655 + * checked, doing so could have affected others with the same 10656 + * id, and we can't check for that because we lost the id when 10657 + * we converted to a PTR_TO_MAP_VALUE. 10658 + */ 10659 + if (type_may_be_null(rold->type)) { 10660 + if (!type_may_be_null(rcur->type)) 10661 + return false; 10662 + if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, id))) 10663 + return false; 10664 + /* Check our ids match any regs they're supposed to */ 10665 + return check_ids(rold->id, rcur->id, idmap); 10666 + } 10667 + 10650 10668 /* If the new min/max/var_off satisfy the old ones and 10651 10669 * everything else matches, we are OK. 10652 10670 * 'id' is not compared, since it's only used for maps with ··· 10674 10660 return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && 10675 10661 range_within(rold, rcur) && 10676 10662 tnum_in(rold->var_off, rcur->var_off); 10677 - case PTR_TO_MAP_VALUE_OR_NULL: 10678 - /* a PTR_TO_MAP_VALUE could be safe to use as a 10679 - * PTR_TO_MAP_VALUE_OR_NULL into the same map. 10680 - * However, if the old PTR_TO_MAP_VALUE_OR_NULL then got NULL- 10681 - * checked, doing so could have affected others with the same 10682 - * id, and we can't check for that because we lost the id when 10683 - * we converted to a PTR_TO_MAP_VALUE. 10684 - */ 10685 - if (rcur->type != PTR_TO_MAP_VALUE_OR_NULL) 10686 - return false; 10687 - if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, id))) 10688 - return false; 10689 - /* Check our ids match any regs they're supposed to */ 10690 - return check_ids(rold->id, rcur->id, idmap); 10691 10663 case PTR_TO_PACKET_META: 10692 10664 case PTR_TO_PACKET: 10693 10665 if (rcur->type != rold->type) ··· 10702 10702 case PTR_TO_PACKET_END: 10703 10703 case PTR_TO_FLOW_KEYS: 10704 10704 case PTR_TO_SOCKET: 10705 - case PTR_TO_SOCKET_OR_NULL: 10706 10705 case PTR_TO_SOCK_COMMON: 10707 - case PTR_TO_SOCK_COMMON_OR_NULL: 10708 10706 case PTR_TO_TCP_SOCK: 10709 - case PTR_TO_TCP_SOCK_OR_NULL: 10710 10707 case PTR_TO_XDP_SOCK: 10711 10708 /* Only valid matches are exact, which memcmp() above 10712 10709 * would have accepted ··· 11229 11232 /* Return true if it's OK to have the same insn return a different type. */ 11230 11233 static bool reg_type_mismatch_ok(enum bpf_reg_type type) 11231 11234 { 11232 - switch (type) { 11235 + switch (base_type(type)) { 11233 11236 case PTR_TO_CTX: 11234 11237 case PTR_TO_SOCKET: 11235 - case PTR_TO_SOCKET_OR_NULL: 11236 11238 case PTR_TO_SOCK_COMMON: 11237 - case PTR_TO_SOCK_COMMON_OR_NULL: 11238 11239 case PTR_TO_TCP_SOCK: 11239 - case PTR_TO_TCP_SOCK_OR_NULL: 11240 11240 case PTR_TO_XDP_SOCK: 11241 11241 case PTR_TO_BTF_ID: 11242 - case PTR_TO_BTF_ID_OR_NULL: 11243 11242 return false; 11244 11243 default: 11245 11244 return true; ··· 11461 11468 if (is_ctx_reg(env, insn->dst_reg)) { 11462 11469 verbose(env, "BPF_ST stores into R%d %s is not allowed\n", 11463 11470 insn->dst_reg, 11464 - reg_type_str[reg_state(env, insn->dst_reg)->type]); 11471 + reg_type_str(env, reg_state(env, insn->dst_reg)->type)); 11465 11472 return -EACCES; 11466 11473 } 11467 11474 ··· 11714 11721 err = -EINVAL; 11715 11722 goto err_put; 11716 11723 } 11717 - aux->btf_var.reg_type = PTR_TO_MEM; 11724 + aux->btf_var.reg_type = PTR_TO_MEM | MEM_RDONLY; 11718 11725 aux->btf_var.mem_size = tsize; 11719 11726 } else { 11720 11727 aux->btf_var.reg_type = PTR_TO_BTF_ID; ··· 13614 13621 mark_reg_known_zero(env, regs, i); 13615 13622 else if (regs[i].type == SCALAR_VALUE) 13616 13623 mark_reg_unknown(env, regs, i); 13617 - else if (regs[i].type == PTR_TO_MEM_OR_NULL) { 13624 + else if (base_type(regs[i].type) == PTR_TO_MEM) { 13618 13625 const u32 mem_size = regs[i].mem_size; 13619 13626 13620 13627 mark_reg_known_zero(env, regs, i);
+13 -13
kernel/trace/bpf_trace.c
··· 345 345 .gpl_only = true, 346 346 .ret_type = RET_INTEGER, 347 347 .arg1_type = ARG_ANYTHING, 348 - .arg2_type = ARG_PTR_TO_MEM, 348 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 349 349 .arg3_type = ARG_CONST_SIZE, 350 350 }; 351 351 ··· 394 394 .func = bpf_trace_printk, 395 395 .gpl_only = true, 396 396 .ret_type = RET_INTEGER, 397 - .arg1_type = ARG_PTR_TO_MEM, 397 + .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 398 398 .arg2_type = ARG_CONST_SIZE, 399 399 }; 400 400 ··· 450 450 .func = bpf_trace_vprintk, 451 451 .gpl_only = true, 452 452 .ret_type = RET_INTEGER, 453 - .arg1_type = ARG_PTR_TO_MEM, 453 + .arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY, 454 454 .arg2_type = ARG_CONST_SIZE, 455 - .arg3_type = ARG_PTR_TO_MEM_OR_NULL, 455 + .arg3_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 456 456 .arg4_type = ARG_CONST_SIZE_OR_ZERO, 457 457 }; 458 458 ··· 492 492 .ret_type = RET_INTEGER, 493 493 .arg1_type = ARG_PTR_TO_BTF_ID, 494 494 .arg1_btf_id = &btf_seq_file_ids[0], 495 - .arg2_type = ARG_PTR_TO_MEM, 495 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 496 496 .arg3_type = ARG_CONST_SIZE, 497 - .arg4_type = ARG_PTR_TO_MEM_OR_NULL, 497 + .arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 498 498 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 499 499 }; 500 500 ··· 509 509 .ret_type = RET_INTEGER, 510 510 .arg1_type = ARG_PTR_TO_BTF_ID, 511 511 .arg1_btf_id = &btf_seq_file_ids[0], 512 - .arg2_type = ARG_PTR_TO_MEM, 512 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 513 513 .arg3_type = ARG_CONST_SIZE_OR_ZERO, 514 514 }; 515 515 ··· 533 533 .ret_type = RET_INTEGER, 534 534 .arg1_type = ARG_PTR_TO_BTF_ID, 535 535 .arg1_btf_id = &btf_seq_file_ids[0], 536 - .arg2_type = ARG_PTR_TO_MEM, 536 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 537 537 .arg3_type = ARG_CONST_SIZE_OR_ZERO, 538 538 .arg4_type = ARG_ANYTHING, 539 539 }; ··· 694 694 .arg1_type = ARG_PTR_TO_CTX, 695 695 .arg2_type = ARG_CONST_MAP_PTR, 696 696 .arg3_type = ARG_ANYTHING, 697 - .arg4_type = ARG_PTR_TO_MEM, 697 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 698 698 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 699 699 }; 700 700 ··· 1004 1004 .ret_type = RET_INTEGER, 1005 1005 .arg1_type = ARG_PTR_TO_MEM, 1006 1006 .arg2_type = ARG_CONST_SIZE, 1007 - .arg3_type = ARG_PTR_TO_MEM, 1007 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1008 1008 .arg4_type = ARG_CONST_SIZE, 1009 1009 .arg5_type = ARG_ANYTHING, 1010 1010 }; ··· 1334 1334 .arg1_type = ARG_PTR_TO_CTX, 1335 1335 .arg2_type = ARG_CONST_MAP_PTR, 1336 1336 .arg3_type = ARG_ANYTHING, 1337 - .arg4_type = ARG_PTR_TO_MEM, 1337 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1338 1338 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 1339 1339 }; 1340 1340 ··· 1556 1556 .arg1_type = ARG_PTR_TO_CTX, 1557 1557 .arg2_type = ARG_CONST_MAP_PTR, 1558 1558 .arg3_type = ARG_ANYTHING, 1559 - .arg4_type = ARG_PTR_TO_MEM, 1559 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1560 1560 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 1561 1561 }; 1562 1562 ··· 1610 1610 .gpl_only = true, 1611 1611 .ret_type = RET_INTEGER, 1612 1612 .arg1_type = ARG_PTR_TO_CTX, 1613 - .arg2_type = ARG_PTR_TO_MEM, 1613 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1614 1614 .arg3_type = ARG_CONST_SIZE_OR_ZERO, 1615 1615 .arg4_type = ARG_ANYTHING, 1616 1616 };
+1 -1
net/core/bpf_sk_storage.c
··· 929 929 { offsetof(struct bpf_iter__bpf_sk_storage_map, sk), 930 930 PTR_TO_BTF_ID_OR_NULL }, 931 931 { offsetof(struct bpf_iter__bpf_sk_storage_map, value), 932 - PTR_TO_RDWR_BUF_OR_NULL }, 932 + PTR_TO_BUF | PTR_MAYBE_NULL }, 933 933 }, 934 934 .seq_info = &iter_seq_info, 935 935 };
+32 -32
net/core/filter.c
··· 1712 1712 .ret_type = RET_INTEGER, 1713 1713 .arg1_type = ARG_PTR_TO_CTX, 1714 1714 .arg2_type = ARG_ANYTHING, 1715 - .arg3_type = ARG_PTR_TO_MEM, 1715 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 1716 1716 .arg4_type = ARG_CONST_SIZE, 1717 1717 .arg5_type = ARG_ANYTHING, 1718 1718 }; ··· 2017 2017 .gpl_only = false, 2018 2018 .pkt_access = true, 2019 2019 .ret_type = RET_INTEGER, 2020 - .arg1_type = ARG_PTR_TO_MEM_OR_NULL, 2020 + .arg1_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 2021 2021 .arg2_type = ARG_CONST_SIZE_OR_ZERO, 2022 - .arg3_type = ARG_PTR_TO_MEM_OR_NULL, 2022 + .arg3_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 2023 2023 .arg4_type = ARG_CONST_SIZE_OR_ZERO, 2024 2024 .arg5_type = ARG_ANYTHING, 2025 2025 }; ··· 2540 2540 .gpl_only = false, 2541 2541 .ret_type = RET_INTEGER, 2542 2542 .arg1_type = ARG_ANYTHING, 2543 - .arg2_type = ARG_PTR_TO_MEM_OR_NULL, 2543 + .arg2_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY, 2544 2544 .arg3_type = ARG_CONST_SIZE_OR_ZERO, 2545 2545 .arg4_type = ARG_ANYTHING, 2546 2546 }; ··· 4173 4173 .arg1_type = ARG_PTR_TO_CTX, 4174 4174 .arg2_type = ARG_CONST_MAP_PTR, 4175 4175 .arg3_type = ARG_ANYTHING, 4176 - .arg4_type = ARG_PTR_TO_MEM, 4176 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4177 4177 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 4178 4178 }; 4179 4179 ··· 4187 4187 .arg1_btf_id = &bpf_skb_output_btf_ids[0], 4188 4188 .arg2_type = ARG_CONST_MAP_PTR, 4189 4189 .arg3_type = ARG_ANYTHING, 4190 - .arg4_type = ARG_PTR_TO_MEM, 4190 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4191 4191 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 4192 4192 }; 4193 4193 ··· 4370 4370 .gpl_only = false, 4371 4371 .ret_type = RET_INTEGER, 4372 4372 .arg1_type = ARG_PTR_TO_CTX, 4373 - .arg2_type = ARG_PTR_TO_MEM, 4373 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4374 4374 .arg3_type = ARG_CONST_SIZE, 4375 4375 .arg4_type = ARG_ANYTHING, 4376 4376 }; ··· 4396 4396 .gpl_only = false, 4397 4397 .ret_type = RET_INTEGER, 4398 4398 .arg1_type = ARG_PTR_TO_CTX, 4399 - .arg2_type = ARG_PTR_TO_MEM, 4399 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4400 4400 .arg3_type = ARG_CONST_SIZE, 4401 4401 }; 4402 4402 ··· 4566 4566 .arg1_type = ARG_PTR_TO_CTX, 4567 4567 .arg2_type = ARG_CONST_MAP_PTR, 4568 4568 .arg3_type = ARG_ANYTHING, 4569 - .arg4_type = ARG_PTR_TO_MEM, 4569 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4570 4570 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 4571 4571 }; 4572 4572 ··· 4580 4580 .arg1_btf_id = &bpf_xdp_output_btf_ids[0], 4581 4581 .arg2_type = ARG_CONST_MAP_PTR, 4582 4582 .arg3_type = ARG_ANYTHING, 4583 - .arg4_type = ARG_PTR_TO_MEM, 4583 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 4584 4584 .arg5_type = ARG_CONST_SIZE_OR_ZERO, 4585 4585 }; 4586 4586 ··· 5066 5066 .arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON, 5067 5067 .arg2_type = ARG_ANYTHING, 5068 5068 .arg3_type = ARG_ANYTHING, 5069 - .arg4_type = ARG_PTR_TO_MEM, 5069 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5070 5070 .arg5_type = ARG_CONST_SIZE, 5071 5071 }; 5072 5072 ··· 5100 5100 .arg1_type = ARG_PTR_TO_CTX, 5101 5101 .arg2_type = ARG_ANYTHING, 5102 5102 .arg3_type = ARG_ANYTHING, 5103 - .arg4_type = ARG_PTR_TO_MEM, 5103 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5104 5104 .arg5_type = ARG_CONST_SIZE, 5105 5105 }; 5106 5106 ··· 5134 5134 .arg1_type = ARG_PTR_TO_CTX, 5135 5135 .arg2_type = ARG_ANYTHING, 5136 5136 .arg3_type = ARG_ANYTHING, 5137 - .arg4_type = ARG_PTR_TO_MEM, 5137 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5138 5138 .arg5_type = ARG_CONST_SIZE, 5139 5139 }; 5140 5140 ··· 5309 5309 .gpl_only = false, 5310 5310 .ret_type = RET_INTEGER, 5311 5311 .arg1_type = ARG_PTR_TO_CTX, 5312 - .arg2_type = ARG_PTR_TO_MEM, 5312 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5313 5313 .arg3_type = ARG_CONST_SIZE, 5314 5314 }; 5315 5315 ··· 5897 5897 .ret_type = RET_INTEGER, 5898 5898 .arg1_type = ARG_PTR_TO_CTX, 5899 5899 .arg2_type = ARG_ANYTHING, 5900 - .arg3_type = ARG_PTR_TO_MEM, 5900 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5901 5901 .arg4_type = ARG_CONST_SIZE 5902 5902 }; 5903 5903 ··· 5907 5907 .ret_type = RET_INTEGER, 5908 5908 .arg1_type = ARG_PTR_TO_CTX, 5909 5909 .arg2_type = ARG_ANYTHING, 5910 - .arg3_type = ARG_PTR_TO_MEM, 5910 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5911 5911 .arg4_type = ARG_CONST_SIZE 5912 5912 }; 5913 5913 ··· 5950 5950 .ret_type = RET_INTEGER, 5951 5951 .arg1_type = ARG_PTR_TO_CTX, 5952 5952 .arg2_type = ARG_ANYTHING, 5953 - .arg3_type = ARG_PTR_TO_MEM, 5953 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 5954 5954 .arg4_type = ARG_CONST_SIZE 5955 5955 }; 5956 5956 ··· 6038 6038 .ret_type = RET_INTEGER, 6039 6039 .arg1_type = ARG_PTR_TO_CTX, 6040 6040 .arg2_type = ARG_ANYTHING, 6041 - .arg3_type = ARG_PTR_TO_MEM, 6041 + .arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6042 6042 .arg4_type = ARG_CONST_SIZE 6043 6043 }; 6044 6044 ··· 6263 6263 .pkt_access = true, 6264 6264 .ret_type = RET_PTR_TO_SOCK_COMMON_OR_NULL, 6265 6265 .arg1_type = ARG_PTR_TO_CTX, 6266 - .arg2_type = ARG_PTR_TO_MEM, 6266 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6267 6267 .arg3_type = ARG_CONST_SIZE, 6268 6268 .arg4_type = ARG_ANYTHING, 6269 6269 .arg5_type = ARG_ANYTHING, ··· 6282 6282 .pkt_access = true, 6283 6283 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6284 6284 .arg1_type = ARG_PTR_TO_CTX, 6285 - .arg2_type = ARG_PTR_TO_MEM, 6285 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6286 6286 .arg3_type = ARG_CONST_SIZE, 6287 6287 .arg4_type = ARG_ANYTHING, 6288 6288 .arg5_type = ARG_ANYTHING, ··· 6301 6301 .pkt_access = true, 6302 6302 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6303 6303 .arg1_type = ARG_PTR_TO_CTX, 6304 - .arg2_type = ARG_PTR_TO_MEM, 6304 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6305 6305 .arg3_type = ARG_CONST_SIZE, 6306 6306 .arg4_type = ARG_ANYTHING, 6307 6307 .arg5_type = ARG_ANYTHING, ··· 6338 6338 .pkt_access = true, 6339 6339 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6340 6340 .arg1_type = ARG_PTR_TO_CTX, 6341 - .arg2_type = ARG_PTR_TO_MEM, 6341 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6342 6342 .arg3_type = ARG_CONST_SIZE, 6343 6343 .arg4_type = ARG_ANYTHING, 6344 6344 .arg5_type = ARG_ANYTHING, ··· 6361 6361 .pkt_access = true, 6362 6362 .ret_type = RET_PTR_TO_SOCK_COMMON_OR_NULL, 6363 6363 .arg1_type = ARG_PTR_TO_CTX, 6364 - .arg2_type = ARG_PTR_TO_MEM, 6364 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6365 6365 .arg3_type = ARG_CONST_SIZE, 6366 6366 .arg4_type = ARG_ANYTHING, 6367 6367 .arg5_type = ARG_ANYTHING, ··· 6384 6384 .pkt_access = true, 6385 6385 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6386 6386 .arg1_type = ARG_PTR_TO_CTX, 6387 - .arg2_type = ARG_PTR_TO_MEM, 6387 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6388 6388 .arg3_type = ARG_CONST_SIZE, 6389 6389 .arg4_type = ARG_ANYTHING, 6390 6390 .arg5_type = ARG_ANYTHING, ··· 6403 6403 .gpl_only = false, 6404 6404 .ret_type = RET_PTR_TO_SOCK_COMMON_OR_NULL, 6405 6405 .arg1_type = ARG_PTR_TO_CTX, 6406 - .arg2_type = ARG_PTR_TO_MEM, 6406 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6407 6407 .arg3_type = ARG_CONST_SIZE, 6408 6408 .arg4_type = ARG_ANYTHING, 6409 6409 .arg5_type = ARG_ANYTHING, ··· 6422 6422 .gpl_only = false, 6423 6423 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6424 6424 .arg1_type = ARG_PTR_TO_CTX, 6425 - .arg2_type = ARG_PTR_TO_MEM, 6425 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6426 6426 .arg3_type = ARG_CONST_SIZE, 6427 6427 .arg4_type = ARG_ANYTHING, 6428 6428 .arg5_type = ARG_ANYTHING, ··· 6441 6441 .gpl_only = false, 6442 6442 .ret_type = RET_PTR_TO_SOCKET_OR_NULL, 6443 6443 .arg1_type = ARG_PTR_TO_CTX, 6444 - .arg2_type = ARG_PTR_TO_MEM, 6444 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6445 6445 .arg3_type = ARG_CONST_SIZE, 6446 6446 .arg4_type = ARG_ANYTHING, 6447 6447 .arg5_type = ARG_ANYTHING, ··· 6754 6754 .pkt_access = true, 6755 6755 .ret_type = RET_INTEGER, 6756 6756 .arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON, 6757 - .arg2_type = ARG_PTR_TO_MEM, 6757 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6758 6758 .arg3_type = ARG_CONST_SIZE, 6759 - .arg4_type = ARG_PTR_TO_MEM, 6759 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6760 6760 .arg5_type = ARG_CONST_SIZE, 6761 6761 }; 6762 6762 ··· 6823 6823 .pkt_access = true, 6824 6824 .ret_type = RET_INTEGER, 6825 6825 .arg1_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON, 6826 - .arg2_type = ARG_PTR_TO_MEM, 6826 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6827 6827 .arg3_type = ARG_CONST_SIZE, 6828 - .arg4_type = ARG_PTR_TO_MEM, 6828 + .arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY, 6829 6829 .arg5_type = ARG_CONST_SIZE, 6830 6830 }; 6831 6831 ··· 7054 7054 .gpl_only = false, 7055 7055 .ret_type = RET_INTEGER, 7056 7056 .arg1_type = ARG_PTR_TO_CTX, 7057 - .arg2_type = ARG_PTR_TO_MEM, 7057 + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, 7058 7058 .arg3_type = ARG_CONST_SIZE, 7059 7059 .arg4_type = ARG_ANYTHING, 7060 7060 };
+1 -1
net/core/sock_map.c
··· 1564 1564 .ctx_arg_info_size = 2, 1565 1565 .ctx_arg_info = { 1566 1566 { offsetof(struct bpf_iter__sockmap, key), 1567 - PTR_TO_RDONLY_BUF_OR_NULL }, 1567 + PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY }, 1568 1568 { offsetof(struct bpf_iter__sockmap, sk), 1569 1569 PTR_TO_BTF_ID_OR_NULL }, 1570 1570 },
+14
tools/testing/selftests/bpf/prog_tests/ksyms_btf.c
··· 8 8 #include "test_ksyms_btf_null_check.skel.h" 9 9 #include "test_ksyms_weak.skel.h" 10 10 #include "test_ksyms_weak.lskel.h" 11 + #include "test_ksyms_btf_write_check.skel.h" 11 12 12 13 static int duration; 13 14 ··· 138 137 test_ksyms_weak_lskel__destroy(skel); 139 138 } 140 139 140 + static void test_write_check(void) 141 + { 142 + struct test_ksyms_btf_write_check *skel; 143 + 144 + skel = test_ksyms_btf_write_check__open_and_load(); 145 + ASSERT_ERR_PTR(skel, "unexpected load of a prog writing to ksym memory\n"); 146 + 147 + test_ksyms_btf_write_check__destroy(skel); 148 + } 149 + 141 150 void test_ksyms_btf(void) 142 151 { 143 152 int percpu_datasec; ··· 178 167 179 168 if (test__start_subtest("weak_ksyms_lskel")) 180 169 test_weak_syms_lskel(); 170 + 171 + if (test__start_subtest("write_check")) 172 + test_write_check(); 181 173 }
+29
tools/testing/selftests/bpf/progs/test_ksyms_btf_write_check.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2021 Google */ 3 + 4 + #include "vmlinux.h" 5 + 6 + #include <bpf/bpf_helpers.h> 7 + 8 + extern const int bpf_prog_active __ksym; /* int type global var. */ 9 + 10 + SEC("raw_tp/sys_enter") 11 + int handler(const void *ctx) 12 + { 13 + int *active; 14 + __u32 cpu; 15 + 16 + cpu = bpf_get_smp_processor_id(); 17 + active = (int *)bpf_per_cpu_ptr(&bpf_prog_active, cpu); 18 + if (active) { 19 + /* Kernel memory obtained from bpf_{per,this}_cpu_ptr 20 + * is read-only, should _not_ pass verification. 21 + */ 22 + /* WRITE_ONCE */ 23 + *(volatile int *)active = -1; 24 + } 25 + 26 + return 0; 27 + } 28 + 29 + char _license[] SEC("license") = "GPL";