| From 17f505a8488a460918b2f53120b375e410ac3ccd Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 29 Apr 2019 11:46:55 -0400 |
| Subject: packet: in recvmsg msg_name return at least sizeof sockaddr_ll |
| |
| From: Willem de Bruijn <willemb@google.com> |
| |
| [ Upstream commit b2cf86e1563e33a14a1c69b3e508d15dc12f804c ] |
| |
| Packet send checks that msg_name is at least sizeof sockaddr_ll. |
| Packet recv must return at least this length, so that its output |
| can be passed unmodified to packet send. |
| |
| This ceased to be true since adding support for lladdr longer than |
| sll_addr. Since, the return value uses true address length. |
| |
| Always return at least sizeof sockaddr_ll, even if address length |
| is shorter. Zero the padding bytes. |
| |
| Change v1->v2: do not overwrite zeroed padding again. use copy_len. |
| |
| Fixes: 0fb375fb9b93 ("[AF_PACKET]: Allow for > 8 byte hardware addresses.") |
| Suggested-by: David Laight <David.Laight@aculab.com> |
| Signed-off-by: Willem de Bruijn <willemb@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/packet/af_packet.c | 13 +++++++++++-- |
| 1 file changed, 11 insertions(+), 2 deletions(-) |
| |
| diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c |
| index 40cade140222f..47a862cc7b349 100644 |
| --- a/net/packet/af_packet.c |
| +++ b/net/packet/af_packet.c |
| @@ -3404,20 +3404,29 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| sock_recv_ts_and_drops(msg, sk, skb); |
| |
| if (msg->msg_name) { |
| + int copy_len; |
| + |
| /* If the address length field is there to be filled |
| * in, we fill it in now. |
| */ |
| if (sock->type == SOCK_PACKET) { |
| __sockaddr_check_size(sizeof(struct sockaddr_pkt)); |
| msg->msg_namelen = sizeof(struct sockaddr_pkt); |
| + copy_len = msg->msg_namelen; |
| } else { |
| struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; |
| |
| msg->msg_namelen = sll->sll_halen + |
| offsetof(struct sockaddr_ll, sll_addr); |
| + copy_len = msg->msg_namelen; |
| + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) { |
| + memset(msg->msg_name + |
| + offsetof(struct sockaddr_ll, sll_addr), |
| + 0, sizeof(sll->sll_addr)); |
| + msg->msg_namelen = sizeof(struct sockaddr_ll); |
| + } |
| } |
| - memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, |
| - msg->msg_namelen); |
| + memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len); |
| } |
| |
| if (pkt_sk(sk)->auxdata) { |
| -- |
| 2.20.1 |
| |