]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
bpf: Add BPF_F_ANY_ALIGNMENT.
authorDavid S. Miller <davem@davemloft.net>
Wed, 2 Jun 2021 03:27:48 +0000 (11:27 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Jun 2021 11:24:08 +0000 (13:24 +0200)
commit e9ee9efc0d176512cdce9d27ff8549d7ffa2bfcd upstream

Often we want to write tests cases that check things like bad context
offset accesses.  And one way to do this is to use an odd offset on,
for example, a 32-bit load.

This unfortunately triggers the alignment checks first on platforms
that do not set CONFIG_EFFICIENT_UNALIGNED_ACCESS.  So the test
case see the alignment failure rather than what it was testing for.

It is often not completely possible to respect the original intention
of the test, or even test the same exact thing, while solving the
alignment issue.

Another option could have been to check the alignment after the
context and other validations are performed by the verifier, but
that is a non-trivial change to the verifier.

Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/uapi/linux/bpf.h
kernel/bpf/syscall.c
kernel/bpf/verifier.c
tools/include/uapi/linux/bpf.h
tools/lib/bpf/bpf.c
tools/lib/bpf/bpf.h
tools/testing/selftests/bpf/test_align.c
tools/testing/selftests/bpf/test_verifier.c

index 71ca8c4dc290fdb29d0b70df19380d0d9932f9ed..8481fc7676c0b50447343d6a43a163249eb8b3f0 100644 (file)
@@ -228,6 +228,20 @@ enum bpf_attach_type {
  */
 #define BPF_F_STRICT_ALIGNMENT (1U << 0)
 
+/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
+ * verifier will allow any alignment whatsoever.  On platforms
+ * with strict alignment requirements for loads ands stores (such
+ * as sparc and mips) the verifier validates that all loads and
+ * stores provably follow this requirement.  This flag turns that
+ * checking and enforcement off.
+ *
+ * It is mostly used for testing when we want to validate the
+ * context and memory access aspects of the verifier, but because
+ * of an unaligned access the alignment check would trigger before
+ * the one we are interested in.
+ */
+#define BPF_F_ANY_ALIGNMENT    (1U << 1)
+
 /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
 #define BPF_PSEUDO_MAP_FD      1
 
index 21a366a661acda958b0392daa7b46042eb5f49c1..353a8d672302bf7373d4e8332b4325946f6a2f4f 100644 (file)
@@ -1367,9 +1367,14 @@ static int bpf_prog_load(union bpf_attr *attr)
        if (CHECK_ATTR(BPF_PROG_LOAD))
                return -EINVAL;
 
-       if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
+       if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT))
                return -EINVAL;
 
+       if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
+           (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
+           !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
        /* copy eBPF program license from user space */
        if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
                              sizeof(license) - 1) < 0)
index 1f4c88ce58deb11e0d43c5b25fc3c4cd1a6c1b08..4ce032c4acd039376740c844e6e6cc8328a7dda3 100644 (file)
@@ -6440,6 +6440,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
        if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
                env->strict_alignment = true;
 
+       if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
+               env->strict_alignment = false;
+
        ret = replace_map_fd_with_map_ptr(env);
        if (ret < 0)
                goto skip_full_check;
index 13944978ada5b77d17158465f9ad6b79bd4b6a39..9e060c6a01ac299bd02aa87ef891c4d18d66c4a8 100644 (file)
@@ -226,6 +226,20 @@ enum bpf_attach_type {
  */
 #define BPF_F_STRICT_ALIGNMENT (1U << 0)
 
+/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
+ * verifier will allow any alignment whatsoever.  On platforms
+ * with strict alignment requirements for loads ands stores (such
+ * as sparc and mips) the verifier validates that all loads and
+ * stores provably follow this requirement.  This flag turns that
+ * checking and enforcement off.
+ *
+ * It is mostly used for testing when we want to validate the
+ * context and memory access aspects of the verifier, but because
+ * of an unaligned access the alignment check would trigger before
+ * the one we are interested in.
+ */
+#define BPF_F_ANY_ALIGNMENT    (1U << 1)
+
 /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
 #define BPF_PSEUDO_MAP_FD      1
 
index 482025b728399338eaa8df4ca32900c9b89a01c7..f28ae6a68697a4051f030d0270010ca63e1ddd7a 100644 (file)
@@ -261,9 +261,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
 }
 
 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
-                      size_t insns_cnt, int strict_alignment,
-                      const char *license, __u32 kern_version,
-                      char *log_buf, size_t log_buf_sz, int log_level)
+                      size_t insns_cnt, __u32 prog_flags, const char *license,
+                      __u32 kern_version, char *log_buf, size_t log_buf_sz,
+                      int log_level)
 {
        union bpf_attr attr;
 
@@ -277,7 +277,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
        attr.log_level = log_level;
        log_buf[0] = 0;
        attr.kern_version = kern_version;
-       attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0;
+       attr.prog_flags = prog_flags;
 
        return sys_bpf_prog_load(&attr, sizeof(attr));
 }
index c3145ab3bdcaca155aef554750cded18018b8e28..7f2e947d940c1f0769198d74c8fa2b722317b1f8 100644 (file)
@@ -79,7 +79,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
                     __u32 kern_version, char *log_buf,
                     size_t log_buf_sz);
 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
-                      size_t insns_cnt, int strict_alignment,
+                      size_t insns_cnt, __u32 prog_flags,
                       const char *license, __u32 kern_version,
                       char *log_buf, size_t log_buf_sz, int log_level);
 
index 5f377ec53f2f8a1df0fecac7a624f43133c4b8f2..3c789d03b629d222618a18d168883615c0661ec8 100644 (file)
@@ -620,8 +620,8 @@ static int do_test_single(struct bpf_align_test *test)
 
        prog_len = probe_filter_length(prog);
        fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
-                                    prog, prog_len, 1, "GPL", 0,
-                                    bpf_vlog, sizeof(bpf_vlog), 2);
+                                    prog, prog_len, BPF_F_STRICT_ALIGNMENT,
+                                    "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 2);
        if (fd_prog < 0 && test->result != REJECT) {
                printf("Failed to load program.\n");
                printf("%s", bpf_vlog);
index 809d8e9ac35635b72fbffb5d12824aca24831050..919f97a202033d3987e34b0f1a83b66410a611c6 100644 (file)
@@ -12862,7 +12862,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
        prog_len = probe_filter_length(prog);
 
        fd_prog = bpf_verify_program(prog_type, prog, prog_len,
-                                    test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
+                                    test->flags & F_LOAD_WITH_STRICT_ALIGNMENT ?
+                                    BPF_F_STRICT_ALIGNMENT : 0,
                                     "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
 
        expected_ret = unpriv && test->result_unpriv != UNDEF ?