Message ID | 20230226085120.3907863-10-joannelkoong@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | Add skb + xdp dynptrs | expand |
Hi Joanne, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on bpf-next/master] url: https://github.com/intel-lab-lkp/linux/commits/Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master patch link: https://lore.kernel.org/r/20230226085120.3907863-10-joannelkoong%40gmail.com patch subject: [PATCH v12 bpf-next 09/10] bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr config: hexagon-randconfig-r026-20230226 (https://download.01.org/0day-ci/archive/20230226/202302261742.iOSFw9wm-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project db89896bbbd2251fff457699635acbbedeead27f) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/bc5a61c43c72539ef11e6435a168bf240a186ac1 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 git checkout bc5a61c43c72539ef11e6435a168bf240a186ac1 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash kernel/bpf/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202302261742.iOSFw9wm-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __raw_readb(PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu' #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) ^ In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu' #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) ^ In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writeb(value, PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ kernel/bpf/verifier.c:6253:5: warning: no previous prototype for function 'process_dynptr_func' [-Wmissing-prototypes] int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ kernel/bpf/verifier.c:6253:1: note: declare 'static' if the function is not intended to be used outside of this translation unit int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ static kernel/bpf/verifier.c:9907:4: error: expected expression struct bpf_reg_state *size_reg = ®s[regno + 1]; ^ kernel/bpf/verifier.c:9910:40: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9916:57: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9921:24: error: use of undeclared identifier 'size_reg' if (!tnum_is_const(size_reg->var_off)) { ^ kernel/bpf/verifier.c:9926:32: error: use of undeclared identifier 'size_reg' meta->arg_constant.value = size_reg->var_off.value; ^ >> kernel/bpf/verifier.c:9908:28: warning: mixing declarations and code is incompatible with standards before C99 [-Wdeclaration-after-statement] const struct btf_param *size_arg = &args[i + 1]; ^ 8 warnings and 5 errors generated. vim +9908 kernel/bpf/verifier.c 9584 9585 static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta, 9586 int insn_idx) 9587 { 9588 const char *func_name = meta->func_name, *ref_tname; 9589 const struct btf *btf = meta->btf; 9590 const struct btf_param *args; 9591 u32 i, nargs; 9592 int ret; 9593 9594 args = (const struct btf_param *)(meta->func_proto + 1); 9595 nargs = btf_type_vlen(meta->func_proto); 9596 if (nargs > MAX_BPF_FUNC_REG_ARGS) { 9597 verbose(env, "Function %s has %d > %d args\n", func_name, nargs, 9598 MAX_BPF_FUNC_REG_ARGS); 9599 return -EINVAL; 9600 } 9601 9602 /* Check that BTF function arguments match actual types that the 9603 * verifier sees. 9604 */ 9605 for (i = 0; i < nargs; i++) { 9606 struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[i + 1]; 9607 const struct btf_type *t, *ref_t, *resolve_ret; 9608 enum bpf_arg_type arg_type = ARG_DONTCARE; 9609 u32 regno = i + 1, ref_id, type_size; 9610 bool is_ret_buf_sz = false; 9611 int kf_arg_type; 9612 9613 t = btf_type_skip_modifiers(btf, args[i].type, NULL); 9614 9615 if (is_kfunc_arg_ignore(btf, &args[i])) 9616 continue; 9617 9618 if (btf_type_is_scalar(t)) { 9619 if (reg->type != SCALAR_VALUE) { 9620 verbose(env, "R%d is not a scalar\n", regno); 9621 return -EINVAL; 9622 } 9623 9624 if (is_kfunc_arg_constant(meta->btf, &args[i])) { 9625 if (meta->arg_constant.found) { 9626 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9627 return -EFAULT; 9628 } 9629 if (!tnum_is_const(reg->var_off)) { 9630 verbose(env, "R%d must be a known constant\n", regno); 9631 return -EINVAL; 9632 } 9633 ret = mark_chain_precision(env, regno); 9634 if (ret < 0) 9635 return ret; 9636 meta->arg_constant.found = true; 9637 meta->arg_constant.value = reg->var_off.value; 9638 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdonly_buf_size")) { 9639 meta->r0_rdonly = true; 9640 is_ret_buf_sz = true; 9641 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdwr_buf_size")) { 9642 is_ret_buf_sz = true; 9643 } 9644 9645 if (is_ret_buf_sz) { 9646 if (meta->r0_size) { 9647 verbose(env, "2 or more rdonly/rdwr_buf_size parameters for kfunc"); 9648 return -EINVAL; 9649 } 9650 9651 if (!tnum_is_const(reg->var_off)) { 9652 verbose(env, "R%d is not a const\n", regno); 9653 return -EINVAL; 9654 } 9655 9656 meta->r0_size = reg->var_off.value; 9657 ret = mark_chain_precision(env, regno); 9658 if (ret) 9659 return ret; 9660 } 9661 continue; 9662 } 9663 9664 if (!btf_type_is_ptr(t)) { 9665 verbose(env, "Unrecognized arg#%d type %s\n", i, btf_type_str(t)); 9666 return -EINVAL; 9667 } 9668 9669 if (is_kfunc_trusted_args(meta) && 9670 (register_is_null(reg) || type_may_be_null(reg->type))) { 9671 verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i); 9672 return -EACCES; 9673 } 9674 9675 if (reg->ref_obj_id) { 9676 if (is_kfunc_release(meta) && meta->ref_obj_id) { 9677 verbose(env, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n", 9678 regno, reg->ref_obj_id, 9679 meta->ref_obj_id); 9680 return -EFAULT; 9681 } 9682 meta->ref_obj_id = reg->ref_obj_id; 9683 if (is_kfunc_release(meta)) 9684 meta->release_regno = regno; 9685 } 9686 9687 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id); 9688 ref_tname = btf_name_by_offset(btf, ref_t->name_off); 9689 9690 kf_arg_type = get_kfunc_ptr_arg_type(env, meta, t, ref_t, ref_tname, args, i, nargs); 9691 if (kf_arg_type < 0) 9692 return kf_arg_type; 9693 9694 switch (kf_arg_type) { 9695 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9696 case KF_ARG_PTR_TO_BTF_ID: 9697 if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta)) 9698 break; 9699 9700 if (!is_trusted_reg(reg)) { 9701 if (!is_kfunc_rcu(meta)) { 9702 verbose(env, "R%d must be referenced or trusted\n", regno); 9703 return -EINVAL; 9704 } 9705 if (!is_rcu_reg(reg)) { 9706 verbose(env, "R%d must be a rcu pointer\n", regno); 9707 return -EINVAL; 9708 } 9709 } 9710 9711 fallthrough; 9712 case KF_ARG_PTR_TO_CTX: 9713 /* Trusted arguments have the same offset checks as release arguments */ 9714 arg_type |= OBJ_RELEASE; 9715 break; 9716 case KF_ARG_PTR_TO_KPTR: 9717 case KF_ARG_PTR_TO_DYNPTR: 9718 case KF_ARG_PTR_TO_LIST_HEAD: 9719 case KF_ARG_PTR_TO_LIST_NODE: 9720 case KF_ARG_PTR_TO_RB_ROOT: 9721 case KF_ARG_PTR_TO_RB_NODE: 9722 case KF_ARG_PTR_TO_MEM: 9723 case KF_ARG_PTR_TO_MEM_SIZE: 9724 case KF_ARG_PTR_TO_CALLBACK: 9725 /* Trusted by default */ 9726 break; 9727 default: 9728 WARN_ON_ONCE(1); 9729 return -EFAULT; 9730 } 9731 9732 if (is_kfunc_release(meta) && reg->ref_obj_id) 9733 arg_type |= OBJ_RELEASE; 9734 ret = check_func_arg_reg_off(env, reg, regno, arg_type); 9735 if (ret < 0) 9736 return ret; 9737 9738 switch (kf_arg_type) { 9739 case KF_ARG_PTR_TO_CTX: 9740 if (reg->type != PTR_TO_CTX) { 9741 verbose(env, "arg#%d expected pointer to ctx, but got %s\n", i, btf_type_str(t)); 9742 return -EINVAL; 9743 } 9744 9745 if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 9746 ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog)); 9747 if (ret < 0) 9748 return -EINVAL; 9749 meta->ret_btf_id = ret; 9750 } 9751 break; 9752 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9753 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9754 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9755 return -EINVAL; 9756 } 9757 if (!reg->ref_obj_id) { 9758 verbose(env, "allocated object must be referenced\n"); 9759 return -EINVAL; 9760 } 9761 if (meta->btf == btf_vmlinux && 9762 meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { 9763 meta->arg_obj_drop.btf = reg->btf; 9764 meta->arg_obj_drop.btf_id = reg->btf_id; 9765 } 9766 break; 9767 case KF_ARG_PTR_TO_KPTR: 9768 if (reg->type != PTR_TO_MAP_VALUE) { 9769 verbose(env, "arg#0 expected pointer to map value\n"); 9770 return -EINVAL; 9771 } 9772 ret = process_kf_arg_ptr_to_kptr(env, reg, ref_t, ref_tname, meta, i); 9773 if (ret < 0) 9774 return ret; 9775 break; 9776 case KF_ARG_PTR_TO_DYNPTR: 9777 { 9778 enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR; 9779 9780 if (reg->type != PTR_TO_STACK && 9781 reg->type != CONST_PTR_TO_DYNPTR) { 9782 verbose(env, "arg#%d expected pointer to stack or dynptr_ptr\n", i); 9783 return -EINVAL; 9784 } 9785 9786 if (reg->type == CONST_PTR_TO_DYNPTR) 9787 dynptr_arg_type |= MEM_RDONLY; 9788 9789 if (is_kfunc_arg_uninit(btf, &args[i])) 9790 dynptr_arg_type |= MEM_UNINIT; 9791 9792 if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) 9793 dynptr_arg_type |= DYNPTR_TYPE_SKB; 9794 else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) 9795 dynptr_arg_type |= DYNPTR_TYPE_XDP; 9796 9797 ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type); 9798 if (ret < 0) 9799 return ret; 9800 9801 if (!(dynptr_arg_type & MEM_UNINIT)) { 9802 int id = dynptr_id(env, reg); 9803 9804 if (id < 0) { 9805 verbose(env, "verifier internal error: failed to obtain dynptr id\n"); 9806 return id; 9807 } 9808 meta->initialized_dynptr.id = id; 9809 meta->initialized_dynptr.type = dynptr_get_type(env, reg); 9810 } 9811 9812 break; 9813 } 9814 case KF_ARG_PTR_TO_LIST_HEAD: 9815 if (reg->type != PTR_TO_MAP_VALUE && 9816 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9817 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9818 return -EINVAL; 9819 } 9820 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9821 verbose(env, "allocated object must be referenced\n"); 9822 return -EINVAL; 9823 } 9824 ret = process_kf_arg_ptr_to_list_head(env, reg, regno, meta); 9825 if (ret < 0) 9826 return ret; 9827 break; 9828 case KF_ARG_PTR_TO_RB_ROOT: 9829 if (reg->type != PTR_TO_MAP_VALUE && 9830 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9831 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9832 return -EINVAL; 9833 } 9834 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9835 verbose(env, "allocated object must be referenced\n"); 9836 return -EINVAL; 9837 } 9838 ret = process_kf_arg_ptr_to_rbtree_root(env, reg, regno, meta); 9839 if (ret < 0) 9840 return ret; 9841 break; 9842 case KF_ARG_PTR_TO_LIST_NODE: 9843 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9844 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9845 return -EINVAL; 9846 } 9847 if (!reg->ref_obj_id) { 9848 verbose(env, "allocated object must be referenced\n"); 9849 return -EINVAL; 9850 } 9851 ret = process_kf_arg_ptr_to_list_node(env, reg, regno, meta); 9852 if (ret < 0) 9853 return ret; 9854 break; 9855 case KF_ARG_PTR_TO_RB_NODE: 9856 if (meta->func_id == special_kfunc_list[KF_bpf_rbtree_remove]) { 9857 if (!type_is_non_owning_ref(reg->type) || reg->ref_obj_id) { 9858 verbose(env, "rbtree_remove node input must be non-owning ref\n"); 9859 return -EINVAL; 9860 } 9861 if (in_rbtree_lock_required_cb(env)) { 9862 verbose(env, "rbtree_remove not allowed in rbtree cb\n"); 9863 return -EINVAL; 9864 } 9865 } else { 9866 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9867 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9868 return -EINVAL; 9869 } 9870 if (!reg->ref_obj_id) { 9871 verbose(env, "allocated object must be referenced\n"); 9872 return -EINVAL; 9873 } 9874 } 9875 9876 ret = process_kf_arg_ptr_to_rbtree_node(env, reg, regno, meta); 9877 if (ret < 0) 9878 return ret; 9879 break; 9880 case KF_ARG_PTR_TO_BTF_ID: 9881 /* Only base_type is checked, further checks are done here */ 9882 if ((base_type(reg->type) != PTR_TO_BTF_ID || 9883 (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) && 9884 !reg2btf_ids[base_type(reg->type)]) { 9885 verbose(env, "arg#%d is %s ", i, reg_type_str(env, reg->type)); 9886 verbose(env, "expected %s or socket\n", 9887 reg_type_str(env, base_type(reg->type) | 9888 (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS))); 9889 return -EINVAL; 9890 } 9891 ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i); 9892 if (ret < 0) 9893 return ret; 9894 break; 9895 case KF_ARG_PTR_TO_MEM: 9896 resolve_ret = btf_resolve_size(btf, ref_t, &type_size); 9897 if (IS_ERR(resolve_ret)) { 9898 verbose(env, "arg#%d reference type('%s %s') size cannot be determined: %ld\n", 9899 i, btf_type_str(ref_t), ref_tname, PTR_ERR(resolve_ret)); 9900 return -EINVAL; 9901 } 9902 ret = check_mem_reg(env, reg, regno, type_size); 9903 if (ret < 0) 9904 return ret; 9905 break; 9906 case KF_ARG_PTR_TO_MEM_SIZE: 9907 struct bpf_reg_state *size_reg = ®s[regno + 1]; > 9908 const struct btf_param *size_arg = &args[i + 1]; 9909 9910 ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); 9911 if (ret < 0) { 9912 verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); 9913 return ret; 9914 } 9915 9916 if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { 9917 if (meta->arg_constant.found) { 9918 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9919 return -EFAULT; 9920 } 9921 if (!tnum_is_const(size_reg->var_off)) { 9922 verbose(env, "R%d must be a known constant\n", regno + 1); 9923 return -EINVAL; 9924 } 9925 meta->arg_constant.found = true; 9926 meta->arg_constant.value = size_reg->var_off.value; 9927 } 9928 9929 /* Skip next '__sz' or '__szk' argument */ 9930 i++; 9931 break; 9932 case KF_ARG_PTR_TO_CALLBACK: 9933 meta->subprogno = reg->subprogno; 9934 break; 9935 } 9936 } 9937 9938 if (is_kfunc_release(meta) && !meta->release_regno) { 9939 verbose(env, "release kernel function %s expects refcounted PTR_TO_BTF_ID\n", 9940 func_name); 9941 return -EINVAL; 9942 } 9943 9944 return 0; 9945 } 9946
Hi Joanne, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on bpf-next/master] url: https://github.com/intel-lab-lkp/linux/commits/Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master patch link: https://lore.kernel.org/r/20230226085120.3907863-10-joannelkoong%40gmail.com patch subject: [PATCH v12 bpf-next 09/10] bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr config: i386-randconfig-a002 (https://download.01.org/0day-ci/archive/20230226/202302261844.BdMQvIkw-lkp@intel.com/config) compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/bc5a61c43c72539ef11e6435a168bf240a186ac1 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 git checkout bc5a61c43c72539ef11e6435a168bf240a186ac1 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash kernel/bpf/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202302261844.BdMQvIkw-lkp@intel.com/ All warnings (new ones prefixed by >>): kernel/bpf/verifier.c:6253:5: warning: no previous prototype for function 'process_dynptr_func' [-Wmissing-prototypes] int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ kernel/bpf/verifier.c:6253:1: note: declare 'static' if the function is not intended to be used outside of this translation unit int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ static kernel/bpf/verifier.c:9907:4: error: expected expression struct bpf_reg_state *size_reg = ®s[regno + 1]; ^ kernel/bpf/verifier.c:9910:40: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9916:57: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9921:24: error: use of undeclared identifier 'size_reg' if (!tnum_is_const(size_reg->var_off)) { ^ kernel/bpf/verifier.c:9926:32: error: use of undeclared identifier 'size_reg' meta->arg_constant.value = size_reg->var_off.value; ^ >> kernel/bpf/verifier.c:9908:28: warning: mixing declarations and code is incompatible with standards before C99 [-Wdeclaration-after-statement] const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:10167:24: warning: array index 16 is past the end of the array (which contains 16 elements) [-Warray-bounds] meta.func_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) { ^ ~~~~~~~~~~~~~~~~~~~~~~~~ kernel/bpf/verifier.c:9017:1: note: array 'special_kfunc_list' declared here BTF_ID_LIST(special_kfunc_list) ^ include/linux/btf_ids.h:207:27: note: expanded from macro 'BTF_ID_LIST' #define BTF_ID_LIST(name) static u32 __maybe_unused name[16]; ^ 3 warnings and 5 errors generated. vim +9908 kernel/bpf/verifier.c 9584 9585 static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta, 9586 int insn_idx) 9587 { 9588 const char *func_name = meta->func_name, *ref_tname; 9589 const struct btf *btf = meta->btf; 9590 const struct btf_param *args; 9591 u32 i, nargs; 9592 int ret; 9593 9594 args = (const struct btf_param *)(meta->func_proto + 1); 9595 nargs = btf_type_vlen(meta->func_proto); 9596 if (nargs > MAX_BPF_FUNC_REG_ARGS) { 9597 verbose(env, "Function %s has %d > %d args\n", func_name, nargs, 9598 MAX_BPF_FUNC_REG_ARGS); 9599 return -EINVAL; 9600 } 9601 9602 /* Check that BTF function arguments match actual types that the 9603 * verifier sees. 9604 */ 9605 for (i = 0; i < nargs; i++) { 9606 struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[i + 1]; 9607 const struct btf_type *t, *ref_t, *resolve_ret; 9608 enum bpf_arg_type arg_type = ARG_DONTCARE; 9609 u32 regno = i + 1, ref_id, type_size; 9610 bool is_ret_buf_sz = false; 9611 int kf_arg_type; 9612 9613 t = btf_type_skip_modifiers(btf, args[i].type, NULL); 9614 9615 if (is_kfunc_arg_ignore(btf, &args[i])) 9616 continue; 9617 9618 if (btf_type_is_scalar(t)) { 9619 if (reg->type != SCALAR_VALUE) { 9620 verbose(env, "R%d is not a scalar\n", regno); 9621 return -EINVAL; 9622 } 9623 9624 if (is_kfunc_arg_constant(meta->btf, &args[i])) { 9625 if (meta->arg_constant.found) { 9626 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9627 return -EFAULT; 9628 } 9629 if (!tnum_is_const(reg->var_off)) { 9630 verbose(env, "R%d must be a known constant\n", regno); 9631 return -EINVAL; 9632 } 9633 ret = mark_chain_precision(env, regno); 9634 if (ret < 0) 9635 return ret; 9636 meta->arg_constant.found = true; 9637 meta->arg_constant.value = reg->var_off.value; 9638 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdonly_buf_size")) { 9639 meta->r0_rdonly = true; 9640 is_ret_buf_sz = true; 9641 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdwr_buf_size")) { 9642 is_ret_buf_sz = true; 9643 } 9644 9645 if (is_ret_buf_sz) { 9646 if (meta->r0_size) { 9647 verbose(env, "2 or more rdonly/rdwr_buf_size parameters for kfunc"); 9648 return -EINVAL; 9649 } 9650 9651 if (!tnum_is_const(reg->var_off)) { 9652 verbose(env, "R%d is not a const\n", regno); 9653 return -EINVAL; 9654 } 9655 9656 meta->r0_size = reg->var_off.value; 9657 ret = mark_chain_precision(env, regno); 9658 if (ret) 9659 return ret; 9660 } 9661 continue; 9662 } 9663 9664 if (!btf_type_is_ptr(t)) { 9665 verbose(env, "Unrecognized arg#%d type %s\n", i, btf_type_str(t)); 9666 return -EINVAL; 9667 } 9668 9669 if (is_kfunc_trusted_args(meta) && 9670 (register_is_null(reg) || type_may_be_null(reg->type))) { 9671 verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i); 9672 return -EACCES; 9673 } 9674 9675 if (reg->ref_obj_id) { 9676 if (is_kfunc_release(meta) && meta->ref_obj_id) { 9677 verbose(env, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n", 9678 regno, reg->ref_obj_id, 9679 meta->ref_obj_id); 9680 return -EFAULT; 9681 } 9682 meta->ref_obj_id = reg->ref_obj_id; 9683 if (is_kfunc_release(meta)) 9684 meta->release_regno = regno; 9685 } 9686 9687 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id); 9688 ref_tname = btf_name_by_offset(btf, ref_t->name_off); 9689 9690 kf_arg_type = get_kfunc_ptr_arg_type(env, meta, t, ref_t, ref_tname, args, i, nargs); 9691 if (kf_arg_type < 0) 9692 return kf_arg_type; 9693 9694 switch (kf_arg_type) { 9695 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9696 case KF_ARG_PTR_TO_BTF_ID: 9697 if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta)) 9698 break; 9699 9700 if (!is_trusted_reg(reg)) { 9701 if (!is_kfunc_rcu(meta)) { 9702 verbose(env, "R%d must be referenced or trusted\n", regno); 9703 return -EINVAL; 9704 } 9705 if (!is_rcu_reg(reg)) { 9706 verbose(env, "R%d must be a rcu pointer\n", regno); 9707 return -EINVAL; 9708 } 9709 } 9710 9711 fallthrough; 9712 case KF_ARG_PTR_TO_CTX: 9713 /* Trusted arguments have the same offset checks as release arguments */ 9714 arg_type |= OBJ_RELEASE; 9715 break; 9716 case KF_ARG_PTR_TO_KPTR: 9717 case KF_ARG_PTR_TO_DYNPTR: 9718 case KF_ARG_PTR_TO_LIST_HEAD: 9719 case KF_ARG_PTR_TO_LIST_NODE: 9720 case KF_ARG_PTR_TO_RB_ROOT: 9721 case KF_ARG_PTR_TO_RB_NODE: 9722 case KF_ARG_PTR_TO_MEM: 9723 case KF_ARG_PTR_TO_MEM_SIZE: 9724 case KF_ARG_PTR_TO_CALLBACK: 9725 /* Trusted by default */ 9726 break; 9727 default: 9728 WARN_ON_ONCE(1); 9729 return -EFAULT; 9730 } 9731 9732 if (is_kfunc_release(meta) && reg->ref_obj_id) 9733 arg_type |= OBJ_RELEASE; 9734 ret = check_func_arg_reg_off(env, reg, regno, arg_type); 9735 if (ret < 0) 9736 return ret; 9737 9738 switch (kf_arg_type) { 9739 case KF_ARG_PTR_TO_CTX: 9740 if (reg->type != PTR_TO_CTX) { 9741 verbose(env, "arg#%d expected pointer to ctx, but got %s\n", i, btf_type_str(t)); 9742 return -EINVAL; 9743 } 9744 9745 if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 9746 ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog)); 9747 if (ret < 0) 9748 return -EINVAL; 9749 meta->ret_btf_id = ret; 9750 } 9751 break; 9752 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9753 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9754 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9755 return -EINVAL; 9756 } 9757 if (!reg->ref_obj_id) { 9758 verbose(env, "allocated object must be referenced\n"); 9759 return -EINVAL; 9760 } 9761 if (meta->btf == btf_vmlinux && 9762 meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { 9763 meta->arg_obj_drop.btf = reg->btf; 9764 meta->arg_obj_drop.btf_id = reg->btf_id; 9765 } 9766 break; 9767 case KF_ARG_PTR_TO_KPTR: 9768 if (reg->type != PTR_TO_MAP_VALUE) { 9769 verbose(env, "arg#0 expected pointer to map value\n"); 9770 return -EINVAL; 9771 } 9772 ret = process_kf_arg_ptr_to_kptr(env, reg, ref_t, ref_tname, meta, i); 9773 if (ret < 0) 9774 return ret; 9775 break; 9776 case KF_ARG_PTR_TO_DYNPTR: 9777 { 9778 enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR; 9779 9780 if (reg->type != PTR_TO_STACK && 9781 reg->type != CONST_PTR_TO_DYNPTR) { 9782 verbose(env, "arg#%d expected pointer to stack or dynptr_ptr\n", i); 9783 return -EINVAL; 9784 } 9785 9786 if (reg->type == CONST_PTR_TO_DYNPTR) 9787 dynptr_arg_type |= MEM_RDONLY; 9788 9789 if (is_kfunc_arg_uninit(btf, &args[i])) 9790 dynptr_arg_type |= MEM_UNINIT; 9791 9792 if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) 9793 dynptr_arg_type |= DYNPTR_TYPE_SKB; 9794 else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) 9795 dynptr_arg_type |= DYNPTR_TYPE_XDP; 9796 9797 ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type); 9798 if (ret < 0) 9799 return ret; 9800 9801 if (!(dynptr_arg_type & MEM_UNINIT)) { 9802 int id = dynptr_id(env, reg); 9803 9804 if (id < 0) { 9805 verbose(env, "verifier internal error: failed to obtain dynptr id\n"); 9806 return id; 9807 } 9808 meta->initialized_dynptr.id = id; 9809 meta->initialized_dynptr.type = dynptr_get_type(env, reg); 9810 } 9811 9812 break; 9813 } 9814 case KF_ARG_PTR_TO_LIST_HEAD: 9815 if (reg->type != PTR_TO_MAP_VALUE && 9816 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9817 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9818 return -EINVAL; 9819 } 9820 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9821 verbose(env, "allocated object must be referenced\n"); 9822 return -EINVAL; 9823 } 9824 ret = process_kf_arg_ptr_to_list_head(env, reg, regno, meta); 9825 if (ret < 0) 9826 return ret; 9827 break; 9828 case KF_ARG_PTR_TO_RB_ROOT: 9829 if (reg->type != PTR_TO_MAP_VALUE && 9830 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9831 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9832 return -EINVAL; 9833 } 9834 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9835 verbose(env, "allocated object must be referenced\n"); 9836 return -EINVAL; 9837 } 9838 ret = process_kf_arg_ptr_to_rbtree_root(env, reg, regno, meta); 9839 if (ret < 0) 9840 return ret; 9841 break; 9842 case KF_ARG_PTR_TO_LIST_NODE: 9843 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9844 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9845 return -EINVAL; 9846 } 9847 if (!reg->ref_obj_id) { 9848 verbose(env, "allocated object must be referenced\n"); 9849 return -EINVAL; 9850 } 9851 ret = process_kf_arg_ptr_to_list_node(env, reg, regno, meta); 9852 if (ret < 0) 9853 return ret; 9854 break; 9855 case KF_ARG_PTR_TO_RB_NODE: 9856 if (meta->func_id == special_kfunc_list[KF_bpf_rbtree_remove]) { 9857 if (!type_is_non_owning_ref(reg->type) || reg->ref_obj_id) { 9858 verbose(env, "rbtree_remove node input must be non-owning ref\n"); 9859 return -EINVAL; 9860 } 9861 if (in_rbtree_lock_required_cb(env)) { 9862 verbose(env, "rbtree_remove not allowed in rbtree cb\n"); 9863 return -EINVAL; 9864 } 9865 } else { 9866 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9867 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9868 return -EINVAL; 9869 } 9870 if (!reg->ref_obj_id) { 9871 verbose(env, "allocated object must be referenced\n"); 9872 return -EINVAL; 9873 } 9874 } 9875 9876 ret = process_kf_arg_ptr_to_rbtree_node(env, reg, regno, meta); 9877 if (ret < 0) 9878 return ret; 9879 break; 9880 case KF_ARG_PTR_TO_BTF_ID: 9881 /* Only base_type is checked, further checks are done here */ 9882 if ((base_type(reg->type) != PTR_TO_BTF_ID || 9883 (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) && 9884 !reg2btf_ids[base_type(reg->type)]) { 9885 verbose(env, "arg#%d is %s ", i, reg_type_str(env, reg->type)); 9886 verbose(env, "expected %s or socket\n", 9887 reg_type_str(env, base_type(reg->type) | 9888 (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS))); 9889 return -EINVAL; 9890 } 9891 ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i); 9892 if (ret < 0) 9893 return ret; 9894 break; 9895 case KF_ARG_PTR_TO_MEM: 9896 resolve_ret = btf_resolve_size(btf, ref_t, &type_size); 9897 if (IS_ERR(resolve_ret)) { 9898 verbose(env, "arg#%d reference type('%s %s') size cannot be determined: %ld\n", 9899 i, btf_type_str(ref_t), ref_tname, PTR_ERR(resolve_ret)); 9900 return -EINVAL; 9901 } 9902 ret = check_mem_reg(env, reg, regno, type_size); 9903 if (ret < 0) 9904 return ret; 9905 break; 9906 case KF_ARG_PTR_TO_MEM_SIZE: 9907 struct bpf_reg_state *size_reg = ®s[regno + 1]; > 9908 const struct btf_param *size_arg = &args[i + 1]; 9909 9910 ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); 9911 if (ret < 0) { 9912 verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); 9913 return ret; 9914 } 9915 9916 if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { 9917 if (meta->arg_constant.found) { 9918 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9919 return -EFAULT; 9920 } 9921 if (!tnum_is_const(size_reg->var_off)) { 9922 verbose(env, "R%d must be a known constant\n", regno + 1); 9923 return -EINVAL; 9924 } 9925 meta->arg_constant.found = true; 9926 meta->arg_constant.value = size_reg->var_off.value; 9927 } 9928 9929 /* Skip next '__sz' or '__szk' argument */ 9930 i++; 9931 break; 9932 case KF_ARG_PTR_TO_CALLBACK: 9933 meta->subprogno = reg->subprogno; 9934 break; 9935 } 9936 } 9937 9938 if (is_kfunc_release(meta) && !meta->release_regno) { 9939 verbose(env, "release kernel function %s expects refcounted PTR_TO_BTF_ID\n", 9940 func_name); 9941 return -EINVAL; 9942 } 9943 9944 return 0; 9945 } 9946
Hi Joanne, Thank you for the patch! Yet something to improve: [auto build test ERROR on bpf-next/master] url: https://github.com/intel-lab-lkp/linux/commits/Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master patch link: https://lore.kernel.org/r/20230226085120.3907863-10-joannelkoong%40gmail.com patch subject: [PATCH v12 bpf-next 09/10] bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr config: hexagon-randconfig-r026-20230226 (https://download.01.org/0day-ci/archive/20230226/202302261821.69VtQP9g-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project db89896bbbd2251fff457699635acbbedeead27f) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/bc5a61c43c72539ef11e6435a168bf240a186ac1 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Joanne-Koong/bpf-Support-sk_buff-and-xdp_buff-as-valid-kfunc-arg-types/20230226-165406 git checkout bc5a61c43c72539ef11e6435a168bf240a186ac1 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202302261821.69VtQP9g-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __raw_readb(PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu' #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) ^ In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu' #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) ^ In file included from kernel/bpf/verifier.c:7: In file included from include/linux/bpf-cgroup.h:5: In file included from include/linux/bpf.h:31: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/hexagon/include/asm/io.h:334: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writeb(value, PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ kernel/bpf/verifier.c:6253:5: warning: no previous prototype for function 'process_dynptr_func' [-Wmissing-prototypes] int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ kernel/bpf/verifier.c:6253:1: note: declare 'static' if the function is not intended to be used outside of this translation unit int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, ^ static >> kernel/bpf/verifier.c:9907:4: error: expected expression struct bpf_reg_state *size_reg = ®s[regno + 1]; ^ >> kernel/bpf/verifier.c:9910:40: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9916:57: error: use of undeclared identifier 'size_reg'; did you mean 'size_arg'? if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { ^~~~~~~~ size_arg kernel/bpf/verifier.c:9908:28: note: 'size_arg' declared here const struct btf_param *size_arg = &args[i + 1]; ^ kernel/bpf/verifier.c:9921:24: error: use of undeclared identifier 'size_reg' if (!tnum_is_const(size_reg->var_off)) { ^ kernel/bpf/verifier.c:9926:32: error: use of undeclared identifier 'size_reg' meta->arg_constant.value = size_reg->var_off.value; ^ kernel/bpf/verifier.c:9908:28: warning: mixing declarations and code is incompatible with standards before C99 [-Wdeclaration-after-statement] const struct btf_param *size_arg = &args[i + 1]; ^ 8 warnings and 5 errors generated. vim +9907 kernel/bpf/verifier.c 9584 9585 static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta, 9586 int insn_idx) 9587 { 9588 const char *func_name = meta->func_name, *ref_tname; 9589 const struct btf *btf = meta->btf; 9590 const struct btf_param *args; 9591 u32 i, nargs; 9592 int ret; 9593 9594 args = (const struct btf_param *)(meta->func_proto + 1); 9595 nargs = btf_type_vlen(meta->func_proto); 9596 if (nargs > MAX_BPF_FUNC_REG_ARGS) { 9597 verbose(env, "Function %s has %d > %d args\n", func_name, nargs, 9598 MAX_BPF_FUNC_REG_ARGS); 9599 return -EINVAL; 9600 } 9601 9602 /* Check that BTF function arguments match actual types that the 9603 * verifier sees. 9604 */ 9605 for (i = 0; i < nargs; i++) { 9606 struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[i + 1]; 9607 const struct btf_type *t, *ref_t, *resolve_ret; 9608 enum bpf_arg_type arg_type = ARG_DONTCARE; 9609 u32 regno = i + 1, ref_id, type_size; 9610 bool is_ret_buf_sz = false; 9611 int kf_arg_type; 9612 9613 t = btf_type_skip_modifiers(btf, args[i].type, NULL); 9614 9615 if (is_kfunc_arg_ignore(btf, &args[i])) 9616 continue; 9617 9618 if (btf_type_is_scalar(t)) { 9619 if (reg->type != SCALAR_VALUE) { 9620 verbose(env, "R%d is not a scalar\n", regno); 9621 return -EINVAL; 9622 } 9623 9624 if (is_kfunc_arg_constant(meta->btf, &args[i])) { 9625 if (meta->arg_constant.found) { 9626 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9627 return -EFAULT; 9628 } 9629 if (!tnum_is_const(reg->var_off)) { 9630 verbose(env, "R%d must be a known constant\n", regno); 9631 return -EINVAL; 9632 } 9633 ret = mark_chain_precision(env, regno); 9634 if (ret < 0) 9635 return ret; 9636 meta->arg_constant.found = true; 9637 meta->arg_constant.value = reg->var_off.value; 9638 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdonly_buf_size")) { 9639 meta->r0_rdonly = true; 9640 is_ret_buf_sz = true; 9641 } else if (is_kfunc_arg_scalar_with_name(btf, &args[i], "rdwr_buf_size")) { 9642 is_ret_buf_sz = true; 9643 } 9644 9645 if (is_ret_buf_sz) { 9646 if (meta->r0_size) { 9647 verbose(env, "2 or more rdonly/rdwr_buf_size parameters for kfunc"); 9648 return -EINVAL; 9649 } 9650 9651 if (!tnum_is_const(reg->var_off)) { 9652 verbose(env, "R%d is not a const\n", regno); 9653 return -EINVAL; 9654 } 9655 9656 meta->r0_size = reg->var_off.value; 9657 ret = mark_chain_precision(env, regno); 9658 if (ret) 9659 return ret; 9660 } 9661 continue; 9662 } 9663 9664 if (!btf_type_is_ptr(t)) { 9665 verbose(env, "Unrecognized arg#%d type %s\n", i, btf_type_str(t)); 9666 return -EINVAL; 9667 } 9668 9669 if (is_kfunc_trusted_args(meta) && 9670 (register_is_null(reg) || type_may_be_null(reg->type))) { 9671 verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i); 9672 return -EACCES; 9673 } 9674 9675 if (reg->ref_obj_id) { 9676 if (is_kfunc_release(meta) && meta->ref_obj_id) { 9677 verbose(env, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n", 9678 regno, reg->ref_obj_id, 9679 meta->ref_obj_id); 9680 return -EFAULT; 9681 } 9682 meta->ref_obj_id = reg->ref_obj_id; 9683 if (is_kfunc_release(meta)) 9684 meta->release_regno = regno; 9685 } 9686 9687 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id); 9688 ref_tname = btf_name_by_offset(btf, ref_t->name_off); 9689 9690 kf_arg_type = get_kfunc_ptr_arg_type(env, meta, t, ref_t, ref_tname, args, i, nargs); 9691 if (kf_arg_type < 0) 9692 return kf_arg_type; 9693 9694 switch (kf_arg_type) { 9695 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9696 case KF_ARG_PTR_TO_BTF_ID: 9697 if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta)) 9698 break; 9699 9700 if (!is_trusted_reg(reg)) { 9701 if (!is_kfunc_rcu(meta)) { 9702 verbose(env, "R%d must be referenced or trusted\n", regno); 9703 return -EINVAL; 9704 } 9705 if (!is_rcu_reg(reg)) { 9706 verbose(env, "R%d must be a rcu pointer\n", regno); 9707 return -EINVAL; 9708 } 9709 } 9710 9711 fallthrough; 9712 case KF_ARG_PTR_TO_CTX: 9713 /* Trusted arguments have the same offset checks as release arguments */ 9714 arg_type |= OBJ_RELEASE; 9715 break; 9716 case KF_ARG_PTR_TO_KPTR: 9717 case KF_ARG_PTR_TO_DYNPTR: 9718 case KF_ARG_PTR_TO_LIST_HEAD: 9719 case KF_ARG_PTR_TO_LIST_NODE: 9720 case KF_ARG_PTR_TO_RB_ROOT: 9721 case KF_ARG_PTR_TO_RB_NODE: 9722 case KF_ARG_PTR_TO_MEM: 9723 case KF_ARG_PTR_TO_MEM_SIZE: 9724 case KF_ARG_PTR_TO_CALLBACK: 9725 /* Trusted by default */ 9726 break; 9727 default: 9728 WARN_ON_ONCE(1); 9729 return -EFAULT; 9730 } 9731 9732 if (is_kfunc_release(meta) && reg->ref_obj_id) 9733 arg_type |= OBJ_RELEASE; 9734 ret = check_func_arg_reg_off(env, reg, regno, arg_type); 9735 if (ret < 0) 9736 return ret; 9737 9738 switch (kf_arg_type) { 9739 case KF_ARG_PTR_TO_CTX: 9740 if (reg->type != PTR_TO_CTX) { 9741 verbose(env, "arg#%d expected pointer to ctx, but got %s\n", i, btf_type_str(t)); 9742 return -EINVAL; 9743 } 9744 9745 if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { 9746 ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog)); 9747 if (ret < 0) 9748 return -EINVAL; 9749 meta->ret_btf_id = ret; 9750 } 9751 break; 9752 case KF_ARG_PTR_TO_ALLOC_BTF_ID: 9753 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9754 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9755 return -EINVAL; 9756 } 9757 if (!reg->ref_obj_id) { 9758 verbose(env, "allocated object must be referenced\n"); 9759 return -EINVAL; 9760 } 9761 if (meta->btf == btf_vmlinux && 9762 meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { 9763 meta->arg_obj_drop.btf = reg->btf; 9764 meta->arg_obj_drop.btf_id = reg->btf_id; 9765 } 9766 break; 9767 case KF_ARG_PTR_TO_KPTR: 9768 if (reg->type != PTR_TO_MAP_VALUE) { 9769 verbose(env, "arg#0 expected pointer to map value\n"); 9770 return -EINVAL; 9771 } 9772 ret = process_kf_arg_ptr_to_kptr(env, reg, ref_t, ref_tname, meta, i); 9773 if (ret < 0) 9774 return ret; 9775 break; 9776 case KF_ARG_PTR_TO_DYNPTR: 9777 { 9778 enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR; 9779 9780 if (reg->type != PTR_TO_STACK && 9781 reg->type != CONST_PTR_TO_DYNPTR) { 9782 verbose(env, "arg#%d expected pointer to stack or dynptr_ptr\n", i); 9783 return -EINVAL; 9784 } 9785 9786 if (reg->type == CONST_PTR_TO_DYNPTR) 9787 dynptr_arg_type |= MEM_RDONLY; 9788 9789 if (is_kfunc_arg_uninit(btf, &args[i])) 9790 dynptr_arg_type |= MEM_UNINIT; 9791 9792 if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) 9793 dynptr_arg_type |= DYNPTR_TYPE_SKB; 9794 else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) 9795 dynptr_arg_type |= DYNPTR_TYPE_XDP; 9796 9797 ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type); 9798 if (ret < 0) 9799 return ret; 9800 9801 if (!(dynptr_arg_type & MEM_UNINIT)) { 9802 int id = dynptr_id(env, reg); 9803 9804 if (id < 0) { 9805 verbose(env, "verifier internal error: failed to obtain dynptr id\n"); 9806 return id; 9807 } 9808 meta->initialized_dynptr.id = id; 9809 meta->initialized_dynptr.type = dynptr_get_type(env, reg); 9810 } 9811 9812 break; 9813 } 9814 case KF_ARG_PTR_TO_LIST_HEAD: 9815 if (reg->type != PTR_TO_MAP_VALUE && 9816 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9817 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9818 return -EINVAL; 9819 } 9820 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9821 verbose(env, "allocated object must be referenced\n"); 9822 return -EINVAL; 9823 } 9824 ret = process_kf_arg_ptr_to_list_head(env, reg, regno, meta); 9825 if (ret < 0) 9826 return ret; 9827 break; 9828 case KF_ARG_PTR_TO_RB_ROOT: 9829 if (reg->type != PTR_TO_MAP_VALUE && 9830 reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9831 verbose(env, "arg#%d expected pointer to map value or allocated object\n", i); 9832 return -EINVAL; 9833 } 9834 if (reg->type == (PTR_TO_BTF_ID | MEM_ALLOC) && !reg->ref_obj_id) { 9835 verbose(env, "allocated object must be referenced\n"); 9836 return -EINVAL; 9837 } 9838 ret = process_kf_arg_ptr_to_rbtree_root(env, reg, regno, meta); 9839 if (ret < 0) 9840 return ret; 9841 break; 9842 case KF_ARG_PTR_TO_LIST_NODE: 9843 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9844 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9845 return -EINVAL; 9846 } 9847 if (!reg->ref_obj_id) { 9848 verbose(env, "allocated object must be referenced\n"); 9849 return -EINVAL; 9850 } 9851 ret = process_kf_arg_ptr_to_list_node(env, reg, regno, meta); 9852 if (ret < 0) 9853 return ret; 9854 break; 9855 case KF_ARG_PTR_TO_RB_NODE: 9856 if (meta->func_id == special_kfunc_list[KF_bpf_rbtree_remove]) { 9857 if (!type_is_non_owning_ref(reg->type) || reg->ref_obj_id) { 9858 verbose(env, "rbtree_remove node input must be non-owning ref\n"); 9859 return -EINVAL; 9860 } 9861 if (in_rbtree_lock_required_cb(env)) { 9862 verbose(env, "rbtree_remove not allowed in rbtree cb\n"); 9863 return -EINVAL; 9864 } 9865 } else { 9866 if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { 9867 verbose(env, "arg#%d expected pointer to allocated object\n", i); 9868 return -EINVAL; 9869 } 9870 if (!reg->ref_obj_id) { 9871 verbose(env, "allocated object must be referenced\n"); 9872 return -EINVAL; 9873 } 9874 } 9875 9876 ret = process_kf_arg_ptr_to_rbtree_node(env, reg, regno, meta); 9877 if (ret < 0) 9878 return ret; 9879 break; 9880 case KF_ARG_PTR_TO_BTF_ID: 9881 /* Only base_type is checked, further checks are done here */ 9882 if ((base_type(reg->type) != PTR_TO_BTF_ID || 9883 (bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) && 9884 !reg2btf_ids[base_type(reg->type)]) { 9885 verbose(env, "arg#%d is %s ", i, reg_type_str(env, reg->type)); 9886 verbose(env, "expected %s or socket\n", 9887 reg_type_str(env, base_type(reg->type) | 9888 (type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS))); 9889 return -EINVAL; 9890 } 9891 ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i); 9892 if (ret < 0) 9893 return ret; 9894 break; 9895 case KF_ARG_PTR_TO_MEM: 9896 resolve_ret = btf_resolve_size(btf, ref_t, &type_size); 9897 if (IS_ERR(resolve_ret)) { 9898 verbose(env, "arg#%d reference type('%s %s') size cannot be determined: %ld\n", 9899 i, btf_type_str(ref_t), ref_tname, PTR_ERR(resolve_ret)); 9900 return -EINVAL; 9901 } 9902 ret = check_mem_reg(env, reg, regno, type_size); 9903 if (ret < 0) 9904 return ret; 9905 break; 9906 case KF_ARG_PTR_TO_MEM_SIZE: > 9907 struct bpf_reg_state *size_reg = ®s[regno + 1]; 9908 const struct btf_param *size_arg = &args[i + 1]; 9909 > 9910 ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); 9911 if (ret < 0) { 9912 verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); 9913 return ret; 9914 } 9915 9916 if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { 9917 if (meta->arg_constant.found) { 9918 verbose(env, "verifier internal error: only one constant argument permitted\n"); 9919 return -EFAULT; 9920 } 9921 if (!tnum_is_const(size_reg->var_off)) { 9922 verbose(env, "R%d must be a known constant\n", regno + 1); 9923 return -EINVAL; 9924 } 9925 meta->arg_constant.found = true; 9926 meta->arg_constant.value = size_reg->var_off.value; 9927 } 9928 9929 /* Skip next '__sz' or '__szk' argument */ 9930 i++; 9931 break; 9932 case KF_ARG_PTR_TO_CALLBACK: 9933 meta->subprogno = reg->subprogno; 9934 break; 9935 } 9936 } 9937 9938 if (is_kfunc_release(meta) && !meta->release_regno) { 9939 verbose(env, "release kernel function %s expects refcounted PTR_TO_BTF_ID\n", 9940 func_name); 9941 return -EINVAL; 9942 } 9943 9944 return 0; 9945 } 9946
diff --git a/include/linux/filter.h b/include/linux/filter.h index 3f6992261ec5..efa5d4a1677e 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1548,6 +1548,9 @@ int __bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags); int __bpf_xdp_load_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len); int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, void *buf, u32 len); +void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len); +void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, + void *buf, unsigned long len, bool flush); #else /* CONFIG_NET */ static inline int __bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) @@ -1572,6 +1575,17 @@ static inline int __bpf_xdp_store_bytes(struct xdp_buff *xdp, u32 offset, { return -EOPNOTSUPP; } + +static inline void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len) +{ + return NULL; +} + +static inline void *bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, void *buf, + unsigned long len, bool flush) +{ + return NULL; +} #endif /* CONFIG_NET */ #endif /* __LINUX_FILTER_H__ */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index faa304c926cf..c9699304aed2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5329,6 +5329,11 @@ union bpf_attr { * *flags* must be 0 except for skb-type dynptrs. * * For skb-type dynptrs: + * * All data slices of the dynptr are automatically + * invalidated after **bpf_dynptr_write**\ (). This is + * because writing may pull the skb and change the + * underlying packet buffer. + * * * For *flags*, please see the flags accepted by * **bpf_skb_store_bytes**\ (). * Return diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 78fad0e84ca4..33055e4c9e2e 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2194,6 +2194,142 @@ __bpf_kfunc struct task_struct *bpf_task_from_pid(s32 pid) return p; } +/** + * bpf_dynptr_slice - Obtain a read-only pointer to the dynptr data. + * + * For non-skb and non-xdp type dynptrs, there is no difference between + * bpf_dynptr_slice and bpf_dynptr_data. + * + * If the intention is to write to the data slice, please use + * bpf_dynptr_slice_rdwr. + * + * The user must check that the returned pointer is not null before using it. + * + * Please note that in the case of skb and xdp dynptrs, bpf_dynptr_slice + * does not change the underlying packet data pointers, so a call to + * bpf_dynptr_slice will not invalidate any ctx->data/data_end pointers in + * the bpf program. + * + * @ptr: The dynptr whose data slice to retrieve + * @offset: Offset into the dynptr + * @buffer: User-provided buffer to copy contents into + * @buffer__szk: Size (in bytes) of the buffer. This is the length of the + * requested slice. This must be a constant. + * + * @returns: NULL if the call failed (eg invalid dynptr), pointer to a read-only + * data slice (can be either direct pointer to the data or a pointer to the user + * provided buffer, with its contents containing the data, if unable to obtain + * direct pointer) + */ +__bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset, + void *buffer, u32 buffer__szk) +{ + enum bpf_dynptr_type type; + u32 len = buffer__szk; + int err; + + if (!ptr->data) + return 0; + + err = bpf_dynptr_check_off_len(ptr, offset, len); + if (err) + return 0; + + type = bpf_dynptr_get_type(ptr); + + switch (type) { + case BPF_DYNPTR_TYPE_LOCAL: + case BPF_DYNPTR_TYPE_RINGBUF: + return ptr->data + ptr->offset + offset; + case BPF_DYNPTR_TYPE_SKB: + return skb_header_pointer(ptr->data, ptr->offset + offset, len, buffer); + case BPF_DYNPTR_TYPE_XDP: + { + void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len); + if (xdp_ptr) + return xdp_ptr; + + bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer, len, false); + return buffer; + } + default: + WARN_ONCE(true, "unknown dynptr type %d\n", type); + return 0; + } +} + +/** + * bpf_dynptr_slice_rdwr - Obtain a writable pointer to the dynptr data. + * + * For non-skb and non-xdp type dynptrs, there is no difference between + * bpf_dynptr_slice and bpf_dynptr_data. + * + * The returned pointer is writable and may point to either directly the dynptr + * data at the requested offset or to the buffer if unable to obtain a direct + * data pointer to (example: the requested slice is to the paged area of an skb + * packet). In the case where the returned pointer is to the buffer, the user + * is responsible for persisting writes through calling bpf_dynptr_write(). This + * usually looks something like this pattern: + * + * struct eth_hdr *eth = bpf_dynptr_slice_rdwr(&dynptr, 0, buffer, sizeof(buffer)); + * if (!eth) + * return TC_ACT_SHOT; + * + * // mutate eth header // + * + * if (eth == buffer) + * bpf_dynptr_write(&ptr, 0, buffer, sizeof(buffer), 0); + * + * Please note that, as in the example above, the user must check that the + * returned pointer is not null before using it. + * + * Please also note that in the case of skb and xdp dynptrs, bpf_dynptr_slice_rdwr + * does not change the underlying packet data pointers, so a call to + * bpf_dynptr_slice_rdwr will not invalidate any ctx->data/data_end pointers in + * the bpf program. + * + * @ptr: The dynptr whose data slice to retrieve + * @offset: Offset into the dynptr + * @buffer: User-provided buffer to copy contents into + * @buffer__szk: Size (in bytes) of the buffer. This is the length of the + * requested slice. This must be a constant. + * + * @returns: NULL if the call failed (eg invalid dynptr), pointer to a + * data slice (can be either direct pointer to the data or a pointer to the user + * provided buffer, with its contents containing the data, if unable to obtain + * direct pointer) + */ +__bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 offset, + void *buffer, u32 buffer__szk) +{ + if (!ptr->data || bpf_dynptr_is_rdonly(ptr)) + return 0; + + /* bpf_dynptr_slice_rdwr is the same logic as bpf_dynptr_slice. + * + * For skb-type dynptrs, it is safe to write into the returned pointer + * if the bpf program allows skb data writes. There are two possiblities + * that may occur when calling bpf_dynptr_slice_rdwr: + * + * 1) The requested slice is in the head of the skb. In this case, the + * returned pointer is directly to skb data, and if the skb is cloned, the + * verifier will have uncloned it (see bpf_unclone_prologue()) already. + * The pointer can be directly written into. + * + * 2) Some portion of the requested slice is in the paged buffer area. + * In this case, the requested data will be copied out into the buffer + * and the returned pointer will be a pointer to the buffer. The skb + * will not be pulled. To persist the write, the user will need to call + * bpf_dynptr_write(), which will pull the skb and commit the write. + * + * Similarly for xdp programs, if the requested slice is not across xdp + * fragments, then a direct pointer will be returned, otherwise the data + * will be copied out into the buffer and the user will need to call + * bpf_dynptr_write() to commit changes. + */ + return bpf_dynptr_slice(ptr, offset, buffer, buffer__szk); +} + __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) { return obj; @@ -2263,6 +2399,8 @@ BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx) BTF_ID_FLAGS(func, bpf_rdonly_cast) BTF_ID_FLAGS(func, bpf_rcu_read_lock) BTF_ID_FLAGS(func, bpf_rcu_read_unlock) +BTF_ID_FLAGS(func, bpf_dynptr_slice, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_dynptr_slice_rdwr, KF_RET_NULL) BTF_SET8_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index cbb8c0178372..a9e806545c0f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -759,6 +759,22 @@ static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type) } } +static enum bpf_type_flag get_dynptr_type_flag(enum bpf_dynptr_type type) +{ + switch (type) { + case BPF_DYNPTR_TYPE_LOCAL: + return DYNPTR_TYPE_LOCAL; + case BPF_DYNPTR_TYPE_RINGBUF: + return DYNPTR_TYPE_RINGBUF; + case BPF_DYNPTR_TYPE_SKB: + return DYNPTR_TYPE_SKB; + case BPF_DYNPTR_TYPE_XDP: + return DYNPTR_TYPE_XDP; + default: + return 0; + } +} + static bool dynptr_type_refcounted(enum bpf_dynptr_type type) { return type == BPF_DYNPTR_TYPE_RINGBUF; @@ -1681,6 +1697,12 @@ static bool reg_is_pkt_pointer_any(const struct bpf_reg_state *reg) reg->type == PTR_TO_PACKET_END; } +static bool reg_is_dynptr_slice_pkt(const struct bpf_reg_state *reg) +{ + return base_type(reg->type) == PTR_TO_MEM && + (reg->type & DYNPTR_TYPE_SKB || reg->type & DYNPTR_TYPE_XDP); +} + /* Unmodified PTR_TO_PACKET[_META,_END] register from ctx access. */ static bool reg_is_init_pkt_pointer(const struct bpf_reg_state *reg, enum bpf_reg_type which) @@ -7429,6 +7451,9 @@ static int check_func_proto(const struct bpf_func_proto *fn, int func_id) /* Packet data might have moved, any old PTR_TO_PACKET[_META,_END] * are now invalid, so turn them into unknown SCALAR_VALUE. + * + * This also applies to dynptr slices belonging to skb and xdp dynptrs, + * since these slices point to packet data. */ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) { @@ -7436,7 +7461,7 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env) struct bpf_reg_state *reg; bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({ - if (reg_is_pkt_pointer_any(reg)) + if (reg_is_pkt_pointer_any(reg) || reg_is_dynptr_slice_pkt(reg)) mark_reg_invalid(env, reg); })); } @@ -8688,6 +8713,11 @@ struct bpf_kfunc_call_arg_meta { struct { struct btf_field *field; } arg_rbtree_root; + struct { + enum bpf_dynptr_type type; + u32 id; + } initialized_dynptr; + u64 mem_size; }; static bool is_kfunc_acquire(struct bpf_kfunc_call_arg_meta *meta) @@ -8761,6 +8791,19 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf, return __kfunc_param_match_suffix(btf, arg, "__sz"); } +static bool is_kfunc_arg_const_mem_size(const struct btf *btf, + const struct btf_param *arg, + const struct bpf_reg_state *reg) +{ + const struct btf_type *t; + + t = btf_type_skip_modifiers(btf, arg->type, NULL); + if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE) + return false; + + return __kfunc_param_match_suffix(btf, arg, "__szk"); +} + static bool is_kfunc_arg_constant(const struct btf *btf, const struct btf_param *arg) { return __kfunc_param_match_suffix(btf, arg, "__k"); @@ -8949,6 +8992,8 @@ enum special_kfunc_type { KF_bpf_rbtree_first, KF_bpf_dynptr_from_skb, KF_bpf_dynptr_from_xdp, + KF_bpf_dynptr_slice, + KF_bpf_dynptr_slice_rdwr, }; BTF_SET_START(special_kfunc_set) @@ -8965,6 +9010,8 @@ BTF_ID(func, bpf_rbtree_add) BTF_ID(func, bpf_rbtree_first) BTF_ID(func, bpf_dynptr_from_skb) BTF_ID(func, bpf_dynptr_from_xdp) +BTF_ID(func, bpf_dynptr_slice) +BTF_ID(func, bpf_dynptr_slice_rdwr) BTF_SET_END(special_kfunc_set) BTF_ID_LIST(special_kfunc_list) @@ -8983,6 +9030,8 @@ BTF_ID(func, bpf_rbtree_add) BTF_ID(func, bpf_rbtree_first) BTF_ID(func, bpf_dynptr_from_skb) BTF_ID(func, bpf_dynptr_from_xdp) +BTF_ID(func, bpf_dynptr_slice) +BTF_ID(func, bpf_dynptr_slice_rdwr) static bool is_kfunc_bpf_rcu_read_lock(struct bpf_kfunc_call_arg_meta *meta) { @@ -9062,7 +9111,10 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, if (is_kfunc_arg_callback(env, meta->btf, &args[argno])) return KF_ARG_PTR_TO_CALLBACK; - if (argno + 1 < nargs && is_kfunc_arg_mem_size(meta->btf, &args[argno + 1], ®s[regno + 1])) + + if (argno + 1 < nargs && + (is_kfunc_arg_mem_size(meta->btf, &args[argno + 1], ®s[regno + 1]) || + is_kfunc_arg_const_mem_size(meta->btf, &args[argno + 1], ®s[regno + 1]))) arg_mem_size = true; /* This is the catch all argument type of register types supported by @@ -9745,6 +9797,18 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type); if (ret < 0) return ret; + + if (!(dynptr_arg_type & MEM_UNINIT)) { + int id = dynptr_id(env, reg); + + if (id < 0) { + verbose(env, "verifier internal error: failed to obtain dynptr id\n"); + return id; + } + meta->initialized_dynptr.id = id; + meta->initialized_dynptr.type = dynptr_get_type(env, reg); + } + break; } case KF_ARG_PTR_TO_LIST_HEAD: @@ -9840,12 +9904,29 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ return ret; break; case KF_ARG_PTR_TO_MEM_SIZE: - ret = check_kfunc_mem_size_reg(env, ®s[regno + 1], regno + 1); + struct bpf_reg_state *size_reg = ®s[regno + 1]; + const struct btf_param *size_arg = &args[i + 1]; + + ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); if (ret < 0) { verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); return ret; } - /* Skip next '__sz' argument */ + + if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { + if (meta->arg_constant.found) { + verbose(env, "verifier internal error: only one constant argument permitted\n"); + return -EFAULT; + } + if (!tnum_is_const(size_reg->var_off)) { + verbose(env, "R%d must be a known constant\n", regno + 1); + return -EINVAL; + } + meta->arg_constant.found = true; + meta->arg_constant.value = size_reg->var_off.value; + } + + /* Skip next '__sz' or '__szk' argument */ i++; break; case KF_ARG_PTR_TO_CALLBACK: @@ -10082,6 +10163,42 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_UNTRUSTED; regs[BPF_REG_0].btf = desc_btf; regs[BPF_REG_0].btf_id = meta.arg_constant.value; + } else if (meta.func_id == special_kfunc_list[KF_bpf_dynptr_slice] || + meta.func_id == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) { + enum bpf_type_flag type_flag = get_dynptr_type_flag(meta.initialized_dynptr.type); + + mark_reg_known_zero(env, regs, BPF_REG_0); + + if (!meta.arg_constant.found) { + verbose(env, "verifier internal error: bpf_dynptr_slice(_rdwr) no constant size\n"); + return -EFAULT; + } + + regs[BPF_REG_0].mem_size = meta.arg_constant.value; + + /* PTR_MAYBE_NULL will be added when is_kfunc_ret_null is checked */ + regs[BPF_REG_0].type = PTR_TO_MEM | type_flag; + + if (meta.func_id == special_kfunc_list[KF_bpf_dynptr_slice]) { + regs[BPF_REG_0].type |= MEM_RDONLY; + } else { + /* this will set env->seen_direct_write to true */ + if (!may_access_direct_pkt_data(env, NULL, BPF_WRITE)) { + verbose(env, "the prog does not allow writes to packet data\n"); + return -EINVAL; + } + } + + if (!meta.initialized_dynptr.id) { + verbose(env, "verifier internal error: no dynptr id\n"); + return -EFAULT; + } + regs[BPF_REG_0].dynptr_id = meta.initialized_dynptr.id; + + /* we don't need to set BPF_REG_0's ref obj id + * because packet slices are not refcounted (see + * dynptr_type_refcounted) + */ } else { verbose(env, "kernel function %s unhandled dynamic return type\n", meta.func_name); diff --git a/net/core/filter.c b/net/core/filter.c index c692046fa7f6..8f3124e06133 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3894,8 +3894,8 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = { .arg2_type = ARG_ANYTHING, }; -static void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, - void *buf, unsigned long len, bool flush) +void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, + void *buf, unsigned long len, bool flush) { unsigned long ptr_len, ptr_off = 0; skb_frag_t *next_frag, *end_frag; @@ -3941,7 +3941,7 @@ static void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, } } -static void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len) +void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len) { struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); u32 size = xdp->data_end - xdp->data; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index faa304c926cf..c9699304aed2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5329,6 +5329,11 @@ union bpf_attr { * *flags* must be 0 except for skb-type dynptrs. * * For skb-type dynptrs: + * * All data slices of the dynptr are automatically + * invalidated after **bpf_dynptr_write**\ (). This is + * because writing may pull the skb and change the + * underlying packet buffer. + * * * For *flags*, please see the flags accepted by * **bpf_skb_store_bytes**\ (). * Return
Two new kfuncs are added, bpf_dynptr_slice and bpf_dynptr_slice_rdwr. The user must pass in a buffer to store the contents of the data slice if a direct pointer to the data cannot be obtained. For skb and xdp type dynptrs, these two APIs are the only way to obtain a data slice. However, for other types of dynptrs, there is no difference between bpf_dynptr_slice(_rdwr) and bpf_dynptr_data. For skb type dynptrs, the data is copied into the user provided buffer if any of the data is not in the linear portion of the skb. For xdp type dynptrs, the data is copied into the user provided buffer if the data is between xdp frags. If the skb is cloned and a call to bpf_dynptr_data_rdwr is made, then the skb will be uncloned (see bpf_unclone_prologue()). Please note that any bpf_dynptr_write() automatically invalidates any prior data slices of the skb dynptr. This is because the skb may be cloned or may need to pull its paged buffer into the head. As such, any bpf_dynptr_write() will automatically have its prior data slices invalidated, even if the write is to data in the skb head of an uncloned skb. Please note as well that any other helper calls that change the underlying packet buffer (eg bpf_skb_pull_data()) invalidates any data slices of the skb dynptr as well, for the same reasons. Signed-off-by: Joanne Koong <joannelkoong@gmail.com> --- include/linux/filter.h | 14 ++++ include/uapi/linux/bpf.h | 5 ++ kernel/bpf/helpers.c | 138 +++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 125 ++++++++++++++++++++++++++++- net/core/filter.c | 6 +- tools/include/uapi/linux/bpf.h | 5 ++ 6 files changed, 286 insertions(+), 7 deletions(-)