Skip to content

Commit 64d8529

Browse files
jsitnickiborkmann
authored andcommitted
bpf: Allow bpf_map_lookup_elem for SOCKMAP and SOCKHASH
White-list map lookup for SOCKMAP/SOCKHASH from BPF. Lookup returns a pointer to a full socket and acquires a reference if necessary. To support it we need to extend the verifier to know that: (1) register storing the lookup result holds a pointer to socket, if lookup was done on SOCKMAP/SOCKHASH, and that (2) map lookup on SOCKMAP/SOCKHASH is a reference acquiring operation, which needs a corresponding reference release with bpf_sk_release. On sock_map side, lookup handlers exposed via bpf_map_ops now bump sk_refcnt if socket is reference counted. In turn, bpf_sk_select_reuseport, the only in-kernel user of SOCKMAP/SOCKHASH ops->map_lookup_elem, was updated to release the reference. Sockets fetched from a map can be used in the same way as ones returned by BPF socket lookup helpers, such as bpf_sk_lookup_tcp. In particular, they can be used with bpf_sk_assign to direct packets toward a socket on TC ingress path. Suggested-by: Lorenz Bauer <[email protected]> Signed-off-by: Jakub Sitnicki <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: John Fastabend <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 0b3b9ca commit 64d8529

File tree

3 files changed

+55
-12
lines changed

3 files changed

+55
-12
lines changed

kernel/bpf/verifier.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,30 @@ static bool is_release_function(enum bpf_func_id func_id)
429429
return func_id == BPF_FUNC_sk_release;
430430
}
431431

432-
static bool is_acquire_function(enum bpf_func_id func_id)
432+
static bool may_be_acquire_function(enum bpf_func_id func_id)
433433
{
434434
return func_id == BPF_FUNC_sk_lookup_tcp ||
435435
func_id == BPF_FUNC_sk_lookup_udp ||
436-
func_id == BPF_FUNC_skc_lookup_tcp;
436+
func_id == BPF_FUNC_skc_lookup_tcp ||
437+
func_id == BPF_FUNC_map_lookup_elem;
438+
}
439+
440+
static bool is_acquire_function(enum bpf_func_id func_id,
441+
const struct bpf_map *map)
442+
{
443+
enum bpf_map_type map_type = map ? map->map_type : BPF_MAP_TYPE_UNSPEC;
444+
445+
if (func_id == BPF_FUNC_sk_lookup_tcp ||
446+
func_id == BPF_FUNC_sk_lookup_udp ||
447+
func_id == BPF_FUNC_skc_lookup_tcp)
448+
return true;
449+
450+
if (func_id == BPF_FUNC_map_lookup_elem &&
451+
(map_type == BPF_MAP_TYPE_SOCKMAP ||
452+
map_type == BPF_MAP_TYPE_SOCKHASH))
453+
return true;
454+
455+
return false;
437456
}
438457

439458
static bool is_ptr_cast_function(enum bpf_func_id func_id)
@@ -3934,15 +3953,17 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
39343953
func_id != BPF_FUNC_sock_map_update &&
39353954
func_id != BPF_FUNC_map_delete_elem &&
39363955
func_id != BPF_FUNC_msg_redirect_map &&
3937-
func_id != BPF_FUNC_sk_select_reuseport)
3956+
func_id != BPF_FUNC_sk_select_reuseport &&
3957+
func_id != BPF_FUNC_map_lookup_elem)
39383958
goto error;
39393959
break;
39403960
case BPF_MAP_TYPE_SOCKHASH:
39413961
if (func_id != BPF_FUNC_sk_redirect_hash &&
39423962
func_id != BPF_FUNC_sock_hash_update &&
39433963
func_id != BPF_FUNC_map_delete_elem &&
39443964
func_id != BPF_FUNC_msg_redirect_hash &&
3945-
func_id != BPF_FUNC_sk_select_reuseport)
3965+
func_id != BPF_FUNC_sk_select_reuseport &&
3966+
func_id != BPF_FUNC_map_lookup_elem)
39463967
goto error;
39473968
break;
39483969
case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
@@ -4112,7 +4133,7 @@ static bool check_refcount_ok(const struct bpf_func_proto *fn, int func_id)
41124133
/* A reference acquiring function cannot acquire
41134134
* another refcounted ptr.
41144135
*/
4115-
if (is_acquire_function(func_id) && count)
4136+
if (may_be_acquire_function(func_id) && count)
41164137
return false;
41174138

41184139
/* We only support one arg being unreferenced at the moment,
@@ -4623,7 +4644,7 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
46234644
if (is_ptr_cast_function(func_id)) {
46244645
/* For release_reference() */
46254646
regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
4626-
} else if (is_acquire_function(func_id)) {
4647+
} else if (is_acquire_function(func_id, meta.map_ptr)) {
46274648
int id = acquire_reference_state(env, insn_idx);
46284649

46294650
if (id < 0)
@@ -6532,12 +6553,16 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state,
65326553
if (is_null) {
65336554
reg->type = SCALAR_VALUE;
65346555
} else if (reg->type == PTR_TO_MAP_VALUE_OR_NULL) {
6535-
if (reg->map_ptr->inner_map_meta) {
6556+
const struct bpf_map *map = reg->map_ptr;
6557+
6558+
if (map->inner_map_meta) {
65366559
reg->type = CONST_PTR_TO_MAP;
6537-
reg->map_ptr = reg->map_ptr->inner_map_meta;
6538-
} else if (reg->map_ptr->map_type ==
6539-
BPF_MAP_TYPE_XSKMAP) {
6560+
reg->map_ptr = map->inner_map_meta;
6561+
} else if (map->map_type == BPF_MAP_TYPE_XSKMAP) {
65406562
reg->type = PTR_TO_XDP_SOCK;
6563+
} else if (map->map_type == BPF_MAP_TYPE_SOCKMAP ||
6564+
map->map_type == BPF_MAP_TYPE_SOCKHASH) {
6565+
reg->type = PTR_TO_SOCKET;
65416566
} else {
65426567
reg->type = PTR_TO_MAP_VALUE;
65436568
}

net/core/filter.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8712,6 +8712,10 @@ BPF_CALL_4(sk_select_reuseport, struct sk_reuseport_kern *, reuse_kern,
87128712

87138713
reuse = rcu_dereference(selected_sk->sk_reuseport_cb);
87148714
if (!reuse) {
8715+
/* Lookup in sock_map can return TCP ESTABLISHED sockets. */
8716+
if (sk_is_refcounted(selected_sk))
8717+
sock_put(selected_sk);
8718+
87158719
/* reuseport_array has only sk with non NULL sk_reuseport_cb.
87168720
* The only (!reuse) case here is - the sk has already been
87178721
* unhashed (e.g. by close()), so treat it as -ENOENT.

net/core/sock_map.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,14 @@ static struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
343343

344344
static void *sock_map_lookup(struct bpf_map *map, void *key)
345345
{
346-
return __sock_map_lookup_elem(map, *(u32 *)key);
346+
struct sock *sk;
347+
348+
sk = __sock_map_lookup_elem(map, *(u32 *)key);
349+
if (!sk || !sk_fullsock(sk))
350+
return NULL;
351+
if (sk_is_refcounted(sk) && !refcount_inc_not_zero(&sk->sk_refcnt))
352+
return NULL;
353+
return sk;
347354
}
348355

349356
static void *sock_map_lookup_sys(struct bpf_map *map, void *key)
@@ -1051,7 +1058,14 @@ static void *sock_hash_lookup_sys(struct bpf_map *map, void *key)
10511058

10521059
static void *sock_hash_lookup(struct bpf_map *map, void *key)
10531060
{
1054-
return __sock_hash_lookup_elem(map, key);
1061+
struct sock *sk;
1062+
1063+
sk = __sock_hash_lookup_elem(map, key);
1064+
if (!sk || !sk_fullsock(sk))
1065+
return NULL;
1066+
if (sk_is_refcounted(sk) && !refcount_inc_not_zero(&sk->sk_refcnt))
1067+
return NULL;
1068+
return sk;
10551069
}
10561070

10571071
static void sock_hash_release_progs(struct bpf_map *map)

0 commit comments

Comments
 (0)