• Dave Marchevsky's avatar
    bpf: Support __kptr to local kptrs · c8e18754
    Dave Marchevsky authored
    If a PTR_TO_BTF_ID type comes from program BTF - not vmlinux or module
    BTF - it must have been allocated by bpf_obj_new and therefore must be
    free'd with bpf_obj_drop. Such a PTR_TO_BTF_ID is considered a "local
    kptr" and is tagged with MEM_ALLOC type tag by bpf_obj_new.
    
    This patch adds support for treating __kptr-tagged pointers to "local
    kptrs" as having an implicit bpf_obj_drop destructor for referenced kptr
    acquire / release semantics. Consider the following example:
    
      struct node_data {
              long key;
              long data;
              struct bpf_rb_node node;
      };
    
      struct map_value {
              struct node_data __kptr *node;
      };
    
      struct {
              __uint(type, BPF_MAP_TYPE_ARRAY);
              __type(key, int);
              __type(value, struct map_value);
              __uint(max_entries, 1);
      } some_nodes SEC(".maps");
    
    If struct node_data had a matching definition in kernel BTF, the verifier would
    expect a destructor for the type to be registered. Since struct node_data does
    not match any type in kernel BTF, the verifier knows that there is no kfunc
    that provides a PTR_TO_BTF_ID to this type, and that such a PTR_TO_BTF_ID can
    only come from bpf_obj_new. So instead of searching for a registered dtor,
    a bpf_obj_drop dtor can be assumed.
    
    This allows the runtime to properly destruct such kptrs in
    bpf_obj_free_fields, which enables maps to clean up map_vals w/ such
    kptrs when going away.
    
    Implementation notes:
      * "kernel_btf" variable is renamed to "kptr_btf" in btf_parse_kptr.
        Before this patch, the variable would only ever point to vmlinux or
        module BTFs, but now it can point to some program BTF for local kptr
        type. It's later used to populate the (btf, btf_id) pair in kptr btf
        field.
      * It's necessary to btf_get the program BTF when populating btf_field
        for local kptr. btf_record_free later does a btf_put.
      * Behavior for non-local referenced kptrs is not modified, as
        bpf_find_btf_id helper only searches vmlinux and module BTFs for
        matching BTF type. If such a type is found, btf_field_kptr's btf will
        pass btf_is_kernel check, and the associated release function is
        some one-argument dtor. If btf_is_kernel check fails, associated
        release function is two-arg bpf_obj_drop_impl. Before this patch
        only btf_field_kptr's w/ kernel or module BTFs were created.
    Signed-off-by: default avatarDave Marchevsky <davemarchevsky@fb.com>
    Link: https://lore.kernel.org/r/20230310230743.2320707-2-davemarchevsky@fb.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    c8e18754
helpers.c 65.5 KB