Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33b7f028 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'transport-header'



Jason Wang says:

====================
We don't set transport header for untrusted packets in the past, but for the
follwoing reasons, we need to do it now.

- Better packet length estimation (introduced in 1def9238) needs l4 header for
  gso packets to compute the header length.
- Some driver needs l4 header (e.g. ixgbe needs tcp header to do atr).

So this patches tries to set transport header for packets from untrusted source
(netback, packet, tuntap, macvtap). Plus a fix for better estimation on packet
length for DODGY packet.

Tested on tun/macvtap/packet, compile test on netback.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a88b9ce5 15e5a030
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <net/rtnetlink.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
#include <net/sock.h>
#include <linux/virtio_net.h>
#include <linux/virtio_net.h>
#include <net/flow_keys.h>


/*
/*
 * A macvtap queue is the central object of this driver, it connects
 * A macvtap queue is the central object of this driver, it connects
@@ -645,6 +646,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
	int vnet_hdr_len = 0;
	int vnet_hdr_len = 0;
	int copylen = 0;
	int copylen = 0;
	bool zerocopy = false;
	bool zerocopy = false;
	struct flow_keys keys;


	if (q->flags & IFF_VNET_HDR) {
	if (q->flags & IFF_VNET_HDR) {
		vnet_hdr_len = q->vnet_hdr_sz;
		vnet_hdr_len = q->vnet_hdr_sz;
@@ -725,6 +727,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
			goto err_kfree;
			goto err_kfree;
	}
	}


	if (skb->ip_summed == CHECKSUM_PARTIAL)
		skb_set_transport_header(skb, skb_checksum_start_offset(skb));
	else if (skb_flow_dissect(skb, &keys))
		skb_set_transport_header(skb, keys.thoff);
	else
		skb_set_transport_header(skb, ETH_HLEN);

	rcu_read_lock_bh();
	rcu_read_lock_bh();
	vlan = rcu_dereference_bh(q->vlan);
	vlan = rcu_dereference_bh(q->vlan);
	/* copy skb_ubuf_info for callback when skb has no error */
	/* copy skb_ubuf_info for callback when skb has no error */
+10 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,7 @@
#include <net/sock.h>
#include <net/sock.h>


#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <net/flow_keys.h>


/* Uncomment to enable debugging */
/* Uncomment to enable debugging */
/* #define TUN_DEBUG 1 */
/* #define TUN_DEBUG 1 */
@@ -1049,6 +1050,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
	bool zerocopy = false;
	bool zerocopy = false;
	int err;
	int err;
	u32 rxhash;
	u32 rxhash;
	struct flow_keys keys;


	if (!(tun->flags & TUN_NO_PI)) {
	if (!(tun->flags & TUN_NO_PI)) {
		if ((len -= sizeof(pi)) > total_len)
		if ((len -= sizeof(pi)) > total_len)
@@ -1203,6 +1205,14 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
	}
	}


	skb_reset_network_header(skb);
	skb_reset_network_header(skb);

	if (skb->ip_summed == CHECKSUM_PARTIAL)
		skb_set_transport_header(skb, skb_checksum_start_offset(skb));
	else if (skb_flow_dissect(skb, &keys))
		skb_set_transport_header(skb, keys.thoff);
	else
		skb_reset_transport_header(skb);

	rxhash = skb_get_rxhash(skb);
	rxhash = skb_get_rxhash(skb);
	netif_rx_ni(skb);
	netif_rx_ni(skb);


+12 −0
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@
#include <linux/udp.h>
#include <linux/udp.h>


#include <net/tcp.h>
#include <net/tcp.h>
#include <net/flow_keys.h>


#include <xen/xen.h>
#include <xen/xen.h>
#include <xen/events.h>
#include <xen/events.h>
@@ -1184,6 +1185,7 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
	if (th >= skb_tail_pointer(skb))
	if (th >= skb_tail_pointer(skb))
		goto out;
		goto out;


	skb_set_transport_header(skb, 4 * iph->ihl);
	skb->csum_start = th - skb->head;
	skb->csum_start = th - skb->head;
	switch (iph->protocol) {
	switch (iph->protocol) {
	case IPPROTO_TCP:
	case IPPROTO_TCP:
@@ -1495,6 +1497,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)


		skb->dev      = vif->dev;
		skb->dev      = vif->dev;
		skb->protocol = eth_type_trans(skb, skb->dev);
		skb->protocol = eth_type_trans(skb, skb->dev);
		skb_reset_network_header(skb);


		if (checksum_setup(vif, skb)) {
		if (checksum_setup(vif, skb)) {
			netdev_dbg(vif->dev,
			netdev_dbg(vif->dev,
@@ -1503,6 +1506,15 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
			continue;
			continue;
		}
		}


		if (!skb_transport_header_was_set(skb)) {
			struct flow_keys keys;

			if (skb_flow_dissect(skb, &keys))
				skb_set_transport_header(skb, keys.thoff);
			else
				skb_reset_transport_header(skb);
		}

		vif->dev->stats.rx_bytes += skb->len;
		vif->dev->stats.rx_bytes += skb->len;
		vif->dev->stats.rx_packets++;
		vif->dev->stats.rx_packets++;


+7 −1
Original line number Original line Diff line number Diff line
@@ -2588,6 +2588,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
	 */
	 */
	if (shinfo->gso_size)  {
	if (shinfo->gso_size)  {
		unsigned int hdr_len;
		unsigned int hdr_len;
		u16 gso_segs = shinfo->gso_segs;


		/* mac layer + network layer */
		/* mac layer + network layer */
		hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
		hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
@@ -2597,7 +2598,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
			hdr_len += tcp_hdrlen(skb);
			hdr_len += tcp_hdrlen(skb);
		else
		else
			hdr_len += sizeof(struct udphdr);
			hdr_len += sizeof(struct udphdr);
		qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len;

		if (shinfo->gso_type & SKB_GSO_DODGY)
			gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
						shinfo->gso_size);

		qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
	}
	}
}
}


+21 −0
Original line number Original line Diff line number Diff line
@@ -88,6 +88,7 @@
#include <linux/virtio_net.h>
#include <linux/virtio_net.h>
#include <linux/errqueue.h>
#include <linux/errqueue.h>
#include <linux/net_tstamp.h>
#include <linux/net_tstamp.h>
#include <net/flow_keys.h>


#ifdef CONFIG_INET
#ifdef CONFIG_INET
#include <net/inet_common.h>
#include <net/inet_common.h>
@@ -1412,6 +1413,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
	__be16 proto = 0;
	__be16 proto = 0;
	int err;
	int err;
	int extra_len = 0;
	int extra_len = 0;
	struct flow_keys keys;


	/*
	/*
	 *	Get and verify the address.
	 *	Get and verify the address.
@@ -1512,6 +1514,11 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
	if (unlikely(extra_len == 4))
	if (unlikely(extra_len == 4))
		skb->no_fcs = 1;
		skb->no_fcs = 1;


	if (skb_flow_dissect(skb, &keys))
		skb_set_transport_header(skb, keys.thoff);
	else
		skb_reset_transport_header(skb);

	dev_queue_xmit(skb);
	dev_queue_xmit(skb);
	rcu_read_unlock();
	rcu_read_unlock();
	return len;
	return len;
@@ -1918,6 +1925,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
	struct page *page;
	struct page *page;
	void *data;
	void *data;
	int err;
	int err;
	struct flow_keys keys;


	ph.raw = frame;
	ph.raw = frame;


@@ -1943,6 +1951,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
	skb_reserve(skb, hlen);
	skb_reserve(skb, hlen);
	skb_reset_network_header(skb);
	skb_reset_network_header(skb);


	if (skb_flow_dissect(skb, &keys))
		skb_set_transport_header(skb, keys.thoff);
	else
		skb_reset_transport_header(skb);

	if (po->tp_tx_has_off) {
	if (po->tp_tx_has_off) {
		int off_min, off_max, off;
		int off_min, off_max, off;
		off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
		off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2199,6 +2212,7 @@ static int packet_snd(struct socket *sock,
	unsigned short gso_type = 0;
	unsigned short gso_type = 0;
	int hlen, tlen;
	int hlen, tlen;
	int extra_len = 0;
	int extra_len = 0;
	struct flow_keys keys;


	/*
	/*
	 *	Get and verify the address.
	 *	Get and verify the address.
@@ -2351,6 +2365,13 @@ static int packet_snd(struct socket *sock,
		len += vnet_hdr_len;
		len += vnet_hdr_len;
	}
	}


	if (skb->ip_summed == CHECKSUM_PARTIAL)
		skb_set_transport_header(skb, skb_checksum_start_offset(skb));
	else if (skb_flow_dissect(skb, &keys))
		skb_set_transport_header(skb, keys.thoff);
	else
		skb_set_transport_header(skb, reserve);

	if (unlikely(extra_len == 4))
	if (unlikely(extra_len == 4))
		skb->no_fcs = 1;
		skb->no_fcs = 1;