]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
net-packet: fix race in packet_set_ring on PACKET_RESERVE
authorWillem de Bruijn <willemb@google.com>
Mon, 7 Aug 2017 09:15:40 +0000 (11:15 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 7 Aug 2017 16:19:59 +0000 (18:19 +0200)
PACKET_RESERVE reserves headroom in memory mapped packet ring frames.
The value po->tp_reserve must is verified to be safe in packet_set_ring

  if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve))

and the setsockopt fails once a ring is set.

  if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
          return -EBUSY;

This operation does not take the socket lock. This leads to a race
similar to the one with PACKET_VERSION fixed in commit 84ac7260236a
("packet: fix race condition in packet_set_ring").

Fix this issue in the same manner: take the socket lock, which as of
that patch is held for the duration of packet_set_ring.

This bug was discovered with syzkaller.

Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
CVE-2017-1000111

(backported from email submission)
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
net/packet/af_packet.c

index 0f074c96f43f9eff16a22c2757e7d4ddbed6c661..ebde2ef2f1229826459a87cea833a8da541321c8 100644 (file)
@@ -3640,14 +3640,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
                if (val > INT_MAX)
                        return -EINVAL;
-               po->tp_reserve = val;
-               return 0;
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
+                       ret = -EBUSY;
+               else {
+                       po->tp_reserve = val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_LOSS:
        {