[kernel] CVE-2014-2568 net: potential info leak when ubuf backed skbs are zero copied (rhbz 1079012 1079013)

Josh Boyer jwboyer at fedoraproject.org
Fri Mar 28 15:10:55 UTC 2014


commit 0fc5fab4f779681b264247626aa10004858ad556
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Fri Mar 28 11:04:39 2014 -0400

    CVE-2014-2568 net: potential info leak when ubuf backed skbs are zero copied (rhbz 1079012 1079013)

 ...n-frags-in-skb_zerocopy-and-handle-errors.patch |  163 ++++++++++++++++++++
 kernel.spec                                        |    9 +
 2 files changed, 172 insertions(+), 0 deletions(-)
---
diff --git a/core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch b/core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch
new file mode 100644
index 0000000..804f3a9
--- /dev/null
+++ b/core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch
@@ -0,0 +1,163 @@
+Bugzilla: 1079013
+Upstream-status: Queued in netdev tree
+
+From 36d5fe6a000790f56039afe26834265db0a3ad4c Mon Sep 17 00:00:00 2001
+From: Zoltan Kiss <zoltan.kiss at citrix.com>
+Date: Wed, 26 Mar 2014 22:37:45 +0000
+Subject: core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle
+ errors
+
+skb_zerocopy can copy elements of the frags array between skbs, but it doesn't
+orphan them. Also, it doesn't handle errors, so this patch takes care of that
+as well, and modify the callers accordingly. skb_tx_error() is also added to
+the callers so they will signal the failed delivery towards the creator of the
+skb.
+
+Signed-off-by: Zoltan Kiss <zoltan.kiss at citrix.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 5e1e6f2..15ede6a 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2451,8 +2451,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
+ 		    unsigned int flags);
+ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
+ unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
+-void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
+-		  int len, int hlen);
++int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
++		 int len, int hlen);
+ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
+ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
+ void skb_scrub_packet(struct sk_buff *skb, bool xnet);
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 869c7af..97e5a2c 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -2127,25 +2127,31 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
+  *
+  *	The `hlen` as calculated by skb_zerocopy_headlen() specifies the
+  *	headroom in the `to` buffer.
++ *
++ *	Return value:
++ *	0: everything is OK
++ *	-ENOMEM: couldn't orphan frags of @from due to lack of memory
++ *	-EFAULT: skb_copy_bits() found some problem with skb geometry
+  */
+-void
+-skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
++int
++skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
+ {
+ 	int i, j = 0;
+ 	int plen = 0; /* length of skb->head fragment */
++	int ret;
+ 	struct page *page;
+ 	unsigned int offset;
+ 
+ 	BUG_ON(!from->head_frag && !hlen);
+ 
+ 	/* dont bother with small payloads */
+-	if (len <= skb_tailroom(to)) {
+-		skb_copy_bits(from, 0, skb_put(to, len), len);
+-		return;
+-	}
++	if (len <= skb_tailroom(to))
++		return skb_copy_bits(from, 0, skb_put(to, len), len);
+ 
+ 	if (hlen) {
+-		skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
++		ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
++		if (unlikely(ret))
++			return ret;
+ 		len -= hlen;
+ 	} else {
+ 		plen = min_t(int, skb_headlen(from), len);
+@@ -2163,6 +2169,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+ 	to->len += len + plen;
+ 	to->data_len += len + plen;
+ 
++	if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
++		skb_tx_error(from);
++		return -ENOMEM;
++	}
++
+ 	for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
+ 		if (!len)
+ 			break;
+@@ -2173,6 +2184,8 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+ 		j++;
+ 	}
+ 	skb_shinfo(to)->nr_frags = j;
++
++	return 0;
+ }
+ EXPORT_SYMBOL_GPL(skb_zerocopy);
+ 
+diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
+index f072fe8..108120f 100644
+--- a/net/netfilter/nfnetlink_queue_core.c
++++ b/net/netfilter/nfnetlink_queue_core.c
+@@ -354,13 +354,16 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
+ 
+ 	skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
+ 				  GFP_ATOMIC);
+-	if (!skb)
++	if (!skb) {
++		skb_tx_error(entskb);
+ 		return NULL;
++	}
+ 
+ 	nlh = nlmsg_put(skb, 0, 0,
+ 			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
+ 			sizeof(struct nfgenmsg), 0);
+ 	if (!nlh) {
++		skb_tx_error(entskb);
+ 		kfree_skb(skb);
+ 		return NULL;
+ 	}
+@@ -488,13 +491,15 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
+ 		nla->nla_type = NFQA_PAYLOAD;
+ 		nla->nla_len = nla_attr_size(data_len);
+ 
+-		skb_zerocopy(skb, entskb, data_len, hlen);
++		if (skb_zerocopy(skb, entskb, data_len, hlen))
++			goto nla_put_failure;
+ 	}
+ 
+ 	nlh->nlmsg_len = skb->len;
+ 	return skb;
+ 
+ nla_put_failure:
++	skb_tx_error(entskb);
+ 	kfree_skb(skb);
+ 	net_err_ratelimited("nf_queue: error creating packet message\n");
+ 	return NULL;
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 8601b32..270b77d 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -464,7 +464,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 	}
+ 	nla->nla_len = nla_attr_size(skb->len);
+ 
+-	skb_zerocopy(user_skb, skb, skb->len, hlen);
++	err = skb_zerocopy(user_skb, skb, skb->len, hlen);
++	if (err)
++		goto out;
+ 
+ 	/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
+ 	if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
+@@ -478,6 +480,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 
+ 	err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
+ out:
++	if (err)
++		skb_tx_error(skb);
+ 	kfree_skb(nskb);
+ 	return err;
+ }
+-- 
+cgit v0.10.1
+
diff --git a/kernel.spec b/kernel.spec
index b7cd5c0..7c78422 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -642,6 +642,9 @@ Patch25036: ppc64le_module_fix.patch
 #rhbz 1046495
 Patch25044: iwlwifi-dvm-take-mutex-when-sending-SYNC-BT-config-command.patch
 
+#CVE-2014-2568 rhbz 1079012 1079013
+Patch25049: core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch
+
 # END OF PATCH DEFINITIONS
 
 %endif
@@ -1289,6 +1292,9 @@ ApplyPatch ppc64le_module_fix.patch
 #rhbz 1046495
 ApplyPatch iwlwifi-dvm-take-mutex-when-sending-SYNC-BT-config-command.patch
 
+#CVE-2014-2568 rhbz 1079012 1079013
+ApplyPatch core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2068,6 +2074,9 @@ fi
 #                                    ||----w |
 #                                    ||     ||
 %changelog
+* Fri Mar 28 2014 Josh Boyer <jwboyer at fedoraproject.org>
+- CVE-2014-2568 net: potential info leak when ubuf backed skbs are zero copied (rhbz 1079012 1079013)
+
 * Fri Mar 28 2014 Josh Boyer <jwboyer at fedoraproject.org> - 3.14.0-0.rc8.git1.1
 - Linux v3.14-rc8-12-g75c5a52
 - Reenable debugging options.


More information about the scm-commits mailing list