|
|
736e49f |
Bugzilla: 1079013
|
|
|
736e49f |
Upstream-status: Queued in netdev tree, backport for 3.13.y sent
|
|
|
736e49f |
|
|
|
736e49f |
From 93f7cfcac69051641d5b10325164a0f313ef5185 Mon Sep 17 00:00:00 2001
|
|
|
736e49f |
From: Josh Boyer <jwboyer@fedoraproject.org>
|
|
|
736e49f |
Date: Fri, 28 Mar 2014 09:32:19 -0400
|
|
|
736e49f |
Subject: [PATCH] nfqueue: Orphan frags in nfqnl_zcopy and handle errors
|
|
|
736e49f |
|
|
|
736e49f |
Backport of upstream commit 36d5fe6a0007 to 3.13.y
|
|
|
736e49f |
|
|
|
736e49f |
nfqnl_zcopy can copy elements of the frags array between skbs, but it doesn't
|
|
|
736e49f |
orphan them. Also, it doesn't handle errors, so this patch takes care of that
|
|
|
736e49f |
as well, and modify the caller accordingly. skb_tx_error() is also added to
|
|
|
736e49f |
the callers so they will signal the failed delivery towards the creator of the
|
|
|
736e49f |
skb.
|
|
|
736e49f |
|
|
|
736e49f |
Signed-off-by: Zoltan Kiss <zoltan.kiss@citrix.com>
|
|
|
736e49f |
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
|
736e49f |
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
|
|
|
736e49f |
---
|
|
|
736e49f |
net/netfilter/nfnetlink_queue_core.c | 31 ++++++++++++++++++++++---------
|
|
|
736e49f |
1 file changed, 22 insertions(+), 9 deletions(-)
|
|
|
736e49f |
|
|
|
736e49f |
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
|
|
|
736e49f |
index 21258cf..b241654 100644
|
|
|
736e49f |
--- a/net/netfilter/nfnetlink_queue_core.c
|
|
|
736e49f |
+++ b/net/netfilter/nfnetlink_queue_core.c
|
|
|
736e49f |
@@ -235,22 +235,23 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
|
|
|
736e49f |
spin_unlock_bh(&queue->lock);
|
|
|
736e49f |
}
|
|
|
736e49f |
|
|
|
736e49f |
-static void
|
|
|
736e49f |
-nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
|
|
|
736e49f |
+static int
|
|
|
736e49f |
+nfqnl_zcopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
|
|
|
736e49f |
{
|
|
|
736e49f |
int i, j = 0;
|
|
|
736e49f |
int plen = 0; /* length of skb->head fragment */
|
|
|
736e49f |
+ int ret;
|
|
|
736e49f |
struct page *page;
|
|
|
736e49f |
unsigned int offset;
|
|
|
736e49f |
|
|
|
736e49f |
/* dont bother with small payloads */
|
|
|
736e49f |
- if (len <= skb_tailroom(to)) {
|
|
|
736e49f |
- skb_copy_bits(from, 0, skb_put(to, len), len);
|
|
|
736e49f |
- return;
|
|
|
736e49f |
- }
|
|
|
736e49f |
+ if (len <= skb_tailroom(to))
|
|
|
736e49f |
+ return skb_copy_bits(from, 0, skb_put(to, len), len);
|
|
|
736e49f |
|
|
|
736e49f |
if (hlen) {
|
|
|
736e49f |
- skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
|
|
|
736e49f |
+ ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
|
|
|
736e49f |
+ if (unlikely(ret))
|
|
|
736e49f |
+ return ret;
|
|
|
736e49f |
len -= hlen;
|
|
|
736e49f |
} else {
|
|
|
736e49f |
plen = min_t(int, skb_headlen(from), len);
|
|
|
736e49f |
@@ -268,6 +269,11 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
|
|
|
736e49f |
to->len += len + plen;
|
|
|
736e49f |
to->data_len += len + plen;
|
|
|
736e49f |
|
|
|
736e49f |
+ if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
|
|
|
736e49f |
+ skb_tx_error(from);
|
|
|
736e49f |
+ return -ENOMEM;
|
|
|
736e49f |
+ }
|
|
|
736e49f |
+
|
|
|
736e49f |
for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
|
|
|
736e49f |
if (!len)
|
|
|
736e49f |
break;
|
|
|
736e49f |
@@ -278,6 +284,8 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
|
|
|
736e49f |
j++;
|
|
|
736e49f |
}
|
|
|
736e49f |
skb_shinfo(to)->nr_frags = j;
|
|
|
736e49f |
+
|
|
|
736e49f |
+ return 0;
|
|
|
736e49f |
}
|
|
|
736e49f |
|
|
|
736e49f |
static int
|
|
|
736e49f |
@@ -374,13 +382,16 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|
|
736e49f |
|
|
|
736e49f |
skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
|
|
|
736e49f |
GFP_ATOMIC);
|
|
|
736e49f |
- if (!skb)
|
|
|
736e49f |
+ if (!skb) {
|
|
|
736e49f |
+ skb_tx_error(entskb);
|
|
|
736e49f |
return NULL;
|
|
|
736e49f |
+ }
|
|
|
736e49f |
|
|
|
736e49f |
nlh = nlmsg_put(skb, 0, 0,
|
|
|
736e49f |
NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
|
|
|
736e49f |
sizeof(struct nfgenmsg), 0);
|
|
|
736e49f |
if (!nlh) {
|
|
|
736e49f |
+ skb_tx_error(entskb);
|
|
|
736e49f |
kfree_skb(skb);
|
|
|
736e49f |
return NULL;
|
|
|
736e49f |
}
|
|
|
736e49f |
@@ -504,13 +515,15 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|
|
736e49f |
nla->nla_type = NFQA_PAYLOAD;
|
|
|
736e49f |
nla->nla_len = nla_attr_size(data_len);
|
|
|
736e49f |
|
|
|
736e49f |
- nfqnl_zcopy(skb, entskb, data_len, hlen);
|
|
|
736e49f |
+ if (nfqnl_zcopy(skb, entskb, data_len, hlen))
|
|
|
736e49f |
+ goto nla_put_failure;
|
|
|
736e49f |
}
|
|
|
736e49f |
|
|
|
736e49f |
nlh->nlmsg_len = skb->len;
|
|
|
736e49f |
return skb;
|
|
|
736e49f |
|
|
|
736e49f |
nla_put_failure:
|
|
|
736e49f |
+ skb_tx_error(entskb);
|
|
|
736e49f |
kfree_skb(skb);
|
|
|
736e49f |
net_err_ratelimited("nf_queue: error creating packet message\n");
|
|
|
736e49f |
return NULL;
|
|
|
736e49f |
--
|
|
|
736e49f |
1.8.5.3
|
|
|
736e49f |
|