OSDN Git Service

selftests/bpf: Generalize dummy program types
[android-x86/kernel.git] / tools / testing / selftests / bpf / test_verifier.c
index a34552a..809d8e9 100644 (file)
@@ -70,7 +70,7 @@ struct bpf_test {
        int fixup_cgroup_storage[MAX_FIXUPS];
        const char *errstr;
        const char *errstr_unpriv;
-       uint32_t retval;
+       uint32_t retval, retval_unpriv;
        enum {
                UNDEF,
                ACCEPT,
@@ -2873,7 +2873,7 @@ static struct bpf_test tests[] = {
                        BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R1 tried to add from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
                .result_unpriv = REJECT,
                .result = ACCEPT,
        },
@@ -2986,6 +2986,8 @@ static struct bpf_test tests[] = {
                .fixup_prog1 = { 2 },
                .result = ACCEPT,
                .retval = 42,
+               /* Verifier rewrite for unpriv skips tail call here. */
+               .retval_unpriv = 2,
        },
        {
                "stack pointer arithmetic",
@@ -4798,6 +4800,7 @@ static struct bpf_test tests[] = {
                .fixup_cgroup_storage = { 1 },
                .result = REJECT,
                .errstr = "get_local_storage() doesn't support non-zero flags",
+               .errstr_unpriv = "R2 leaks addr into helper function",
                .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
        },
        {
@@ -7501,7 +7504,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7526,7 +7528,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7553,7 +7554,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R8 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7579,7 +7579,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R8 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7628,7 +7627,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7700,7 +7698,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7752,7 +7749,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7780,7 +7776,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7807,7 +7802,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7837,7 +7831,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R7 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7868,7 +7861,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 4 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
        },
        {
@@ -7897,7 +7889,6 @@ static struct bpf_test tests[] = {
                },
                .fixup_map1 = { 3 },
                .errstr = "unbounded min value",
-               .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
                .result = REJECT,
                .result_unpriv = REJECT,
        },
@@ -9799,7 +9790,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R0 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "R0 tried to subtract pointer from scalar",
                .result = REJECT,
        },
@@ -9814,7 +9805,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R1 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .result_unpriv = REJECT,
                .result = ACCEPT,
                .retval = 1,
@@ -9827,22 +9818,23 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R0 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "R0 tried to subtract pointer from scalar",
                .result = REJECT,
        },
        {
                "check deducing bounds from const, 4",
                .insns = {
+                       BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_JMP_IMM(BPF_JSLE, BPF_REG_0, 0, 1),
                        BPF_EXIT_INSN(),
                        BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1),
                        BPF_EXIT_INSN(),
-                       BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
+                       BPF_ALU64_REG(BPF_SUB, BPF_REG_6, BPF_REG_0),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R1 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R6 has pointer with unsupported alu operation",
                .result_unpriv = REJECT,
                .result = ACCEPT,
        },
@@ -9854,7 +9846,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R0 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "R0 tried to subtract pointer from scalar",
                .result = REJECT,
        },
@@ -9867,7 +9859,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R0 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "R0 tried to subtract pointer from scalar",
                .result = REJECT,
        },
@@ -9881,7 +9873,7 @@ static struct bpf_test tests[] = {
                                    offsetof(struct __sk_buff, mark)),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R1 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "dereference of modified ctx ptr",
                .result = REJECT,
        },
@@ -9895,7 +9887,7 @@ static struct bpf_test tests[] = {
                                    offsetof(struct __sk_buff, mark)),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R1 tried to add from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "dereference of modified ctx ptr",
                .result = REJECT,
        },
@@ -9907,7 +9899,7 @@ static struct bpf_test tests[] = {
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
                        BPF_EXIT_INSN(),
                },
-               .errstr_unpriv = "R0 tried to sub from different maps, paths, or prohibited types",
+               .errstr_unpriv = "R1 has pointer with unsupported alu operation",
                .errstr = "R0 tried to subtract pointer from scalar",
                .result = REJECT,
        },
@@ -12253,17 +12245,17 @@ static struct bpf_test tests[] = {
                                     BPF_FUNC_map_lookup_elem),
                        BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 28),
                        BPF_MOV64_REG(BPF_REG_7, BPF_REG_0),
-                       BPF_MOV64_IMM(BPF_REG_9, sizeof(struct test_val)),
+                       BPF_MOV64_IMM(BPF_REG_9, sizeof(struct test_val)/2),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
                        BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
-                       BPF_MOV64_IMM(BPF_REG_3, sizeof(struct test_val)),
+                       BPF_MOV64_IMM(BPF_REG_3, sizeof(struct test_val)/2),
                        BPF_MOV64_IMM(BPF_REG_4, 256),
                        BPF_EMIT_CALL(BPF_FUNC_get_stack),
                        BPF_MOV64_IMM(BPF_REG_1, 0),
                        BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
                        BPF_ALU64_IMM(BPF_LSH, BPF_REG_8, 32),
                        BPF_ALU64_IMM(BPF_ARSH, BPF_REG_8, 32),
-                       BPF_JMP_REG(BPF_JSLT, BPF_REG_1, BPF_REG_8, 16),
+                       BPF_JMP_REG(BPF_JSLT, BPF_REG_8, BPF_REG_1, 16),
                        BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_8),
                        BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
                        BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_8),
@@ -12273,7 +12265,7 @@ static struct bpf_test tests[] = {
                        BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
                        BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_1),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_7),
-                       BPF_MOV64_IMM(BPF_REG_5, sizeof(struct test_val)),
+                       BPF_MOV64_IMM(BPF_REG_5, sizeof(struct test_val)/2),
                        BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_5),
                        BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 4),
                        BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
@@ -12639,18 +12631,18 @@ static int create_map(uint32_t type, uint32_t size_key,
        return fd;
 }
 
-static int create_prog_dummy1(void)
+static int create_prog_dummy1(enum bpf_map_type prog_type)
 {
        struct bpf_insn prog[] = {
                BPF_MOV64_IMM(BPF_REG_0, 42),
                BPF_EXIT_INSN(),
        };
 
-       return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog,
+       return bpf_load_program(prog_type, prog,
                                ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
 }
 
-static int create_prog_dummy2(int mfd, int idx)
+static int create_prog_dummy2(enum bpf_map_type prog_type, int mfd, int idx)
 {
        struct bpf_insn prog[] = {
                BPF_MOV64_IMM(BPF_REG_3, idx),
@@ -12661,11 +12653,12 @@ static int create_prog_dummy2(int mfd, int idx)
                BPF_EXIT_INSN(),
        };
 
-       return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog,
+       return bpf_load_program(prog_type, prog,
                                ARRAY_SIZE(prog), "GPL", 0, NULL, 0);
 }
 
-static int create_prog_array(uint32_t max_elem, int p1key)
+static int create_prog_array(enum bpf_map_type prog_type, uint32_t max_elem,
+                            int p1key)
 {
        int p2key = 1;
        int mfd, p1fd, p2fd;
@@ -12677,8 +12670,8 @@ static int create_prog_array(uint32_t max_elem, int p1key)
                return -1;
        }
 
-       p1fd = create_prog_dummy1();
-       p2fd = create_prog_dummy2(mfd, p2key);
+       p1fd = create_prog_dummy1(prog_type);
+       p2fd = create_prog_dummy2(prog_type, mfd, p2key);
        if (p1fd < 0 || p2fd < 0)
                goto out;
        if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0)
@@ -12733,8 +12726,8 @@ static int create_cgroup_storage(void)
 
 static char bpf_vlog[UINT_MAX >> 8];
 
-static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
-                         int *map_fds)
+static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type,
+                         struct bpf_insn *prog, int *map_fds)
 {
        int *fixup_map1 = test->fixup_map1;
        int *fixup_map2 = test->fixup_map2;
@@ -12789,7 +12782,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
        }
 
        if (*fixup_prog1) {
-               map_fds[4] = create_prog_array(4, 0);
+               map_fds[4] = create_prog_array(prog_type, 4, 0);
                do {
                        prog[*fixup_prog1].imm = map_fds[4];
                        fixup_prog1++;
@@ -12797,7 +12790,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
        }
 
        if (*fixup_prog2) {
-               map_fds[5] = create_prog_array(8, 7);
+               map_fds[5] = create_prog_array(prog_type, 8, 7);
                do {
                        prog[*fixup_prog2].imm = map_fds[5];
                        fixup_prog2++;
@@ -12821,6 +12814,33 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
        }
 }
 
+static int set_admin(bool admin)
+{
+       cap_t caps;
+       const cap_value_t cap_val = CAP_SYS_ADMIN;
+       int ret = -1;
+
+       caps = cap_get_proc();
+       if (!caps) {
+               perror("cap_get_proc");
+               return -1;
+       }
+       if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
+                               admin ? CAP_SET : CAP_CLEAR)) {
+               perror("cap_set_flag");
+               goto out;
+       }
+       if (cap_set_proc(caps)) {
+               perror("cap_set_proc");
+               goto out;
+       }
+       ret = 0;
+out:
+       if (cap_free(caps))
+               perror("cap_free");
+       return ret;
+}
+
 static void do_test_single(struct bpf_test *test, bool unpriv,
                           int *passes, int *errors)
 {
@@ -12829,23 +12849,28 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
        struct bpf_insn *prog = test->insns;
        int map_fds[MAX_NR_MAPS];
        const char *expected_err;
+       uint32_t expected_val;
        uint32_t retval;
        int i, err;
 
        for (i = 0; i < MAX_NR_MAPS; i++)
                map_fds[i] = -1;
 
-       do_test_fixup(test, prog, map_fds);
+       if (!prog_type)
+               prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
+       do_test_fixup(test, prog_type, prog, map_fds);
        prog_len = probe_filter_length(prog);
 
-       fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
-                                    prog, prog_len, test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
+       fd_prog = bpf_verify_program(prog_type, prog, prog_len,
+                                    test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
                                     "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
 
        expected_ret = unpriv && test->result_unpriv != UNDEF ?
                       test->result_unpriv : test->result;
        expected_err = unpriv && test->errstr_unpriv ?
                       test->errstr_unpriv : test->errstr;
+       expected_val = unpriv && test->retval_unpriv ?
+                      test->retval_unpriv : test->retval;
 
        reject_from_alignment = fd_prog < 0 &&
                                (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) &&
@@ -12879,16 +12904,20 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
                __u8 tmp[TEST_DATA_LEN << 2];
                __u32 size_tmp = sizeof(tmp);
 
+               if (unpriv)
+                       set_admin(true);
                err = bpf_prog_test_run(fd_prog, 1, test->data,
                                        sizeof(test->data), tmp, &size_tmp,
                                        &retval, NULL);
+               if (unpriv)
+                       set_admin(false);
                if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
                        printf("Unexpected bpf_prog_test_run error\n");
                        goto fail_log;
                }
-               if (!err && retval != test->retval &&
-                   test->retval != POINTER_VALUE) {
-                       printf("FAIL retval %d != %d\n", retval, test->retval);
+               if (!err && retval != expected_val &&
+                   expected_val != POINTER_VALUE) {
+                       printf("FAIL retval %d != %d\n", retval, expected_val);
                        goto fail_log;
                }
        }
@@ -12931,33 +12960,6 @@ static bool is_admin(void)
        return (sysadmin == CAP_SET);
 }
 
-static int set_admin(bool admin)
-{
-       cap_t caps;
-       const cap_value_t cap_val = CAP_SYS_ADMIN;
-       int ret = -1;
-
-       caps = cap_get_proc();
-       if (!caps) {
-               perror("cap_get_proc");
-               return -1;
-       }
-       if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
-                               admin ? CAP_SET : CAP_CLEAR)) {
-               perror("cap_set_flag");
-               goto out;
-       }
-       if (cap_set_proc(caps)) {
-               perror("cap_set_proc");
-               goto out;
-       }
-       ret = 0;
-out:
-       if (cap_free(caps))
-               perror("cap_free");
-       return ret;
-}
-
 static void get_unpriv_disabled()
 {
        char buf[2];
@@ -12974,6 +12976,13 @@ static void get_unpriv_disabled()
        fclose(fd);
 }
 
+static bool test_as_unpriv(struct bpf_test *test)
+{
+       return !test->prog_type ||
+              test->prog_type == BPF_PROG_TYPE_SOCKET_FILTER ||
+              test->prog_type == BPF_PROG_TYPE_CGROUP_SKB;
+}
+
 static int do_test(bool unpriv, unsigned int from, unsigned int to)
 {
        int i, passes = 0, errors = 0, skips = 0;
@@ -12984,10 +12993,10 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to)
                /* Program types that are not supported by non-root we
                 * skip right away.
                 */
-               if (!test->prog_type && unpriv_disabled) {
+               if (test_as_unpriv(test) && unpriv_disabled) {
                        printf("#%d/u %s SKIP\n", i, test->descr);
                        skips++;
-               } else if (!test->prog_type) {
+               } else if (test_as_unpriv(test)) {
                        if (!unpriv)
                                set_admin(false);
                        printf("#%d/u %s ", i, test->descr);