Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
authorJakub Kicinski <kuba@kernel.org>
Thu, 30 Nov 2023 03:40:04 +0000 (19:40 -0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Nov 2023 03:40:04 +0000 (19:40 -0800)
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>
drivers/net/netdevsim/bpf.c
drivers/net/netkit.c
include/linux/skmsg.h
include/net/af_unix.h
kernel/bpf/memalloc.c
net/core/skmsg.c
net/unix/af_unix.c
net/unix/unix_bpf.c
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
tools/testing/selftests/bpf/progs/test_sockmap_listen.c

index f60eb97e3a627eabaafb6db0c77f4ddc39761620..608953d4f98da9f2e44b006e8187b0e445b1d38c 100644 (file)
@@ -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;
@@ -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;
        }
index 97bd6705c24117cff255ebbe34fc9efc4c0da2bd..39171380ccf29e27412bb2b9cee7102acc4a83ab 100644 (file)
@@ -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);
index c1637515a8a41613580eb6006fd17f9ad0a8733b..c953b8c0d2f4339a647b93ef0c2b8796010181b1 100644 (file)
@@ -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;
 };
 
index 824c258143a3ab360b870fda38ba684b70068eee..49c4640027d8a6b93e903a6238d21e8541e31da4 100644 (file)
@@ -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
 
index 63b909d277d47925c70215adbbc4b11b4e5ad558..6a51cfe4c2d63f573542fd918ff8276b7d3abd33 100644 (file)
@@ -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);
        }
index 6c31eefbd77786ba3651f79313af867883210654..93ecfceac1bc49bd843728518215ade5ced374a5 100644 (file)
@@ -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);
 }
index a357dc5f24046d98674da9935eccbb9e18ea4616..ac1f2bc18fc9685652c26ac3b68f19bfd82f8332 100644 (file)
@@ -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;
index 2f9d8271c6ec7df2007267d3905703c6c9686d10..7ea7c3a0d0d06224f49ad5f073bf772b9528a30a 100644 (file)
@@ -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;
index a934d430c20c130e3efbc47560bf7af64a1d1597..a92807bfcd134987417c0ea4254bf34aec1a5615 100644 (file)
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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];
@@ -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);
@@ -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;
@@ -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);
index 464d35bd57c708a748163d71089ee329a76b56e1..b7250eb9c30cca8f77675e56529e6b780d76ab2e 100644 (file)
@@ -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);