Skip to content

Commit e9ee9ef

Browse files
davem330Alexei Starovoitov
authored andcommitted
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. Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 88945f4 commit e9ee9ef

File tree

8 files changed

+45
-9
lines changed

8 files changed

+45
-9
lines changed

include/uapi/linux/bpf.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,20 @@ enum bpf_attach_type {
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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1452,9 +1452,14 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6505,6 +6505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,20 @@ enum bpf_attach_type {
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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
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,
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,8 @@ static int do_test_single(struct bpf_align_test *test)
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14275,7 +14275,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
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 ?

0 commit comments

Comments
 (0)