]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net/packet: convert po->origdev to an atomic flag
authorEric Dumazet <edumazet@google.com>
Thu, 16 Mar 2023 01:10:07 +0000 (01:10 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 May 2023 09:35:41 +0000 (11:35 +0200)
[ Upstream commit ee5675ecdf7a4e713ed21d98a70c2871d6ebed01 ]

syzbot/KCAN reported that po->origdev can be read
while another thread is changing its value.

We can avoid this splat by converting this field
to an actual bit.

Following patches will convert remaining 1bit fields.

Fixes: 3dc15cc8ffbb ("[AF_PACKET]: Add option to return orig_dev to userspace.")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/packet/af_packet.c
net/packet/diag.c
net/packet/internal.h

index 8636e74557ec2f2d2781ca8c6a1050308c781612..0e88a8dd4530f8418a9c9411818125cdeeb2d76c 100644 (file)
@@ -2125,7 +2125,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
        sll = &PACKET_SKB_CB(skb)->sa.ll;
        sll->sll_hatype = dev->type;
        sll->sll_pkttype = skb->pkt_type;
-       if (unlikely(po->origdev))
+       if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
                sll->sll_ifindex = orig_dev->ifindex;
        else
                sll->sll_ifindex = dev->ifindex;
@@ -2393,7 +2393,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        sll->sll_hatype = dev->type;
        sll->sll_protocol = skb->protocol;
        sll->sll_pkttype = skb->pkt_type;
-       if (unlikely(po->origdev))
+       if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
                sll->sll_ifindex = orig_dev->ifindex;
        else
                sll->sll_ifindex = dev->ifindex;
@@ -3853,9 +3853,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
-               lock_sock(sk);
-               po->origdev = !!val;
-               release_sock(sk);
+               packet_sock_flag_set(po, PACKET_SOCK_ORIGDEV, val);
                return 0;
        }
        case PACKET_VNET_HDR:
@@ -4007,7 +4005,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
                val = po->auxdata;
                break;
        case PACKET_ORIGDEV:
-               val = po->origdev;
+               val = packet_sock_flag(po, PACKET_SOCK_ORIGDEV);
                break;
        case PACKET_VNET_HDR:
                val = po->has_vnet_hdr;
index 07812ae5ca073e0c7622034939c1b7eeb378d567..e1ac9bb375b313dbb4af9a4f9aa3cf5fe7e0f47e 100644 (file)
@@ -25,7 +25,7 @@ static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
                pinfo.pdi_flags |= PDI_RUNNING;
        if (po->auxdata)
                pinfo.pdi_flags |= PDI_AUXDATA;
-       if (po->origdev)
+       if (packet_sock_flag(po, PACKET_SOCK_ORIGDEV))
                pinfo.pdi_flags |= PDI_ORIGDEV;
        if (po->has_vnet_hdr)
                pinfo.pdi_flags |= PDI_VNETHDR;
index 907f4cd2a7188e4258c3144cdf5c1ff0d96288ca..23649010e9586e317771ba638825b06392326a0b 100644 (file)
@@ -115,9 +115,9 @@ struct packet_sock {
        int                     copy_thresh;
        spinlock_t              bind_lock;
        struct mutex            pg_vec_lock;
+       unsigned long           flags;
        unsigned int            running;        /* bind_lock must be held */
        unsigned int            auxdata:1,      /* writer must hold sock lock */
-                               origdev:1,
                                has_vnet_hdr:1,
                                tp_loss:1,
                                tp_tx_has_off:1;
@@ -143,4 +143,24 @@ static struct packet_sock *pkt_sk(struct sock *sk)
        return (struct packet_sock *)sk;
 }
 
+enum packet_sock_flags {
+       PACKET_SOCK_ORIGDEV,
+};
+
+static inline void packet_sock_flag_set(struct packet_sock *po,
+                                       enum packet_sock_flags flag,
+                                       bool val)
+{
+       if (val)
+               set_bit(flag, &po->flags);
+       else
+               clear_bit(flag, &po->flags);
+}
+
+static inline bool packet_sock_flag(const struct packet_sock *po,
+                                   enum packet_sock_flags flag)
+{
+       return test_bit(flag, &po->flags);
+}
+
 #endif