Skip to content

Commit d2f30f5

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says: ==================== pull-request: bpf 2018-05-24 The following pull-request contains BPF updates for your *net* tree. The main changes are: 1) Fix a bug in the original fix to prevent out of bounds speculation when multiple tail call maps from different branches or calls end up at the same tail call helper invocation, from Daniel. 2) Two selftest fixes, one in reuseport_bpf_numa where test is skipped in case of missing numa support and another one to update kernel config to properly support xdp_meta.sh test, from Anders. ... Would be great if you have a chance to merge net into net-next after that. The verifier fix would be needed later as a dependency in bpf-next for upcomig work there. When you do the merge there's a trivial conflict on BPF side with 849fa50 ("bpf/verifier: refine retval R0 state for bpf_get_stack helper"): Resolution is to keep both functions, the do_refine_retval_range() and record_func_map(). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 24e4b07 + c93552c commit d2f30f5

File tree

4 files changed

+70
-24
lines changed

4 files changed

+70
-24
lines changed

include/linux/bpf_verifier.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ struct bpf_verifier_state_list {
142142
struct bpf_insn_aux_data {
143143
union {
144144
enum bpf_reg_type ptr_type; /* pointer type for load/store insns */
145-
struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */
145+
unsigned long map_state; /* pointer/poison value for maps */
146146
s32 call_imm; /* saved imm field of call insn */
147147
};
148148
int ctx_field_size; /* the ctx field size for load insn, maybe 0 */

kernel/bpf/verifier.c

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,29 @@ struct bpf_verifier_stack_elem {
156156
#define BPF_COMPLEXITY_LIMIT_INSNS 131072
157157
#define BPF_COMPLEXITY_LIMIT_STACK 1024
158158

159-
#define BPF_MAP_PTR_POISON ((void *)0xeB9F + POISON_POINTER_DELTA)
159+
#define BPF_MAP_PTR_UNPRIV 1UL
160+
#define BPF_MAP_PTR_POISON ((void *)((0xeB9FUL << 1) + \
161+
POISON_POINTER_DELTA))
162+
#define BPF_MAP_PTR(X) ((struct bpf_map *)((X) & ~BPF_MAP_PTR_UNPRIV))
163+
164+
static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux)
165+
{
166+
return BPF_MAP_PTR(aux->map_state) == BPF_MAP_PTR_POISON;
167+
}
168+
169+
static bool bpf_map_ptr_unpriv(const struct bpf_insn_aux_data *aux)
170+
{
171+
return aux->map_state & BPF_MAP_PTR_UNPRIV;
172+
}
173+
174+
static void bpf_map_ptr_store(struct bpf_insn_aux_data *aux,
175+
const struct bpf_map *map, bool unpriv)
176+
{
177+
BUILD_BUG_ON((unsigned long)BPF_MAP_PTR_POISON & BPF_MAP_PTR_UNPRIV);
178+
unpriv |= bpf_map_ptr_unpriv(aux);
179+
aux->map_state = (unsigned long)map |
180+
(unpriv ? BPF_MAP_PTR_UNPRIV : 0UL);
181+
}
160182

161183
struct bpf_call_arg_meta {
162184
struct bpf_map *map_ptr;
@@ -2333,6 +2355,29 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
23332355
return 0;
23342356
}
23352357

2358+
static int
2359+
record_func_map(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
2360+
int func_id, int insn_idx)
2361+
{
2362+
struct bpf_insn_aux_data *aux = &env->insn_aux_data[insn_idx];
2363+
2364+
if (func_id != BPF_FUNC_tail_call &&
2365+
func_id != BPF_FUNC_map_lookup_elem)
2366+
return 0;
2367+
if (meta->map_ptr == NULL) {
2368+
verbose(env, "kernel subsystem misconfigured verifier\n");
2369+
return -EINVAL;
2370+
}
2371+
2372+
if (!BPF_MAP_PTR(aux->map_state))
2373+
bpf_map_ptr_store(aux, meta->map_ptr,
2374+
meta->map_ptr->unpriv_array);
2375+
else if (BPF_MAP_PTR(aux->map_state) != meta->map_ptr)
2376+
bpf_map_ptr_store(aux, BPF_MAP_PTR_POISON,
2377+
meta->map_ptr->unpriv_array);
2378+
return 0;
2379+
}
2380+
23362381
static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn_idx)
23372382
{
23382383
const struct bpf_func_proto *fn = NULL;
@@ -2387,13 +2432,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
23872432
err = check_func_arg(env, BPF_REG_2, fn->arg2_type, &meta);
23882433
if (err)
23892434
return err;
2390-
if (func_id == BPF_FUNC_tail_call) {
2391-
if (meta.map_ptr == NULL) {
2392-
verbose(env, "verifier bug\n");
2393-
return -EINVAL;
2394-
}
2395-
env->insn_aux_data[insn_idx].map_ptr = meta.map_ptr;
2396-
}
23972435
err = check_func_arg(env, BPF_REG_3, fn->arg3_type, &meta);
23982436
if (err)
23992437
return err;
@@ -2404,6 +2442,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
24042442
if (err)
24052443
return err;
24062444

2445+
err = record_func_map(env, &meta, func_id, insn_idx);
2446+
if (err)
2447+
return err;
2448+
24072449
/* Mark slots with STACK_MISC in case of raw mode, stack offset
24082450
* is inferred from register state.
24092451
*/
@@ -2428,8 +2470,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
24282470
} else if (fn->ret_type == RET_VOID) {
24292471
regs[BPF_REG_0].type = NOT_INIT;
24302472
} else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL) {
2431-
struct bpf_insn_aux_data *insn_aux;
2432-
24332473
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
24342474
/* There is no offset yet applied, variable or fixed */
24352475
mark_reg_known_zero(env, regs, BPF_REG_0);
@@ -2445,11 +2485,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
24452485
}
24462486
regs[BPF_REG_0].map_ptr = meta.map_ptr;
24472487
regs[BPF_REG_0].id = ++env->id_gen;
2448-
insn_aux = &env->insn_aux_data[insn_idx];
2449-
if (!insn_aux->map_ptr)
2450-
insn_aux->map_ptr = meta.map_ptr;
2451-
else if (insn_aux->map_ptr != meta.map_ptr)
2452-
insn_aux->map_ptr = BPF_MAP_PTR_POISON;
24532488
} else {
24542489
verbose(env, "unknown return type %d of func %s#%d\n",
24552490
fn->ret_type, func_id_name(func_id), func_id);
@@ -5417,6 +5452,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
54175452
struct bpf_insn *insn = prog->insnsi;
54185453
const struct bpf_func_proto *fn;
54195454
const int insn_cnt = prog->len;
5455+
struct bpf_insn_aux_data *aux;
54205456
struct bpf_insn insn_buf[16];
54215457
struct bpf_prog *new_prog;
54225458
struct bpf_map *map_ptr;
@@ -5491,19 +5527,22 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
54915527
insn->imm = 0;
54925528
insn->code = BPF_JMP | BPF_TAIL_CALL;
54935529

5530+
aux = &env->insn_aux_data[i + delta];
5531+
if (!bpf_map_ptr_unpriv(aux))
5532+
continue;
5533+
54945534
/* instead of changing every JIT dealing with tail_call
54955535
* emit two extra insns:
54965536
* if (index >= max_entries) goto out;
54975537
* index &= array->index_mask;
54985538
* to avoid out-of-bounds cpu speculation
54995539
*/
5500-
map_ptr = env->insn_aux_data[i + delta].map_ptr;
5501-
if (map_ptr == BPF_MAP_PTR_POISON) {
5540+
if (bpf_map_ptr_poisoned(aux)) {
55025541
verbose(env, "tail_call abusing map_ptr\n");
55035542
return -EINVAL;
55045543
}
5505-
if (!map_ptr->unpriv_array)
5506-
continue;
5544+
5545+
map_ptr = BPF_MAP_PTR(aux->map_state);
55075546
insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3,
55085547
map_ptr->max_entries, 2);
55095548
insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3,
@@ -5527,9 +5566,12 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
55275566
*/
55285567
if (prog->jit_requested && BITS_PER_LONG == 64 &&
55295568
insn->imm == BPF_FUNC_map_lookup_elem) {
5530-
map_ptr = env->insn_aux_data[i + delta].map_ptr;
5531-
if (map_ptr == BPF_MAP_PTR_POISON ||
5532-
!map_ptr->ops->map_gen_lookup)
5569+
aux = &env->insn_aux_data[i + delta];
5570+
if (bpf_map_ptr_poisoned(aux))
5571+
goto patch_call_imm;
5572+
5573+
map_ptr = BPF_MAP_PTR(aux->map_state);
5574+
if (!map_ptr->ops->map_gen_lookup)
55335575
goto patch_call_imm;
55345576

55355577
cnt = map_ptr->ops->map_gen_lookup(map_ptr, insn_buf);

tools/testing/selftests/bpf/config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ CONFIG_BPF_EVENTS=y
55
CONFIG_TEST_BPF=m
66
CONFIG_CGROUP_BPF=y
77
CONFIG_NETDEVSIM=m
8+
CONFIG_NET_CLS_ACT=y
9+
CONFIG_NET_SCH_INGRESS=y

tools/testing/selftests/net/reuseport_bpf_numa.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <unistd.h>
2424
#include <numa.h>
2525

26+
#include "../kselftest.h"
27+
2628
static const int PORT = 8888;
2729

2830
static void build_rcv_group(int *rcv_fd, size_t len, int family, int proto)
@@ -229,7 +231,7 @@ int main(void)
229231
int *rcv_fd, nodes;
230232

231233
if (numa_available() < 0)
232-
error(1, errno, "no numa api support");
234+
ksft_exit_skip("no numa api support\n");
233235

234236
nodes = numa_max_node() + 1;
235237

0 commit comments

Comments
 (0)