af_packet: avoid a false positive warning in packet_setsockopt()
authorEric Dumazet <edumazet@google.com>
Fri, 5 Apr 2024 11:49:39 +0000 (11:49 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Apr 2024 12:19:01 +0000 (13:19 +0100)
Although the code is correct, the following line

copy_from_sockptr(&req_u.req, optval, len));

triggers this warning :

memcpy: detected field-spanning write (size 28) of single field "dst" at include/linux/sockptr.h:49 (size 16)

Refactor the code to be more explicit.

Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/packet/af_packet.c

index 18f616f487eaad0f7b31fb074e194c0479f30d77..8c6d3fbb4ed87f17c2e365810106a05fe9b8ff0c 100644 (file)
@@ -3800,28 +3800,30 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
        case PACKET_TX_RING:
        {
                union tpacket_req_u req_u;
-               int len;
 
+               ret = -EINVAL;
                lock_sock(sk);
                switch (po->tp_version) {
                case TPACKET_V1:
                case TPACKET_V2:
-                       len = sizeof(req_u.req);
+                       if (optlen < sizeof(req_u.req))
+                               break;
+                       ret = copy_from_sockptr(&req_u.req, optval,
+                                               sizeof(req_u.req)) ?
+                                               -EINVAL : 0;
                        break;
                case TPACKET_V3:
                default:
-                       len = sizeof(req_u.req3);
+                       if (optlen < sizeof(req_u.req3))
+                               break;
+                       ret = copy_from_sockptr(&req_u.req3, optval,
+                                               sizeof(req_u.req3)) ?
+                                               -EINVAL : 0;
                        break;
                }
-               if (optlen < len) {
-                       ret = -EINVAL;
-               } else {
-                       if (copy_from_sockptr(&req_u.req, optval, len))
-                               ret = -EFAULT;
-                       else
-                               ret = packet_set_ring(sk, &req_u, 0,
-                                                   optname == PACKET_TX_RING);
-               }
+               if (!ret)
+                       ret = packet_set_ring(sk, &req_u, 0,
+                                             optname == PACKET_TX_RING);
                release_sock(sk);
                return ret;
        }