Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…/git/bpf/bpf

Daniel Borkmann says:

====================
pull-request: bpf 2023-11-30

We've added 5 non-merge commits during the last 7 day(s) which contain
a total of 10 files changed, 66 insertions(+), 15 deletions(-).

The main changes are:

1) Fix AF_UNIX splat from use after free in BPF sockmap,
   from John Fastabend.

2) Fix a syzkaller splat in netdevsim by properly handling offloaded
   programs (and not device-bound ones), from Stanislav Fomichev.

3) Fix bpf_mem_cache_alloc_flags() to initialize the allocation hint,
   from Hou Tao.

4) Fix netkit by rejecting IFLA_NETKIT_PEER_INFO in changelink,
   from Daniel Borkmann.

* tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf:
  bpf, sockmap: Add af_unix test with both sockets in map
  bpf, sockmap: af_unix stream sockets need to hold ref for pair sock
  netkit: Reject IFLA_NETKIT_PEER_INFO in netkit_change_link
  bpf: Add missed allocation hint for bpf_mem_cache_alloc_flags()
  netdevsim: Don't accept device bound programs
====================

Link: https://lore.kernel.org/r/20231129234916.16128-1-daniel@iogearbox.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Nov 30, 2023
2 parents 83f2df9 + 51354f7 commit 0d47fa5
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 15 deletions.
4 changes: 2 additions & 2 deletions drivers/net/netdevsim/bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ static void nsim_prog_set_loaded(struct bpf_prog *prog, bool loaded)
{
struct nsim_bpf_bound_prog *state;

if (!prog || !prog->aux->offload)
if (!prog || !bpf_prog_is_offloaded(prog->aux))
return;

state = prog->aux->offload->dev_priv;
Expand Down Expand Up @@ -311,7 +311,7 @@ nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
if (!bpf->prog)
return 0;

if (!bpf->prog->aux->offload) {
if (!bpf_prog_is_offloaded(bpf->prog->aux)) {
NSIM_EA(bpf->extack, "xdpoffload of non-bound program");
return -EINVAL;
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/netkit.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,12 @@ static int netkit_change_link(struct net_device *dev, struct nlattr *tb[],
return -EACCES;
}

if (data[IFLA_NETKIT_PEER_INFO]) {
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_NETKIT_PEER_INFO],
"netkit peer info cannot be changed after device creation");
return -EINVAL;
}

if (data[IFLA_NETKIT_POLICY]) {
attr = data[IFLA_NETKIT_POLICY];
policy = nla_get_u32(attr);
Expand Down
1 change: 1 addition & 0 deletions include/linux/skmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct sk_psock {
struct mutex work_mutex;
struct sk_psock_work_state work_state;
struct delayed_work work;
struct sock *sk_pair;
struct rcu_work rwork;
};

Expand Down
1 change: 1 addition & 0 deletions include/net/af_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct unix_sock {
};

#define unix_sk(ptr) container_of_const(ptr, struct unix_sock, sk)
#define unix_peer(sk) (unix_sk(sk)->peer)

#define peer_wait peer_wq.wait

Expand Down
2 changes: 2 additions & 0 deletions kernel/bpf/memalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,8 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags)
memcg = get_memcg(c);
old_memcg = set_active_memcg(memcg);
ret = __alloc(c, NUMA_NO_NODE, GFP_KERNEL | __GFP_NOWARN | __GFP_ACCOUNT);
if (ret)
*(struct bpf_mem_cache **)ret = c;
set_active_memcg(old_memcg);
mem_cgroup_put(memcg);
}
Expand Down
2 changes: 2 additions & 0 deletions net/core/skmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,8 @@ static void sk_psock_destroy(struct work_struct *work)

if (psock->sk_redir)
sock_put(psock->sk_redir);
if (psock->sk_pair)
sock_put(psock->sk_pair);
sock_put(psock->sk);
kfree(psock);
}
Expand Down
2 changes: 0 additions & 2 deletions net/unix/af_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
}
#endif /* CONFIG_SECURITY_NETWORK */

#define unix_peer(sk) (unix_sk(sk)->peer)

static inline int unix_our_peer(struct sock *sk, struct sock *osk)
{
return unix_peer(osk) == sk;
Expand Down
5 changes: 5 additions & 0 deletions net/unix/unix_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,17 @@ int unix_dgram_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool re

int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
{
struct sock *sk_pair;

if (restore) {
sk->sk_write_space = psock->saved_write_space;
sock_replace_proto(sk, psock->sk_proto);
return 0;
}

sk_pair = unix_peer(sk);
sock_hold(sk_pair);
psock->sk_pair = sk_pair;
unix_stream_bpf_check_needs_rebuild(psock->sk_proto);
sock_replace_proto(sk, &unix_stream_bpf_prot);
return 0;
Expand Down
51 changes: 40 additions & 11 deletions tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,8 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map,
}

static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1,
int sock_mapfd, int verd_mapfd, enum redir_mode mode)
int sock_mapfd, int nop_mapfd,
int verd_mapfd, enum redir_mode mode)
{
const char *log_prefix = redir_mode_str(mode);
unsigned int pass;
Expand All @@ -1351,6 +1352,12 @@ static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1,
if (err)
return;

if (nop_mapfd >= 0) {
err = add_to_sockmap(nop_mapfd, cli0, cli1);
if (err)
return;
}

n = write(cli1, "a", 1);
if (n < 0)
FAIL_ERRNO("%s: write", log_prefix);
Expand Down Expand Up @@ -1387,7 +1394,7 @@ static void unix_redir_to_connected(int sotype, int sock_mapfd,
goto close0;
c1 = sfd[0], p1 = sfd[1];

pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);

xclose(c1);
xclose(p1);
Expand Down Expand Up @@ -1677,7 +1684,7 @@ static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd,
if (err)
goto close_cli0;

pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);

xclose(c1);
xclose(p1);
Expand Down Expand Up @@ -1735,7 +1742,7 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd,
if (err)
goto close;

pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, -1, verd_mapfd, mode);

xclose(c1);
xclose(p1);
Expand Down Expand Up @@ -1770,8 +1777,10 @@ static void inet_unix_skb_redir_to_connected(struct test_sockmap_listen *skel,
xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
}

static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
int verd_mapfd, enum redir_mode mode)
static void unix_inet_redir_to_connected(int family, int type,
int sock_mapfd, int nop_mapfd,
int verd_mapfd,
enum redir_mode mode)
{
int c0, c1, p0, p1;
int sfd[2];
Expand All @@ -1785,7 +1794,8 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
goto close_cli0;
c1 = sfd[0], p1 = sfd[1];

pairs_redir_to_connected(c0, p0, c1, p1, sock_mapfd, verd_mapfd, mode);
pairs_redir_to_connected(c0, p0, c1, p1,
sock_mapfd, nop_mapfd, verd_mapfd, mode);

xclose(c1);
xclose(p1);
Expand All @@ -1799,6 +1809,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
struct bpf_map *inner_map, int family)
{
int verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
int nop_map = bpf_map__fd(skel->maps.nop_map);
int verdict_map = bpf_map__fd(skel->maps.verdict_map);
int sock_map = bpf_map__fd(inner_map);
int err;
Expand All @@ -1808,14 +1819,32 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
return;

skel->bss->test_ingress = false;
unix_inet_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map,
unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, -1, verdict_map,
REDIR_EGRESS);
unix_inet_redir_to_connected(family, SOCK_STREAM, sock_map, verdict_map,
unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, -1, verdict_map,
REDIR_EGRESS);

unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, nop_map, verdict_map,
REDIR_EGRESS);
unix_inet_redir_to_connected(family, SOCK_STREAM,
sock_map, nop_map, verdict_map,
REDIR_EGRESS);
skel->bss->test_ingress = true;
unix_inet_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map,
unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, -1, verdict_map,
REDIR_INGRESS);
unix_inet_redir_to_connected(family, SOCK_STREAM,
sock_map, -1, verdict_map,
REDIR_INGRESS);

unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, nop_map, verdict_map,
REDIR_INGRESS);
unix_inet_redir_to_connected(family, SOCK_STREAM, sock_map, verdict_map,
unix_inet_redir_to_connected(family, SOCK_STREAM,
sock_map, nop_map, verdict_map,
REDIR_INGRESS);

xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
Expand Down
7 changes: 7 additions & 0 deletions tools/testing/selftests/bpf/progs/test_sockmap_listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ struct {
__type(value, __u64);
} sock_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__uint(max_entries, 2);
__type(key, __u32);
__type(value, __u64);
} nop_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, 2);
Expand Down

0 comments on commit 0d47fa5

Please sign in to comment.