packet: in recvmsg msg_name return at least sizeof sockaddr_ll [Linux 5.1]

packet: in recvmsg msg_name return at least sizeof sockaddr_ll [Linux 5.1]

This Linux kernel change "packet: in recvmsg msg_name return at least sizeof sockaddr_ll" is included in the Linux 5.1 release. This change is authored by Willem de Bruijn <willemb [at] google.com> on Mon Apr 29 11:46:55 2019 -0400. The commit for this change in Linux stable tree is b2cf86e (patch).

packet: in recvmsg msg_name return at least sizeof sockaddr_ll

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 <[email protected]>
Signed-off-by: Willem de Bruijn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>

There are 13 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 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 9419c5c..7d361cd 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3344,20 +3344,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) {

Leave a Reply

Your email address will not be published. Required fields are marked *