Commit 8155aedf authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Daniel Borkmann says:

====================
pull-request: bpf 2018-01-13

The following pull-request contains BPF updates for your *net* tree.

The main changes are:

1) Follow-up fix to the recent BPF out-of-bounds speculation
   fix that prevents max_entries overflows and an undefined
   behavior on 32 bit archs on index_mask calculation, from
   Daniel.

2) Reject unsupported BPF_ARSH opcode in 32 bit ALU mode that
   was otherwise throwing an unknown opcode warning in the
   interpreter, from Daniel.

3) Typo fix in one of the user facing verbose() messages that
   was added during the BPF out-of-bounds speculation fix,
   from Colin.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5dd966c6 bbeb6e43
...@@ -56,7 +56,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) ...@@ -56,7 +56,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
u32 elem_size, index_mask, max_entries; u32 elem_size, index_mask, max_entries;
bool unpriv = !capable(CAP_SYS_ADMIN); bool unpriv = !capable(CAP_SYS_ADMIN);
struct bpf_array *array; struct bpf_array *array;
u64 array_size; u64 array_size, mask64;
/* check sanity of attributes */ /* check sanity of attributes */
if (attr->max_entries == 0 || attr->key_size != 4 || if (attr->max_entries == 0 || attr->key_size != 4 ||
...@@ -74,13 +74,25 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) ...@@ -74,13 +74,25 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
elem_size = round_up(attr->value_size, 8); elem_size = round_up(attr->value_size, 8);
max_entries = attr->max_entries; max_entries = attr->max_entries;
index_mask = roundup_pow_of_two(max_entries) - 1;
if (unpriv) /* On 32 bit archs roundup_pow_of_two() with max_entries that has
* upper most bit set in u32 space is undefined behavior due to
* resulting 1U << 32, so do it manually here in u64 space.
*/
mask64 = fls_long(max_entries - 1);
mask64 = 1ULL << mask64;
mask64 -= 1;
index_mask = mask64;
if (unpriv) {
/* round up array size to nearest power of 2, /* round up array size to nearest power of 2,
* since cpu will speculate within index_mask limits * since cpu will speculate within index_mask limits
*/ */
max_entries = index_mask + 1; max_entries = index_mask + 1;
/* Check for overflows. */
if (max_entries < attr->max_entries)
return ERR_PTR(-E2BIG);
}
array_size = sizeof(*array); array_size = sizeof(*array);
if (percpu) if (percpu)
......
...@@ -2493,6 +2493,11 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -2493,6 +2493,11 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
return -EINVAL; return -EINVAL;
} }
if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) {
verbose(env, "BPF_ARSH not supported for 32 bit ALU\n");
return -EINVAL;
}
if ((opcode == BPF_LSH || opcode == BPF_RSH || if ((opcode == BPF_LSH || opcode == BPF_RSH ||
opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) { opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32; int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
...@@ -4472,7 +4477,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) ...@@ -4472,7 +4477,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
*/ */
map_ptr = env->insn_aux_data[i + delta].map_ptr; map_ptr = env->insn_aux_data[i + delta].map_ptr;
if (map_ptr == BPF_MAP_PTR_POISON) { if (map_ptr == BPF_MAP_PTR_POISON) {
verbose(env, "tail_call obusing map_ptr\n"); verbose(env, "tail_call abusing map_ptr\n");
return -EINVAL; return -EINVAL;
} }
if (!map_ptr->unpriv_array) if (!map_ptr->unpriv_array)
......
...@@ -272,6 +272,46 @@ static struct bpf_test tests[] = { ...@@ -272,6 +272,46 @@ static struct bpf_test tests[] = {
.errstr = "invalid bpf_ld_imm64 insn", .errstr = "invalid bpf_ld_imm64 insn",
.result = REJECT, .result = REJECT,
}, },
{
"arsh32 on imm",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_ALU32_IMM(BPF_ARSH, BPF_REG_0, 5),
BPF_EXIT_INSN(),
},
.result = REJECT,
.errstr = "BPF_ARSH not supported for 32 bit ALU",
},
{
"arsh32 on reg",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_MOV64_IMM(BPF_REG_1, 5),
BPF_ALU32_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1),
BPF_EXIT_INSN(),
},
.result = REJECT,
.errstr = "BPF_ARSH not supported for 32 bit ALU",
},
{
"arsh64 on imm",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_ALU64_IMM(BPF_ARSH, BPF_REG_0, 5),
BPF_EXIT_INSN(),
},
.result = ACCEPT,
},
{
"arsh64 on reg",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_MOV64_IMM(BPF_REG_1, 5),
BPF_ALU64_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1),
BPF_EXIT_INSN(),
},
.result = ACCEPT,
},
{ {
"no bpf_exit", "no bpf_exit",
.insns = { .insns = {
......
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