diff options
| author | Willem de Bruijn <willemb@google.com> | 2019-04-29 11:53:18 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2019-05-01 11:28:35 -0400 |
| commit | 486efdc8f6ce802b27e15921d2353cc740c55451 (patch) | |
| tree | 38f6396a1f53717bdd1247a75abb4e632fe2e2ea | |
| parent | b2cf86e1563e33a14a1c69b3e508d15dc12f804c (diff) | |
packet: validate msg_namelen in send directly
Packet sockets in datagram mode take a destination address. Verify its
length before passing to dev_hard_header.
Prior to 2.6.14-rc3, the send code ignored sll_halen. This is
established behavior. Directly compare msg_namelen to dev->addr_len.
Change v1->v2: initialize addr in all paths
Fixes: 6b8d95f1795c4 ("packet: validate address length if non-zero")
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>
| -rw-r--r-- | net/packet/af_packet.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7d361cd53ad5..9b81813dd16a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -2602,8 +2602,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2602 | void *ph; | 2602 | void *ph; |
| 2603 | DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name); | 2603 | DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name); |
| 2604 | bool need_wait = !(msg->msg_flags & MSG_DONTWAIT); | 2604 | bool need_wait = !(msg->msg_flags & MSG_DONTWAIT); |
| 2605 | unsigned char *addr = NULL; | ||
| 2605 | int tp_len, size_max; | 2606 | int tp_len, size_max; |
| 2606 | unsigned char *addr; | ||
| 2607 | void *data; | 2607 | void *data; |
| 2608 | int len_sum = 0; | 2608 | int len_sum = 0; |
| 2609 | int status = TP_STATUS_AVAILABLE; | 2609 | int status = TP_STATUS_AVAILABLE; |
| @@ -2614,7 +2614,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2614 | if (likely(saddr == NULL)) { | 2614 | if (likely(saddr == NULL)) { |
| 2615 | dev = packet_cached_dev_get(po); | 2615 | dev = packet_cached_dev_get(po); |
| 2616 | proto = po->num; | 2616 | proto = po->num; |
| 2617 | addr = NULL; | ||
| 2618 | } else { | 2617 | } else { |
| 2619 | err = -EINVAL; | 2618 | err = -EINVAL; |
| 2620 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) | 2619 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) |
| @@ -2624,10 +2623,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
| 2624 | sll_addr))) | 2623 | sll_addr))) |
| 2625 | goto out; | 2624 | goto out; |
| 2626 | proto = saddr->sll_protocol; | 2625 | proto = saddr->sll_protocol; |
| 2627 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; | ||
| 2628 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); | 2626 | dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); |
| 2629 | if (addr && dev && saddr->sll_halen < dev->addr_len) | 2627 | if (po->sk.sk_socket->type == SOCK_DGRAM) { |
| 2630 | goto out_put; | 2628 | if (dev && msg->msg_namelen < dev->addr_len + |
| 2629 | offsetof(struct sockaddr_ll, sll_addr)) | ||
| 2630 | goto out_put; | ||
| 2631 | addr = saddr->sll_addr; | ||
| 2632 | } | ||
| 2631 | } | 2633 | } |
| 2632 | 2634 | ||
| 2633 | err = -ENXIO; | 2635 | err = -ENXIO; |
| @@ -2799,7 +2801,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2799 | struct sk_buff *skb; | 2801 | struct sk_buff *skb; |
| 2800 | struct net_device *dev; | 2802 | struct net_device *dev; |
| 2801 | __be16 proto; | 2803 | __be16 proto; |
| 2802 | unsigned char *addr; | 2804 | unsigned char *addr = NULL; |
| 2803 | int err, reserve = 0; | 2805 | int err, reserve = 0; |
| 2804 | struct sockcm_cookie sockc; | 2806 | struct sockcm_cookie sockc; |
| 2805 | struct virtio_net_hdr vnet_hdr = { 0 }; | 2807 | struct virtio_net_hdr vnet_hdr = { 0 }; |
| @@ -2816,7 +2818,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2816 | if (likely(saddr == NULL)) { | 2818 | if (likely(saddr == NULL)) { |
| 2817 | dev = packet_cached_dev_get(po); | 2819 | dev = packet_cached_dev_get(po); |
| 2818 | proto = po->num; | 2820 | proto = po->num; |
| 2819 | addr = NULL; | ||
| 2820 | } else { | 2821 | } else { |
| 2821 | err = -EINVAL; | 2822 | err = -EINVAL; |
| 2822 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) | 2823 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) |
| @@ -2824,10 +2825,13 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
| 2824 | if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) | 2825 | if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) |
| 2825 | goto out; | 2826 | goto out; |
| 2826 | proto = saddr->sll_protocol; | 2827 | proto = saddr->sll_protocol; |
| 2827 | addr = saddr->sll_halen ? saddr->sll_addr : NULL; | ||
| 2828 | dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); | 2828 | dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); |
| 2829 | if (addr && dev && saddr->sll_halen < dev->addr_len) | 2829 | if (sock->type == SOCK_DGRAM) { |
| 2830 | goto out_unlock; | 2830 | if (dev && msg->msg_namelen < dev->addr_len + |
| 2831 | offsetof(struct sockaddr_ll, sll_addr)) | ||
| 2832 | goto out_unlock; | ||
| 2833 | addr = saddr->sll_addr; | ||
| 2834 | } | ||
| 2831 | } | 2835 | } |
| 2832 | 2836 | ||
| 2833 | err = -ENXIO; | 2837 | err = -ENXIO; |
