aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2011-08-30 09:01:20 -0400
committerPatrick McHardy <kaber@trash.net>2011-08-30 09:01:20 -0400
commitc6675233f9015d3c0460c8aab53ed9b99d915c64 (patch)
tree3d1b9b71059be24fe3a35411eecc62000bba5abc /net
parent9823d9ff483af4ce8804a9eb69600ca739cd1f58 (diff)
netfilter: nf_queue: reject NF_STOLEN verdicts from userspace
A userspace listener may send (bogus) NF_STOLEN verdict, which causes skb leak. This problem was previously fixed via 64507fdbc29c3a622180378210ecea8659b14e40 (netfilter: nf_queue: fix NF_STOLEN skb leak) but this had to be reverted because NF_STOLEN can also be returned by a netfilter hook when iterating the rules in nf_reinject. Reject userspace NF_STOLEN verdict, as suggested by Michal Miroslaw. This is complementary to commit fad54440438a7c231a6ae347738423cbabc936d9 (netfilter: avoid double free in nf_reinject). Cc: Julian Anastasov <ja@ssi.bg> Cc: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/ip_queue.c11
-rw-r--r--net/ipv6/netfilter/ip6_queue.c11
-rw-r--r--net/netfilter/nfnetlink_queue.c4
3 files changed, 10 insertions, 16 deletions
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 48f7d5b4ff37..e59aabd0eae4 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -314,7 +314,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
314{ 314{
315 struct nf_queue_entry *entry; 315 struct nf_queue_entry *entry;
316 316
317 if (vmsg->value > NF_MAX_VERDICT) 317 if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN)
318 return -EINVAL; 318 return -EINVAL;
319 319
320 entry = ipq_find_dequeue_entry(vmsg->id); 320 entry = ipq_find_dequeue_entry(vmsg->id);
@@ -359,12 +359,9 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
359 break; 359 break;
360 360
361 case IPQM_VERDICT: 361 case IPQM_VERDICT:
362 if (pmsg->msg.verdict.value > NF_MAX_VERDICT) 362 status = ipq_set_verdict(&pmsg->msg.verdict,
363 status = -EINVAL; 363 len - sizeof(*pmsg));
364 else 364 break;
365 status = ipq_set_verdict(&pmsg->msg.verdict,
366 len - sizeof(*pmsg));
367 break;
368 default: 365 default:
369 status = -EINVAL; 366 status = -EINVAL;
370 } 367 }
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 87b243a25afa..e63c3972a739 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -314,7 +314,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
314{ 314{
315 struct nf_queue_entry *entry; 315 struct nf_queue_entry *entry;
316 316
317 if (vmsg->value > NF_MAX_VERDICT) 317 if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN)
318 return -EINVAL; 318 return -EINVAL;
319 319
320 entry = ipq_find_dequeue_entry(vmsg->id); 320 entry = ipq_find_dequeue_entry(vmsg->id);
@@ -359,12 +359,9 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
359 break; 359 break;
360 360
361 case IPQM_VERDICT: 361 case IPQM_VERDICT:
362 if (pmsg->msg.verdict.value > NF_MAX_VERDICT) 362 status = ipq_set_verdict(&pmsg->msg.verdict,
363 status = -EINVAL; 363 len - sizeof(*pmsg));
364 else 364 break;
365 status = ipq_set_verdict(&pmsg->msg.verdict,
366 len - sizeof(*pmsg));
367 break;
368 default: 365 default:
369 status = -EINVAL; 366 status = -EINVAL;
370 } 367 }
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 00bd475eab4b..a80b0cb03f17 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -646,8 +646,8 @@ verdicthdr_get(const struct nlattr * const nfqa[])
646 return NULL; 646 return NULL;
647 647
648 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); 648 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
649 verdict = ntohl(vhdr->verdict); 649 verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
650 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) 650 if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
651 return NULL; 651 return NULL;
652 return vhdr; 652 return vhdr;
653} 653}