On Mon, Apr 29, 2019 at 5:03 AM David Laight <david.lai...@aculab.com> wrote: > > From: Willem de Bruijn [mailto:willemdebruijn.ker...@gmail.com] > > Sent: 26 April 2019 20:30 > > 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. > > > > Fixes: 0fb375fb9b93 ("[AF_PACKET]: Allow for > 8 byte hardware addresses.") > > Suggested-by: David Laight <david.lai...@aculab.com> > > Signed-off-by: Willem de Bruijn <will...@google.com> > > --- > > net/packet/af_packet.c | 7 ++++++- > > 1 file changed, 6 insertions(+), 1 deletion(-) > > > > diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c > > index 13301e36b4a28..ca38e75c702e7 100644 > > --- a/net/packet/af_packet.c > > +++ b/net/packet/af_packet.c > > @@ -3358,9 +3358,14 @@ static int packet_recvmsg(struct socket *sock, > > struct msghdr *msg, size_t len, > > msg->msg_namelen = sizeof(struct sockaddr_pkt); > > } else { > > struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; > > - > > msg->msg_namelen = sll->sll_halen + > > offsetof(struct sockaddr_ll, sll_addr); > > + 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); > > That memcpy() carefully overwrites the zeroed bytes. > You need a separate 'copy_len' that isn't updated (from 18 to 20).
Argh. Thanks! 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); } Can then also change memset to zero only two bytes in the Ethernet case. + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) { + msg->msg_namelen = sizeof(struct sockaddr_ll); + memset(msg->msg_name + copy_len, 0, + msg->namelen - copy_len); + }