Commit 0d47fa5c authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/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.netSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 83f2df9d 51354f70
...@@ -93,7 +93,7 @@ static void nsim_prog_set_loaded(struct bpf_prog *prog, bool loaded) ...@@ -93,7 +93,7 @@ static void nsim_prog_set_loaded(struct bpf_prog *prog, bool loaded)
{ {
struct nsim_bpf_bound_prog *state; struct nsim_bpf_bound_prog *state;
if (!prog || !prog->aux->offload) if (!prog || !bpf_prog_is_offloaded(prog->aux))
return; return;
state = prog->aux->offload->dev_priv; state = prog->aux->offload->dev_priv;
...@@ -311,7 +311,7 @@ nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf) ...@@ -311,7 +311,7 @@ nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
if (!bpf->prog) if (!bpf->prog)
return 0; return 0;
if (!bpf->prog->aux->offload) { if (!bpf_prog_is_offloaded(bpf->prog->aux)) {
NSIM_EA(bpf->extack, "xdpoffload of non-bound program"); NSIM_EA(bpf->extack, "xdpoffload of non-bound program");
return -EINVAL; return -EINVAL;
} }
......
...@@ -851,6 +851,12 @@ static int netkit_change_link(struct net_device *dev, struct nlattr *tb[], ...@@ -851,6 +851,12 @@ static int netkit_change_link(struct net_device *dev, struct nlattr *tb[],
return -EACCES; 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]) { if (data[IFLA_NETKIT_POLICY]) {
attr = data[IFLA_NETKIT_POLICY]; attr = data[IFLA_NETKIT_POLICY];
policy = nla_get_u32(attr); policy = nla_get_u32(attr);
......
...@@ -106,6 +106,7 @@ struct sk_psock { ...@@ -106,6 +106,7 @@ struct sk_psock {
struct mutex work_mutex; struct mutex work_mutex;
struct sk_psock_work_state work_state; struct sk_psock_work_state work_state;
struct delayed_work work; struct delayed_work work;
struct sock *sk_pair;
struct rcu_work rwork; struct rcu_work rwork;
}; };
......
...@@ -75,6 +75,7 @@ struct unix_sock { ...@@ -75,6 +75,7 @@ struct unix_sock {
}; };
#define unix_sk(ptr) container_of_const(ptr, struct unix_sock, sk) #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 #define peer_wait peer_wq.wait
......
...@@ -978,6 +978,8 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags) ...@@ -978,6 +978,8 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags)
memcg = get_memcg(c); memcg = get_memcg(c);
old_memcg = set_active_memcg(memcg); old_memcg = set_active_memcg(memcg);
ret = __alloc(c, NUMA_NO_NODE, GFP_KERNEL | __GFP_NOWARN | __GFP_ACCOUNT); 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); set_active_memcg(old_memcg);
mem_cgroup_put(memcg); mem_cgroup_put(memcg);
} }
......
...@@ -826,6 +826,8 @@ static void sk_psock_destroy(struct work_struct *work) ...@@ -826,6 +826,8 @@ static void sk_psock_destroy(struct work_struct *work)
if (psock->sk_redir) if (psock->sk_redir)
sock_put(psock->sk_redir); sock_put(psock->sk_redir);
if (psock->sk_pair)
sock_put(psock->sk_pair);
sock_put(psock->sk); sock_put(psock->sk);
kfree(psock); kfree(psock);
} }
......
...@@ -213,8 +213,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) ...@@ -213,8 +213,6 @@ static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
} }
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#define unix_peer(sk) (unix_sk(sk)->peer)
static inline int unix_our_peer(struct sock *sk, struct sock *osk) static inline int unix_our_peer(struct sock *sk, struct sock *osk)
{ {
return unix_peer(osk) == sk; return unix_peer(osk) == sk;
......
...@@ -159,12 +159,17 @@ int unix_dgram_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool re ...@@ -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) int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
{ {
struct sock *sk_pair;
if (restore) { if (restore) {
sk->sk_write_space = psock->saved_write_space; sk->sk_write_space = psock->saved_write_space;
sock_replace_proto(sk, psock->sk_proto); sock_replace_proto(sk, psock->sk_proto);
return 0; 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); unix_stream_bpf_check_needs_rebuild(psock->sk_proto);
sock_replace_proto(sk, &unix_stream_bpf_prot); sock_replace_proto(sk, &unix_stream_bpf_prot);
return 0; return 0;
......
...@@ -1337,7 +1337,8 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map, ...@@ -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, 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); const char *log_prefix = redir_mode_str(mode);
unsigned int pass; unsigned int pass;
...@@ -1351,6 +1352,12 @@ static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1, ...@@ -1351,6 +1352,12 @@ static void pairs_redir_to_connected(int cli0, int peer0, int cli1, int peer1,
if (err) if (err)
return; return;
if (nop_mapfd >= 0) {
err = add_to_sockmap(nop_mapfd, cli0, cli1);
if (err)
return;
}
n = write(cli1, "a", 1); n = write(cli1, "a", 1);
if (n < 0) if (n < 0)
FAIL_ERRNO("%s: write", log_prefix); FAIL_ERRNO("%s: write", log_prefix);
...@@ -1387,7 +1394,7 @@ static void unix_redir_to_connected(int sotype, int sock_mapfd, ...@@ -1387,7 +1394,7 @@ static void unix_redir_to_connected(int sotype, int sock_mapfd,
goto close0; goto close0;
c1 = sfd[0], p1 = sfd[1]; 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(c1);
xclose(p1); xclose(p1);
...@@ -1677,7 +1684,7 @@ static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd, ...@@ -1677,7 +1684,7 @@ static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd,
if (err) if (err)
goto close_cli0; 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(c1);
xclose(p1); xclose(p1);
...@@ -1735,7 +1742,7 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd, ...@@ -1735,7 +1742,7 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd,
if (err) if (err)
goto close; 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(c1);
xclose(p1); xclose(p1);
...@@ -1770,8 +1777,10 @@ static void inet_unix_skb_redir_to_connected(struct test_sockmap_listen *skel, ...@@ -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); xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
} }
static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd, static void unix_inet_redir_to_connected(int family, int type,
int verd_mapfd, enum redir_mode mode) int sock_mapfd, int nop_mapfd,
int verd_mapfd,
enum redir_mode mode)
{ {
int c0, c1, p0, p1; int c0, c1, p0, p1;
int sfd[2]; int sfd[2];
...@@ -1785,7 +1794,8 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd, ...@@ -1785,7 +1794,8 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
goto close_cli0; goto close_cli0;
c1 = sfd[0], p1 = sfd[1]; 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(c1);
xclose(p1); xclose(p1);
...@@ -1799,6 +1809,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel, ...@@ -1799,6 +1809,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
struct bpf_map *inner_map, int family) struct bpf_map *inner_map, int family)
{ {
int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); 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 verdict_map = bpf_map__fd(skel->maps.verdict_map);
int sock_map = bpf_map__fd(inner_map); int sock_map = bpf_map__fd(inner_map);
int err; int err;
...@@ -1808,14 +1819,32 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel, ...@@ -1808,14 +1819,32 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
return; return;
skel->bss->test_ingress = false; 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); 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); REDIR_EGRESS);
skel->bss->test_ingress = true; 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); 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); REDIR_INGRESS);
xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT);
......
...@@ -14,6 +14,13 @@ struct { ...@@ -14,6 +14,13 @@ struct {
__type(value, __u64); __type(value, __u64);
} sock_map SEC(".maps"); } 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 { struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH); __uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, 2); __uint(max_entries, 2);
......
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