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