Message ID | 20210208104747.573461-3-liuhangbin@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | BPF |
Headers | show |
Series | xdp: add a new helper for dev map multicast support | expand |
Context | Check | Description |
---|---|---|
netdev/cover_letter | success | Link |
netdev/fixes_present | success | Link |
netdev/patch_count | success | Link |
netdev/tree_selection | success | Clearly marked for bpf-next |
netdev/subject_prefix | success | Link |
netdev/cc_maintainers | warning | 5 maintainers not CCed: yhs@fb.com kafai@fb.com songliubraving@fb.com kpsingh@kernel.org andrii@kernel.org |
netdev/source_inline | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Link |
netdev/module_param | success | Was 0 now: 0 |
netdev/build_32bit | success | Errors and warnings before: 12175 this patch: 12175 |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/verify_fixes | success | Link |
netdev/checkpatch | warning | WARNING: line length of 95 exceeds 80 columns |
netdev/build_allmodconfig_warn | success | Errors and warnings before: 12823 this patch: 12823 |
netdev/header_inline | success | Link |
netdev/stable | success | Stable not CCed |
On 2/8/21 11:47 AM, Hangbin Liu wrote: > Add a new bpf argument type ARG_CONST_MAP_PTR_OR_NULL which could be > used when we want to allow NULL pointer for map parameter. The bpf helper > need to take care and check if the map is NULL when use this type. > > Acked-by: Toke Høiland-Jørgensen <toke@redhat.com> > Acked-by: John Fastabend <john.fastabend@gmail.com> > Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> [...] > @@ -4259,9 +4261,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, > meta->ref_obj_id = reg->ref_obj_id; > } > > - if (arg_type == ARG_CONST_MAP_PTR) { > - /* bpf_map_xxx(map_ptr) call: remember that map_ptr */ > - meta->map_ptr = reg->map_ptr; > + if (arg_type == ARG_CONST_MAP_PTR || > + arg_type == ARG_CONST_MAP_PTR_OR_NULL) { > + meta->map_ptr = register_is_null(reg) ? NULL : reg->map_ptr; Sorry, but after re-reading this is unfortunately still broken :( Looking at your helper func proto: +static const struct bpf_func_proto bpf_xdp_redirect_map_multi_proto = { + .func = bpf_xdp_redirect_map_multi, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_CONST_MAP_PTR, + .arg2_type = ARG_CONST_MAP_PTR_OR_NULL, + .arg3_type = ARG_ANYTHING, +}; So in check_helper_call() first meta->map_ptr is set to arg1 map, then when checking arg2 map it can either be const NULL or a valid map ptr, but then later on in check_map_func_compatibility() we only end up checking compatibility of the /2nd/ map (e.g. on !meta->map_ptr we just return 0). This means, we can pass whatever map type as arg1 map and it will pass the verifier just fine.
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 321966fc35db..b0777c8c03fd 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -296,6 +296,7 @@ enum bpf_arg_type { ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */ ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */ ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */ + ARG_CONST_MAP_PTR_OR_NULL, /* const argument used as pointer to bpf_map or NULL */ __BPF_ARG_TYPE_MAX, }; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 15694246f854..adc7a2b02a60 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -451,7 +451,8 @@ static bool arg_type_may_be_null(enum bpf_arg_type type) type == ARG_PTR_TO_MEM_OR_NULL || type == ARG_PTR_TO_CTX_OR_NULL || type == ARG_PTR_TO_SOCKET_OR_NULL || - type == ARG_PTR_TO_ALLOC_MEM_OR_NULL; + type == ARG_PTR_TO_ALLOC_MEM_OR_NULL || + type == ARG_CONST_MAP_PTR_OR_NULL; } /* Determine whether the function releases some resources allocated by another @@ -4114,6 +4115,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_CONST_SIZE_OR_ZERO] = &scalar_types, [ARG_CONST_ALLOC_SIZE_OR_ZERO] = &scalar_types, [ARG_CONST_MAP_PTR] = &const_map_ptr_types, + [ARG_CONST_MAP_PTR_OR_NULL] = &const_map_ptr_types, [ARG_PTR_TO_CTX] = &context_types, [ARG_PTR_TO_CTX_OR_NULL] = &context_types, [ARG_PTR_TO_SOCK_COMMON] = &sock_types, @@ -4259,9 +4261,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, meta->ref_obj_id = reg->ref_obj_id; } - if (arg_type == ARG_CONST_MAP_PTR) { - /* bpf_map_xxx(map_ptr) call: remember that map_ptr */ - meta->map_ptr = reg->map_ptr; + if (arg_type == ARG_CONST_MAP_PTR || + arg_type == ARG_CONST_MAP_PTR_OR_NULL) { + meta->map_ptr = register_is_null(reg) ? NULL : reg->map_ptr; } else if (arg_type == ARG_PTR_TO_MAP_KEY) { /* bpf_map_xxx(..., map_ptr, ..., key) call: * check that [key, key + map->key_size) are within