From patchwork Sat Jun 6 00:16:31 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sridhar Samudrala X-Patchwork-Id: 28404 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n560HCQb029891 for ; Sat, 6 Jun 2009 00:17:12 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752824AbZFFAQd (ORCPT ); Fri, 5 Jun 2009 20:16:33 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752806AbZFFAQc (ORCPT ); Fri, 5 Jun 2009 20:16:32 -0400 Received: from e3.ny.us.ibm.com ([32.97.182.143]:47119 "EHLO e3.ny.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752776AbZFFAQb (ORCPT ); Fri, 5 Jun 2009 20:16:31 -0400 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e3.ny.us.ibm.com (8.13.1/8.13.1) with ESMTP id n560BmWC027975; Fri, 5 Jun 2009 20:11:48 -0400 Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v9.2) with ESMTP id n560GXdE212974; Fri, 5 Jun 2009 20:16:33 -0400 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id n560GXVR018843; Fri, 5 Jun 2009 20:16:33 -0400 Received: from [9.47.18.19] (w-sridhar.beaverton.ibm.com [9.47.18.19]) by d01av04.pok.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id n560GWTR018820; Fri, 5 Jun 2009 20:16:32 -0400 Subject: [PATCH net-next 2/4] udp: Handle large UFO packets from untrusted sources From: Sridhar Samudrala To: davem@davemloft.net, netdev@vger.kernel.org, kvm@vger.kernel.org, herbert.xu@redhat.com, rusty@rustcorp.com.au Date: Fri, 05 Jun 2009 17:16:31 -0700 Message-Id: <1244247391.1526.171.camel@w-sridhar.beaverton.ibm.com> Mime-Version: 1.0 X-Mailer: Evolution 2.24.5 (2.24.5-1.fc10) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Setup partial checksum and add gso checks to handle large UFO packets from untrusted sources. Signed-off-by: Sridhar Samudrala --- include/net/udp.h | 3 +++ net/ipv4/af_inet.c | 2 ++ net/ipv4/udp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udp.c | 22 +++++++++++++++++++ 4 files changed, 87 insertions(+), 0 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/net/udp.h b/include/net/udp.h index 90e6ce5..274b764 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -207,4 +207,7 @@ extern void udp4_proc_exit(void); #endif extern void udp_init(void); + +extern int udp_v4_gso_send_check(struct sk_buff *skb); +extern struct sk_buff *udp_ufo_fragment(struct sk_buff *skb, int features); #endif /* _UDP_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index d873621..1c1ac7d 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1426,6 +1426,8 @@ static struct net_protocol tcp_protocol = { static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, + .gso_send_check = udp_v4_gso_send_check, + .gso_segment = udp_ufo_fragment, .no_policy = 1, .netns_ok = 1, }; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 8f4158d..678bdf9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1815,6 +1815,66 @@ void __init udp_init(void) sysctl_udp_wmem_min = SK_MEM_QUANTUM; } +int udp_v4_gso_send_check(struct sk_buff *skb) +{ + const struct iphdr *iph; + struct udphdr *uh; + + if (!pskb_may_pull(skb, sizeof(*uh))) + return -EINVAL; + + iph = ip_hdr(skb); + uh = udp_hdr(skb); + + uh->check = 0; + uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, IPPROTO_UDP, 0); + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + return 0; +} + +struct sk_buff *udp_ufo_fragment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct udphdr *uh; + unsigned uhlen; + unsigned int mss; + + if (!pskb_may_pull(skb, sizeof(*uh))) + goto out; + + uh = udp_hdr(skb); + uhlen = sizeof(*uh); + + __skb_pull(skb, uhlen); + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) + goto out; + + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + int type = skb_shinfo(skb)->gso_type; + + if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || + !(type & (SKB_GSO_UDP)))) + goto out; + + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); + + segs = NULL; + goto out; + } + + /* Software UFO is not yet supported */ + segs = ERR_PTR(-EPROTONOSUPPORT); + +out: + return segs; +} +EXPORT_SYMBOL(udp_ufo_fragment); + + EXPORT_SYMBOL(udp_disconnect); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_prot); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index fad0f5f..ccd42d5 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1081,9 +1081,31 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, } #endif + +static int udpv6_gso_send_check(struct sk_buff *skb) +{ + struct ipv6hdr *ipv6h; + struct udphdr *uh; + + if (!pskb_may_pull(skb, sizeof(*uh))) + return -EINVAL; + + ipv6h = ipv6_hdr(skb); + uh = udp_hdr(skb); + + uh->check = 0; + uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, IPPROTO_UDP, 0); + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + return 0; +} + static struct inet6_protocol udpv6_protocol = { .handler = udpv6_rcv, .err_handler = udpv6_err, + .gso_send_check = udpv6_gso_send_check, + .gso_segment = udp_ufo_fragment, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, };