History

bpf: Add BPF_F_ANY_ALIGNMENT.

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.

David Miller committed 7 years ago

Commit e9ee9ef1 parent 88945f48 files · +45 −9Browse files

Unified · Split

8 files
  1. include/uapi/linux/bpf.h +14 −0
  2. kernel/bpf/syscall.c +6 −1
  3. kernel/bpf/verifier.c +2 −0
  4. tools/include/uapi/linux/bpf.h +14 −0
  5. tools/lib/bpf/bpf.c +4 −4
  6. tools/lib/bpf/bpf.h +1 −1
  7. tools/testing/selftests/bpf/test_align.c +2 −2
  8. tools/testing/selftests/bpf/test_verifier.c +2 −1
include/uapi/linux/bpf.h+14−0
@@ -232,6 +232,20 @@ enum bpf_attach_type { · 231 unmodified lines
232232 */
233233 #define BPF_F_STRICT_ALIGNMENT (1U << 0)
234234
235+/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
236+ * verifier will allow any alignment whatsoever. On platforms
237+ * with strict alignment requirements for loads ands stores (such
238+ * as sparc and mips) the verifier validates that all loads and
239+ * stores provably follow this requirement. This flag turns that
240+ * checking and enforcement off.
241+ *
242+ * It is mostly used for testing when we want to validate the
243+ * context and memory access aspects of the verifier, but because
244+ * of an unaligned access the alignment check would trigger before
245+ * the one we are interested in.
246+ */
247+#define BPF_F_ANY_ALIGNMENT (1U << 1)
248+
235249 /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
236250 #define BPF_PSEUDO_MAP_FD 1
237251
kernel/bpf/syscall.c+6−1
@@ -1452,9 +1452,14 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) · 1451 unmodified lines
14521452 if (CHECK_ATTR(BPF_PROG_LOAD))
14531453 return -EINVAL;
14541454
1455− if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
1455+ if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT))
14561456 return -EINVAL;
14571457
1458+ if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
1459+ (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
1460+ !capable(CAP_SYS_ADMIN))
1461+ return -EPERM;
1462+
14581463 /* copy eBPF program license from user space */
14591464 if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
14601465 sizeof(license) - 1) < 0)
kernel/bpf/verifier.c+2−0
@@ -6505,6 +6505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, · 6504 unmodified lines
65056505 env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
65066506 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
65076507 env->strict_alignment = true;
6508+ if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
6509+ env->strict_alignment = false;
65086510
65096511 ret = replace_map_fd_with_map_ptr(env);
65106512 if (ret < 0)
tools/include/uapi/linux/bpf.h+14−0
@@ -232,6 +232,20 @@ enum bpf_attach_type { · 231 unmodified lines
232232 */
233233 #define BPF_F_STRICT_ALIGNMENT (1U << 0)
234234
235+/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
236+ * verifier will allow any alignment whatsoever. On platforms
237+ * with strict alignment requirements for loads ands stores (such
238+ * as sparc and mips) the verifier validates that all loads and
239+ * stores provably follow this requirement. This flag turns that
240+ * checking and enforcement off.
241+ *
242+ * It is mostly used for testing when we want to validate the
243+ * context and memory access aspects of the verifier, but because
244+ * of an unaligned access the alignment check would trigger before
245+ * the one we are interested in.
246+ */
247+#define BPF_F_ANY_ALIGNMENT (1U << 1)
248+
235249 /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
236250 #define BPF_PSEUDO_MAP_FD 1
237251
tools/lib/bpf/bpf.c+4−4
@@ -279,9 +279,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, · 278 unmodified lines
279279 }
280280
281281 int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
282− size_t insns_cnt, int strict_alignment,
283− const char *license, __u32 kern_version,
284− char *log_buf, size_t log_buf_sz, int log_level)
282+ size_t insns_cnt, __u32 prog_flags, const char *license,
283+ __u32 kern_version, char *log_buf, size_t log_buf_sz,
284+ int log_level)
285285 {
286286 union bpf_attr attr;
287287
@@ -295,7 +295,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, · 7 unmodified lines
295295 attr.log_level = log_level;
296296 log_buf[0] = 0;
297297 attr.kern_version = kern_version;
298− attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0;
298+ attr.prog_flags = prog_flags;
299299
300300 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
301301 }
tools/lib/bpf/bpf.h+1−1
@@ -98,7 +98,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type, · 97 unmodified lines
9898 char *log_buf, size_t log_buf_sz);
9999 LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
100100 const struct bpf_insn *insns,
101− size_t insns_cnt, int strict_alignment,
101+ size_t insns_cnt, __u32 prog_flags,
102102 const char *license, __u32 kern_version,
103103 char *log_buf, size_t log_buf_sz,
104104 int log_level);
tools/testing/selftests/bpf/test_align.c+2−2
@@ -620,8 +620,8 @@ static int do_test_single(struct bpf_align_test *test) · 619 unmodified lines
620620
621621 prog_len = probe_filter_length(prog);
622622 fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
623− prog, prog_len, 1, "GPL", 0,
624− bpf_vlog, sizeof(bpf_vlog), 2);
623+ prog, prog_len, BPF_F_STRICT_ALIGNMENT,
624+ "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 2);
625625 if (fd_prog < 0 && test->result != REJECT) {
626626 printf("Failed to load program.\n");
627627 printf("%s", bpf_vlog);
tools/testing/selftests/bpf/test_verifier.c+2−1
@@ -14275,7 +14275,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, · 14274 unmodified lines
1427514275 prog_len = probe_filter_length(prog);
1427614276
1427714277 fd_prog = bpf_verify_program(prog_type, prog, prog_len,
14278− test->flags & F_LOAD_WITH_STRICT_ALIGNMENT,
14278+ test->flags & F_LOAD_WITH_STRICT_ALIGNMENT ?
14279+ BPF_F_STRICT_ALIGNMENT : 0,
1427914280 "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
1428014281
1428114282 expected_ret = unpriv && test->result_unpriv != UNDEF ?