Skip to content

Commit 6291b3a

Browse files
author
Florian Westphal
committed
netfilter: conntrack: convert nf_conntrack_update to netfilter verdicts
This function calls helpers that can return nf-verdicts, but then those get converted to -1/0 as thats what the caller expects. Theoretically NF_DROP could have an errno number set in the upper 24 bits of the return value. Or any of those helpers could return NF_STOLEN, which would result in use-after-free. This is fine as-is, the called functions don't do this yet. But its better to avoid possible future problems if the upcoming patchset to add NF_DROP_REASON() support gains further users, so remove the 0/-1 translation from the picture and pass the verdicts down to the caller. Signed-off-by: Florian Westphal <[email protected]>
1 parent 4d26ab0 commit 6291b3a

File tree

2 files changed

+42
-31
lines changed

2 files changed

+42
-31
lines changed

net/netfilter/nf_conntrack_core.c

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,11 +2169,11 @@ static int __nf_conntrack_update(struct net *net, struct sk_buff *skb,
21692169

21702170
dataoff = get_l4proto(skb, skb_network_offset(skb), l3num, &l4num);
21712171
if (dataoff <= 0)
2172-
return -1;
2172+
return NF_DROP;
21732173

21742174
if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num,
21752175
l4num, net, &tuple))
2176-
return -1;
2176+
return NF_DROP;
21772177

21782178
if (ct->status & IPS_SRC_NAT) {
21792179
memcpy(tuple.src.u3.all,
@@ -2193,7 +2193,7 @@ static int __nf_conntrack_update(struct net *net, struct sk_buff *skb,
21932193

21942194
h = nf_conntrack_find_get(net, nf_ct_zone(ct), &tuple);
21952195
if (!h)
2196-
return 0;
2196+
return NF_ACCEPT;
21972197

21982198
/* Store status bits of the conntrack that is clashing to re-do NAT
21992199
* mangling according to what it has been done already to this packet.
@@ -2206,19 +2206,25 @@ static int __nf_conntrack_update(struct net *net, struct sk_buff *skb,
22062206

22072207
nat_hook = rcu_dereference(nf_nat_hook);
22082208
if (!nat_hook)
2209-
return 0;
2209+
return NF_ACCEPT;
22102210

2211-
if (status & IPS_SRC_NAT &&
2212-
nat_hook->manip_pkt(skb, ct, NF_NAT_MANIP_SRC,
2213-
IP_CT_DIR_ORIGINAL) == NF_DROP)
2214-
return -1;
2211+
if (status & IPS_SRC_NAT) {
2212+
unsigned int verdict = nat_hook->manip_pkt(skb, ct,
2213+
NF_NAT_MANIP_SRC,
2214+
IP_CT_DIR_ORIGINAL);
2215+
if (verdict != NF_ACCEPT)
2216+
return verdict;
2217+
}
22152218

2216-
if (status & IPS_DST_NAT &&
2217-
nat_hook->manip_pkt(skb, ct, NF_NAT_MANIP_DST,
2218-
IP_CT_DIR_ORIGINAL) == NF_DROP)
2219-
return -1;
2219+
if (status & IPS_DST_NAT) {
2220+
unsigned int verdict = nat_hook->manip_pkt(skb, ct,
2221+
NF_NAT_MANIP_DST,
2222+
IP_CT_DIR_ORIGINAL);
2223+
if (verdict != NF_ACCEPT)
2224+
return verdict;
2225+
}
22202226

2221-
return 0;
2227+
return NF_ACCEPT;
22222228
}
22232229

22242230
/* This packet is coming from userspace via nf_queue, complete the packet
@@ -2233,14 +2239,14 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
22332239

22342240
help = nfct_help(ct);
22352241
if (!help)
2236-
return 0;
2242+
return NF_ACCEPT;
22372243

22382244
helper = rcu_dereference(help->helper);
22392245
if (!helper)
2240-
return 0;
2246+
return NF_ACCEPT;
22412247

22422248
if (!(helper->flags & NF_CT_HELPER_F_USERSPACE))
2243-
return 0;
2249+
return NF_ACCEPT;
22442250

22452251
switch (nf_ct_l3num(ct)) {
22462252
case NFPROTO_IPV4:
@@ -2255,42 +2261,44 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
22552261
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
22562262
&frag_off);
22572263
if (protoff < 0 || (frag_off & htons(~0x7)) != 0)
2258-
return 0;
2264+
return NF_ACCEPT;
22592265
break;
22602266
}
22612267
#endif
22622268
default:
2263-
return 0;
2269+
return NF_ACCEPT;
22642270
}
22652271

22662272
if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
22672273
!nf_is_loopback_packet(skb)) {
22682274
if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
22692275
NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
2270-
return -1;
2276+
return NF_DROP;
22712277
}
22722278
}
22732279

22742280
/* We've seen it coming out the other side: confirm it */
2275-
return nf_conntrack_confirm(skb) == NF_DROP ? - 1 : 0;
2281+
return nf_conntrack_confirm(skb);
22762282
}
22772283

22782284
static int nf_conntrack_update(struct net *net, struct sk_buff *skb)
22792285
{
22802286
enum ip_conntrack_info ctinfo;
22812287
struct nf_conn *ct;
2282-
int err;
22832288

22842289
ct = nf_ct_get(skb, &ctinfo);
22852290
if (!ct)
2286-
return 0;
2291+
return NF_ACCEPT;
22872292

22882293
if (!nf_ct_is_confirmed(ct)) {
2289-
err = __nf_conntrack_update(net, skb, ct, ctinfo);
2290-
if (err < 0)
2291-
return err;
2294+
int ret = __nf_conntrack_update(net, skb, ct, ctinfo);
2295+
2296+
if (ret != NF_ACCEPT)
2297+
return ret;
22922298

22932299
ct = nf_ct_get(skb, &ctinfo);
2300+
if (!ct)
2301+
return NF_ACCEPT;
22942302
}
22952303

22962304
return nf_confirm_cthelper(skb, ct, ctinfo);

net/netfilter/nfnetlink_queue.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,19 +228,22 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
228228
static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict)
229229
{
230230
const struct nf_ct_hook *ct_hook;
231-
int err;
232231

233232
if (verdict == NF_ACCEPT ||
234233
verdict == NF_REPEAT ||
235234
verdict == NF_STOP) {
236235
rcu_read_lock();
237236
ct_hook = rcu_dereference(nf_ct_hook);
238-
if (ct_hook) {
239-
err = ct_hook->update(entry->state.net, entry->skb);
240-
if (err < 0)
241-
verdict = NF_DROP;
242-
}
237+
if (ct_hook)
238+
verdict = ct_hook->update(entry->state.net, entry->skb);
243239
rcu_read_unlock();
240+
241+
switch (verdict & NF_VERDICT_MASK) {
242+
case NF_STOLEN:
243+
nf_queue_entry_free(entry);
244+
return;
245+
}
246+
244247
}
245248
nf_reinject(entry, verdict);
246249
}

0 commit comments

Comments
 (0)