Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-block.git] / kernel / bpf / btf.c
index 73780748404c29bfd6b4d2284b2aff615093497f..1853beaed4beecfd49ea1bf5aa56ba6f013c7c74 100644 (file)
@@ -207,6 +207,11 @@ enum btf_kfunc_hook {
        BTF_KFUNC_HOOK_TRACING,
        BTF_KFUNC_HOOK_SYSCALL,
        BTF_KFUNC_HOOK_FMODRET,
+       BTF_KFUNC_HOOK_CGROUP_SKB,
+       BTF_KFUNC_HOOK_SCHED_ACT,
+       BTF_KFUNC_HOOK_SK_SKB,
+       BTF_KFUNC_HOOK_SOCKET_FILTER,
+       BTF_KFUNC_HOOK_LWT,
        BTF_KFUNC_HOOK_MAX,
 };
 
@@ -3283,9 +3288,9 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t,
        /* Reject extra tags */
        if (btf_type_is_type_tag(btf_type_by_id(btf, t->type)))
                return -EINVAL;
-       if (!strcmp("kptr", __btf_name_by_offset(btf, t->name_off)))
+       if (!strcmp("kptr_untrusted", __btf_name_by_offset(btf, t->name_off)))
                type = BPF_KPTR_UNREF;
-       else if (!strcmp("kptr_ref", __btf_name_by_offset(btf, t->name_off)))
+       else if (!strcmp("kptr", __btf_name_by_offset(btf, t->name_off)))
                type = BPF_KPTR_REF;
        else
                return -EINVAL;
@@ -5684,6 +5689,10 @@ again:
         * int socket_filter_bpf_prog(struct __sk_buff *skb)
         * { // no fields of skb are ever used }
         */
+       if (strcmp(ctx_tname, "__sk_buff") == 0 && strcmp(tname, "sk_buff") == 0)
+               return ctx_type;
+       if (strcmp(ctx_tname, "xdp_md") == 0 && strcmp(tname, "xdp_buff") == 0)
+               return ctx_type;
        if (strcmp(ctx_tname, tname)) {
                /* bpf_user_pt_regs_t is a typedef, so resolve it to
                 * underlying struct and check name again
@@ -6155,6 +6164,7 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
        const char *tname, *mname, *tag_value;
        u32 vlen, elem_id, mid;
 
+       *flag = 0;
 again:
        tname = __btf_name_by_offset(btf, t->name_off);
        if (!btf_type_is_struct(t)) {
@@ -6321,6 +6331,15 @@ error:
                 * of this field or inside of this struct
                 */
                if (btf_type_is_struct(mtype)) {
+                       if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
+                           btf_type_vlen(mtype) != 1)
+                               /*
+                                * walking unions yields untrusted pointers
+                                * with exception of __bpf_md_ptr and other
+                                * unions with a single member
+                                */
+                               *flag |= PTR_UNTRUSTED;
+
                        /* our field must be inside that union or struct */
                        t = mtype;
 
@@ -6365,7 +6384,7 @@ error:
                        stype = btf_type_skip_modifiers(btf, mtype->type, &id);
                        if (btf_type_is_struct(stype)) {
                                *next_btf_id = id;
-                               *flag = tmp_flag;
+                               *flag |= tmp_flag;
                                return WALK_PTR;
                        }
                }
@@ -7705,6 +7724,19 @@ static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type)
                return BTF_KFUNC_HOOK_TRACING;
        case BPF_PROG_TYPE_SYSCALL:
                return BTF_KFUNC_HOOK_SYSCALL;
+       case BPF_PROG_TYPE_CGROUP_SKB:
+               return BTF_KFUNC_HOOK_CGROUP_SKB;
+       case BPF_PROG_TYPE_SCHED_ACT:
+               return BTF_KFUNC_HOOK_SCHED_ACT;
+       case BPF_PROG_TYPE_SK_SKB:
+               return BTF_KFUNC_HOOK_SK_SKB;
+       case BPF_PROG_TYPE_SOCKET_FILTER:
+               return BTF_KFUNC_HOOK_SOCKET_FILTER;
+       case BPF_PROG_TYPE_LWT_OUT:
+       case BPF_PROG_TYPE_LWT_IN:
+       case BPF_PROG_TYPE_LWT_XMIT:
+       case BPF_PROG_TYPE_LWT_SEG6LOCAL:
+               return BTF_KFUNC_HOOK_LWT;
        default:
                return BTF_KFUNC_HOOK_MAX;
        }
@@ -8336,7 +8368,7 @@ out:
 
 bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
                                const struct bpf_reg_state *reg,
-                               int off)
+                               int off, const char *suffix)
 {
        struct btf *btf = reg->btf;
        const struct btf_type *walk_type, *safe_type;
@@ -8353,7 +8385,7 @@ bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
 
        tname = btf_name_by_offset(btf, walk_type->name_off);
 
-       ret = snprintf(safe_tname, sizeof(safe_tname), "%s__safe_fields", tname);
+       ret = snprintf(safe_tname, sizeof(safe_tname), "%s%s", tname, suffix);
        if (ret < 0)
                return false;