nfqueue: Orphan frags in nfqnl_zcopy() and handle errors (CVE-2014-2568)

svn path=/dists/sid/linux/; revision=21190
This commit is contained in:
Ben Hutchings 2014-03-25 16:55:44 +00:00
parent 9f6a808fee
commit 1d8877c3c3
3 changed files with 107 additions and 0 deletions

1
debian/changelog vendored
View File

@ -58,6 +58,7 @@ linux (3.13.7-1) UNRELEASED; urgency=medium
[ Ben Hutchings ]
* [arm] mm: Avoid ABI change in 3.13.6 (fixes FTBFS)
* nfqueue: Orphan frags in nfqnl_zcopy() and handle errors (CVE-2014-2568)
-- Ben Hutchings <ben@decadent.org.uk> Fri, 21 Mar 2014 19:47:01 +0000

View File

@ -0,0 +1,105 @@
Subject: [v4] core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors
From: Zoltan Kiss <zoltan.kiss@citrix.com>
Date: Fri, 21 Mar 2014 10:31:34 +0000
Origin: https://patchwork.ozlabs.org/patch/332544/
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@citrix.com>
Acked-by: Thomas Graf <tgraf@redhat.com>
[bwh: skb_zerocopy() is new in 3.14, but was moved from a static function
in nfnetlink_queue. We need to patch that and its caller, but not
openvswitch.]
---
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -235,22 +235,23 @@ nfqnl_flush(struct nfqnl_instance *queue
spin_unlock_bh(&queue->lock);
}
-static void
+static int
nfqnl_zcopy(struct sk_buff *to, const 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;
/* 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);
@@ -268,6 +269,11 @@ nfqnl_zcopy(struct sk_buff *to, const st
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;
@@ -278,6 +284,8 @@ nfqnl_zcopy(struct sk_buff *to, const st
j++;
}
skb_shinfo(to)->nr_frags = j;
+
+ return 0;
}
static int
@@ -374,13 +382,16 @@ nfqnl_build_packet_message(struct net *n
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;
}
@@ -504,13 +515,15 @@ nfqnl_build_packet_message(struct net *n
nla->nla_type = NFQA_PAYLOAD;
nla->nla_len = nla_attr_size(data_len);
- nfqnl_zcopy(skb, entskb, data_len, hlen);
+ if (nfqnl_zcopy(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;

View File

@ -93,3 +93,4 @@ debian/netdev-avoid-abi-change-in-3.13.6.patch
debian/can-avoid-abi-change-in-3.13.6.patch
debian/arm-mm-avoid-abi-change-in-3.13.6.patch
debian/fireware-avoid-abi-change-in-3.13.7.patch
bugfix/all/net-core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch