Skip to content

Commit 9c42bc9

Browse files
committed
netfilter: nf_conntrack_expect: honor expectation helper field
The expectation helper field is mostly unused. As a result, the netfilter codebase relies on accessing the helper through exp->master. Always set on the expectation helper field so it can be used to reach the helper. nf_ct_expect_init() is called from packet path where the skb owns the ct object, therefore accessing exp->master for the newly created expectation is safe. This saves a lot of updates in all callsites to pass the ct object as parameter to nf_ct_expect_init(). This is a preparation patches for follow up fixes. Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent fafdd92 commit 9c42bc9

7 files changed

Lines changed: 29 additions & 12 deletions

File tree

include/net/netfilter/nf_conntrack_expect.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct nf_conntrack_expect {
4040
struct nf_conntrack_expect *this);
4141

4242
/* Helper to assign to new connection */
43-
struct nf_conntrack_helper *helper;
43+
struct nf_conntrack_helper __rcu *helper;
4444

4545
/* The conntrack of the master connection */
4646
struct nf_conn *master;

net/netfilter/nf_conntrack_broadcast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
7070
exp->expectfn = NULL;
7171
exp->flags = NF_CT_EXPECT_PERMANENT;
7272
exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
73-
exp->helper = NULL;
73+
rcu_assign_pointer(exp->helper, helper);
7474

7575
nf_ct_expect_related(exp, 0);
7676
nf_ct_expect_put(exp);

net/netfilter/nf_conntrack_expect.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,19 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
309309
}
310310
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
311311

312+
/* This function can only be used from packet path, where accessing
313+
* master's helper is safe, because the packet holds a reference on
314+
* the conntrack object. Never use it from control plane.
315+
*/
312316
void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
313317
u_int8_t family,
314318
const union nf_inet_addr *saddr,
315319
const union nf_inet_addr *daddr,
316320
u_int8_t proto, const __be16 *src, const __be16 *dst)
317321
{
322+
struct nf_conntrack_helper *helper = NULL;
323+
struct nf_conn *ct = exp->master;
324+
struct nf_conn_help *help;
318325
int len;
319326

320327
if (family == AF_INET)
@@ -325,7 +332,12 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
325332
exp->flags = 0;
326333
exp->class = class;
327334
exp->expectfn = NULL;
328-
exp->helper = NULL;
335+
336+
help = nfct_help(ct);
337+
if (help)
338+
helper = rcu_dereference(help->helper);
339+
340+
rcu_assign_pointer(exp->helper, helper);
329341
exp->tuple.src.l3num = family;
330342
exp->tuple.dst.protonum = proto;
331343

net/netfilter/nf_conntrack_h323_main.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
643643
&ct->tuplehash[!dir].tuple.src.u3,
644644
&ct->tuplehash[!dir].tuple.dst.u3,
645645
IPPROTO_TCP, NULL, &port);
646-
exp->helper = &nf_conntrack_helper_h245;
646+
rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245);
647647

648648
nathook = rcu_dereference(nfct_h323_nat_hook);
649649
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -767,7 +767,7 @@ static int expect_callforwarding(struct sk_buff *skb,
767767
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
768768
&ct->tuplehash[!dir].tuple.src.u3, &addr,
769769
IPPROTO_TCP, NULL, &port);
770-
exp->helper = nf_conntrack_helper_q931;
770+
rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
771771

772772
nathook = rcu_dereference(nfct_h323_nat_hook);
773773
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -1234,7 +1234,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
12341234
&ct->tuplehash[!dir].tuple.src.u3 : NULL,
12351235
&ct->tuplehash[!dir].tuple.dst.u3,
12361236
IPPROTO_TCP, NULL, &port);
1237-
exp->helper = nf_conntrack_helper_q931;
1237+
rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
12381238
exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
12391239

12401240
nathook = rcu_dereference(nfct_h323_nat_hook);
@@ -1306,7 +1306,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
13061306
nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
13071307
&ct->tuplehash[!dir].tuple.src.u3, &addr,
13081308
IPPROTO_UDP, NULL, &port);
1309-
exp->helper = nf_conntrack_helper_ras;
1309+
rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras);
13101310

13111311
if (nf_ct_expect_related(exp, 0) == 0) {
13121312
pr_debug("nf_ct_ras: expect RAS ");
@@ -1523,7 +1523,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
15231523
&ct->tuplehash[!dir].tuple.src.u3, &addr,
15241524
IPPROTO_TCP, NULL, &port);
15251525
exp->flags = NF_CT_EXPECT_PERMANENT;
1526-
exp->helper = nf_conntrack_helper_q931;
1526+
rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
15271527

15281528
if (nf_ct_expect_related(exp, 0) == 0) {
15291529
pr_debug("nf_ct_ras: expect Q.931 ");
@@ -1577,7 +1577,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
15771577
&ct->tuplehash[!dir].tuple.src.u3, &addr,
15781578
IPPROTO_TCP, NULL, &port);
15791579
exp->flags = NF_CT_EXPECT_PERMANENT;
1580-
exp->helper = nf_conntrack_helper_q931;
1580+
rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931);
15811581

15821582
if (nf_ct_expect_related(exp, 0) == 0) {
15831583
pr_debug("nf_ct_ras: expect Q.931 ");

net/netfilter/nf_conntrack_helper.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
399399
const struct nf_conntrack_helper *me = data;
400400
const struct nf_conntrack_helper *this;
401401

402-
if (exp->helper == me)
402+
if (rcu_access_pointer(exp->helper) == me)
403403
return true;
404404

405405
this = rcu_dereference_protected(help->helper,
@@ -421,6 +421,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
421421

422422
nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
423423
nf_ct_iterate_destroy(unhelp, me);
424+
425+
/* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
426+
* last step, this ensures rcu readers of exp->helper are done.
427+
* No need for another synchronize_rcu() here.
428+
*/
424429
}
425430
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
426431

net/netfilter/nf_conntrack_netlink.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3573,7 +3573,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
35733573

35743574
exp->class = class;
35753575
exp->master = ct;
3576-
exp->helper = helper;
3576+
rcu_assign_pointer(exp->helper, helper);
35773577
exp->tuple = *tuple;
35783578
exp->mask.src.u3 = mask->src.u3;
35793579
exp->mask.src.u.all = mask->src.u.all;

net/netfilter/nf_conntrack_sip.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
12971297
nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
12981298
saddr, &daddr, proto, NULL, &port);
12991299
exp->timeout.expires = sip_timeout * HZ;
1300-
exp->helper = helper;
1300+
rcu_assign_pointer(exp->helper, helper);
13011301
exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
13021302

13031303
hooks = rcu_dereference(nf_nat_sip_hooks);

0 commit comments

Comments
 (0)