bpf: Add BPF_F_ANY_ALIGNMENT.
authorDavid Miller <davem@davemloft.net>
Sat, 1 Dec 2018 05:08:14 +0000 (21:08 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 1 Dec 2018 05:38:48 +0000 (21:38 -0800)
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>
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 597afdbc1ab93a7f5e6774dd5dcba035d59f597d..8050caea74955e0d2b2034d653a3b8f42995aa73 100644 (file)
@@ -232,6 +232,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 85cbeec06e50d05ae1612882d4d4b7f9e4338a64..f9554d9a14e18840c61436ce32f58070c88a690f 100644 (file)
@@ -1452,9 +1452,14 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
        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 9584438fa2cc177517fc71d4b95d3883a112da75..71988337ac14e34c5b104b41705e86d82b8fb699 100644 (file)
@@ -6505,6 +6505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
        env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
        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)
index 597afdbc1ab93a7f5e6774dd5dcba035d59f597d..8050caea74955e0d2b2034d653a3b8f42995aa73 100644 (file)
@@ -232,6 +232,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 ce182219459003c4079b8a1f5a5692c49887f4f5..c19226cccf39f7c52ce3a6eaedcd5db7e3521fb7 100644 (file)
@@ -279,9 +279,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;
 
@@ -295,7 +295,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(BPF_PROG_LOAD, &attr, sizeof(attr));
 }
index 09e8bbe111d4c39452162b4e91c8c146b0394054..60392b70587ca1645479c319dd8552e179153e2f 100644 (file)
@@ -98,7 +98,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
                                char *log_buf, size_t log_buf_sz);
 LIBBPF_API 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 5eace1f606fb49eb2da69a8830c78393693236f2..78e779c358693322a5ccfbe88efa577464a3cac7 100644 (file)
@@ -14275,7 +14275,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 ?