Commit b918f7b3 authored by Michal Kubeček's avatar Michal Kubeček Committed by Luis Henriques

udp: only allow UFO for packets from SOCK_DGRAM sockets

commit acf8dd0a upstream.

If an over-MTU UDP datagram is sent through a SOCK_RAW socket to a
UFO-capable device, ip_ufo_append_data() sets skb->ip_summed to
CHECKSUM_PARTIAL unconditionally as all GSO code assumes transport layer
checksum is to be computed on segmentation. However, in this case,
skb->csum_start and skb->csum_offset are never set as raw socket
transmit path bypasses udp_send_skb() where they are usually set. As a
result, driver may access invalid memory when trying to calculate the
checksum and store the result (as observed in virtio_net driver).

Moreover, the very idea of modifying the userspace provided UDP header
is IMHO against raw socket semantics (I wasn't able to find a document
clearly stating this or the opposite, though). And while allowing
CHECKSUM_NONE in the UFO case would be more efficient, it would be a bit
too intrusive change just to handle a corner case like this. Therefore
disallowing UFO for packets from SOCK_DGRAM seems to be the best option.
Signed-off-by: default avatarMichal Kubecek <mkubecek@suse.cz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 2b4ee605
...@@ -886,7 +886,8 @@ static int __ip_append_data(struct sock *sk, ...@@ -886,7 +886,8 @@ static int __ip_append_data(struct sock *sk,
cork->length += length; cork->length += length;
if (((length > mtu) || (skb && skb_is_gso(skb))) && if (((length > mtu) || (skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) && (sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) { (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
(sk->sk_type == SOCK_DGRAM)) {
err = ip_ufo_append_data(sk, queue, getfrag, from, length, err = ip_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, transhdrlen, hh_len, fragheaderlen, transhdrlen,
maxfraglen, flags); maxfraglen, flags);
......
...@@ -1296,7 +1296,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, ...@@ -1296,7 +1296,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
if (((length > mtu) || if (((length > mtu) ||
(skb && skb_is_gso(skb))) && (skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) && (sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO)) { (rt->dst.dev->features & NETIF_F_UFO) &&
(sk->sk_type == SOCK_DGRAM)) {
err = ip6_ufo_append_data(sk, getfrag, from, length, err = ip6_ufo_append_data(sk, getfrag, from, length,
hh_len, fragheaderlen, hh_len, fragheaderlen,
transhdrlen, mtu, flags, rt); transhdrlen, mtu, flags, rt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment