Commit e9ee9efc authored by David Miller's avatar David Miller Committed by Alexei Starovoitov

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: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 88945f46
...@@ -232,6 +232,20 @@ enum bpf_attach_type { ...@@ -232,6 +232,20 @@ enum bpf_attach_type {
*/ */
#define BPF_F_STRICT_ALIGNMENT (1U << 0) #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 */ /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
#define BPF_PSEUDO_MAP_FD 1 #define BPF_PSEUDO_MAP_FD 1
......
...@@ -1452,9 +1452,14 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) ...@@ -1452,9 +1452,14 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
if (CHECK_ATTR(BPF_PROG_LOAD)) if (CHECK_ATTR(BPF_PROG_LOAD))
return -EINVAL; return -EINVAL;
if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT))
return -EINVAL; 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 */ /* copy eBPF program license from user space */
if (strncpy_from_user(license, u64_to_user_ptr(attr->license), if (strncpy_from_user(license, u64_to_user_ptr(attr->license),
sizeof(license) - 1) < 0) sizeof(license) - 1) < 0)
......
...@@ -6505,6 +6505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, ...@@ -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); env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
env->strict_alignment = true; env->strict_alignment = true;
if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
env->strict_alignment = false;
ret = replace_map_fd_with_map_ptr(env); ret = replace_map_fd_with_map_ptr(env);
if (ret < 0) if (ret < 0)
......
...@@ -232,6 +232,20 @@ enum bpf_attach_type { ...@@ -232,6 +232,20 @@ enum bpf_attach_type {
*/ */
#define BPF_F_STRICT_ALIGNMENT (1U << 0) #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 */ /* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
#define BPF_PSEUDO_MAP_FD 1 #define BPF_PSEUDO_MAP_FD 1
......
...@@ -279,9 +279,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, ...@@ -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, 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,
const char *license, __u32 kern_version, __u32 kern_version, char *log_buf, size_t log_buf_sz,
char *log_buf, size_t log_buf_sz, int log_level) int log_level)
{ {
union bpf_attr attr; union bpf_attr attr;
...@@ -295,7 +295,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, ...@@ -295,7 +295,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
attr.log_level = log_level; attr.log_level = log_level;
log_buf[0] = 0; log_buf[0] = 0;
attr.kern_version = kern_version; 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)); return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
} }
......
...@@ -98,7 +98,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type, ...@@ -98,7 +98,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
char *log_buf, size_t log_buf_sz); char *log_buf, size_t log_buf_sz);
LIBBPF_API int bpf_verify_program(enum bpf_prog_type type, LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
const struct bpf_insn *insns, 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, const char *license, __u32 kern_version,
char *log_buf, size_t log_buf_sz, char *log_buf, size_t log_buf_sz,
int log_level); int log_level);
......
...@@ -620,8 +620,8 @@ static int do_test_single(struct bpf_align_test *test) ...@@ -620,8 +620,8 @@ static int do_test_single(struct bpf_align_test *test)
prog_len = probe_filter_length(prog); prog_len = probe_filter_length(prog);
fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
prog, prog_len, 1, "GPL", 0, prog, prog_len, BPF_F_STRICT_ALIGNMENT,
bpf_vlog, sizeof(bpf_vlog), 2); "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 2);
if (fd_prog < 0 && test->result != REJECT) { if (fd_prog < 0 && test->result != REJECT) {
printf("Failed to load program.\n"); printf("Failed to load program.\n");
printf("%s", bpf_vlog); printf("%s", bpf_vlog);
......
...@@ -14275,7 +14275,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -14275,7 +14275,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
prog_len = probe_filter_length(prog); prog_len = probe_filter_length(prog);
fd_prog = bpf_verify_program(prog_type, prog, prog_len, 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); "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 1);
expected_ret = unpriv && test->result_unpriv != UNDEF ? expected_ret = unpriv && test->result_unpriv != UNDEF ?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment