• David Vernet's avatar
    bpf: Allow trusted args to walk struct when checking BTF IDs · b613d335
    David Vernet authored
    When validating BTF types for KF_TRUSTED_ARGS kfuncs, the verifier
    currently enforces that the top-level type must match when calling
    the kfunc. In other words, the verifier does not allow the BPF program
    to pass a bitwise equivalent struct, despite it being allowed according
    to the C standard.
    
    For example, if you have the following type:
    
    struct  nf_conn___init {
    	struct nf_conn ct;
    };
    
    The C standard stipulates that it would be safe to pass a struct
    nf_conn___init to a kfunc expecting a struct nf_conn. The verifier
    currently disallows this, however, as semantically kfuncs may want to
    enforce that structs that have equivalent types according to the C
    standard, but have different BTF IDs, are not able to be passed to
    kfuncs expecting one or the other. For example, struct nf_conn___init
    may not be queried / looked up, as it is allocated but may not yet be
    fully initialized.
    
    On the other hand, being able to pass types that are equivalent
    according to the C standard will be useful for other types of kfunc /
    kptrs enabled by BPF.  For example, in a follow-on patch, a series of
    kfuncs will be added which allow programs to do bitwise queries on
    cpumasks that are either allocated by the program (in which case they'll
    be a 'struct bpf_cpumask' type that wraps a cpumask_t as its first
    element), or a cpumask that was allocated by the main kernel (in which
    case it will just be a straight cpumask_t, as in task->cpus_ptr).
    
    Having the two types of cpumasks allows us to distinguish between the
    two for when a cpumask is read-only vs. mutatable. A struct bpf_cpumask
    can be mutated by e.g. bpf_cpumask_clear(), whereas a regular cpumask_t
    cannot be. On the other hand, a struct bpf_cpumask can of course be
    queried in the exact same manner as a cpumask_t, with e.g.
    bpf_cpumask_test_cpu().
    
    If we were to enforce that top level types match, then a user that's
    passing a struct bpf_cpumask to a read-only cpumask_t argument would
    have to cast with something like bpf_cast_to_kern_ctx() (which itself
    would need to be updated to expect the alias, and currently it only
    accommodates a single alias per prog type). Additionally, not specifying
    KF_TRUSTED_ARGS is not an option, as some kfuncs take one argument as a
    struct bpf_cpumask *, and another as a struct cpumask *
    (i.e. cpumask_t).
    
    In order to enable this, this patch relaxes the constraint that a
    KF_TRUSTED_ARGS kfunc must have strict type matching, and instead only
    enforces strict type matching if a type is observed to be a "no-cast
    alias" (i.e., that the type names are equivalent, but one is suffixed
    with ___init).
    
    Additionally, in order to try and be conservative and match existing
    behavior / expectations, this patch also enforces strict type checking
    for acquire kfuncs. We were already enforcing it for release kfuncs, so
    this should also improve the consistency of the semantics for kfuncs.
    Signed-off-by: default avatarDavid Vernet <void@manifault.com>
    Link: https://lore.kernel.org/r/20230120192523.3650503-3-void@manifault.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    b613d335
btf.c 213 KB