af_packet: avoid a false positive warning in packet_setsockopt()

[ Upstream commit 86d43e2bf9 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Eric Dumazet 2024-04-05 11:49:39 +00:00 committed by Greg Kroah-Hartman
parent ceba8dbabd
commit 82116ea1cc

View file

@ -3799,28 +3799,30 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
case PACKET_TX_RING: case PACKET_TX_RING:
{ {
union tpacket_req_u req_u; union tpacket_req_u req_u;
int len;
ret = -EINVAL;
lock_sock(sk); lock_sock(sk);
switch (po->tp_version) { switch (po->tp_version) {
case TPACKET_V1: case TPACKET_V1:
case TPACKET_V2: 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; break;
case TPACKET_V3: case TPACKET_V3:
default: 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; break;
} }
if (optlen < len) { if (!ret)
ret = -EINVAL; ret = packet_set_ring(sk, &req_u, 0,
} else { optname == PACKET_TX_RING);
if (copy_from_sockptr(&req_u.req, optval, len))
ret = -EFAULT;
else
ret = packet_set_ring(sk, &req_u, 0,
optname == PACKET_TX_RING);
}
release_sock(sk); release_sock(sk);
return ret; return ret;
} }