From 0fc5fab4f779681b264247626aa10004858ad556 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 28 Mar 2014 11:04:39 -0400 Subject: [PATCH] CVE-2014-2568 net: potential info leak when ubuf backed skbs are zero copied (rhbz 1079012 1079013) --- ...gs-in-skb_zerocopy-and-handle-errors.patch | 163 ++++++++++++++++++ kernel.spec | 9 + 2 files changed, 172 insertions(+) create mode 100644 core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch 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 000000000..804f3a901 --- /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 +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 +Signed-off-by: David S. Miller + +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 b7cd5c09a..7c7842256 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 +- CVE-2014-2568 net: potential info leak when ubuf backed skbs are zero copied (rhbz 1079012 1079013) + * Fri Mar 28 2014 Josh Boyer - 3.14.0-0.rc8.git1.1 - Linux v3.14-rc8-12-g75c5a52 - Reenable debugging options.