Skip to content

Commit db472c3

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-26-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter for net This is v3, I kept back an ipset fix and another to tigthen the xtables interface to reject invalid combinations with the NFPROTO_ARP family. They need a bit more discussion. I fixed the issues reported by AI on patch 9 (add #ifdef to access ct zone, update nf_conntrack_broadcast and patch 10 (use better Fixes: tag). Thanks! The following patchset contains Netfilter fixes for *net*. Note that most bugs fixed here stem from 2.6 days, the large PR is not due to an increase in regressions. 1) Fix incorrect reject of set updates with nf_tables pipapo set avx2 backend. This comes with a regression test in patch 2. From Florian Westphal. 2) nfnetlink_log needs to zero padding to prevent infoleak to userspace, from Weiming Shi. 3) xtables ip6t_rt module never validated that addrnr length is within the allowed array boundary. Reject bogus values. From Ren Wei. 4) Fix high memory usage in rbtree set backend that was unwanted side-effect of the recently added binary search blob. From Pablo Neira Ayuso. 5) Patches 5 to 10, also from Pablo, address long-standing RCU safety bugs in conntracks handling of expectations: We can never safely defer a conntrack extension area without holding a reference. Yet expectation handling does so in multiple places. Fix this by avoiding the need to look into the master conntrack to begin with and by extending locked sections in a few places. 11) Fix use of uninitialized rtp_addr in the sip conntrack helper, also from Weiming Shi. 12) Add stricter netlink policy checks in ctnetlink, from David Carlier. This avoids undefined behaviour when userspace provides huge wscale value. netfilter pull request 26-03-26 * tag 'nf-26-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: ctnetlink: use netlink policy range checks netfilter: nf_conntrack_sip: fix use of uninitialized rtp_addr in process_sdp netfilter: nf_conntrack_expect: skip expectations in other netns via proc netfilter: nf_conntrack_expect: store netns and zone in expectation netfilter: ctnetlink: ensure safe access to master conntrack netfilter: nf_conntrack_expect: use expect->helper netfilter: nf_conntrack_expect: honor expectation helper field netfilter: nft_set_rbtree: revisit array resize logic netfilter: ip6t_rt: reject oversized addrnr in rt_mt6_check() netfilter: nfnetlink_log: fix uninitialized padding leak in NFULA_PAYLOAD selftests: netfilter: nft_concat_range.sh: add check for flush+reload bug netfilter: nft_set_pipapo_avx2: don't return non-matching entry on expiry ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents deec4f7 + 8f15b50 commit db472c3

16 files changed

Lines changed: 296 additions & 102 deletions

include/net/netfilter/nf_conntrack_core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ void nf_conntrack_lock(spinlock_t *lock);
8383

8484
extern spinlock_t nf_conntrack_expect_lock;
8585

86+
static inline void lockdep_nfct_expect_lock_held(void)
87+
{
88+
lockdep_assert_held(&nf_conntrack_expect_lock);
89+
}
90+
8691
/* ctnetlink code shared by both ctnetlink and nf_conntrack_bpf */
8792

8893
static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout)

include/net/netfilter/nf_conntrack_expect.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
2222
/* Hash member */
2323
struct hlist_node hnode;
2424

25+
/* Network namespace */
26+
possible_net_t net;
27+
2528
/* We expect this tuple, with the following mask */
2629
struct nf_conntrack_tuple tuple;
2730
struct nf_conntrack_tuple_mask mask;
2831

32+
#ifdef CONFIG_NF_CONNTRACK_ZONES
33+
struct nf_conntrack_zone zone;
34+
#endif
2935
/* Usage count. */
3036
refcount_t use;
3137

@@ -40,7 +46,7 @@ struct nf_conntrack_expect {
4046
struct nf_conntrack_expect *this);
4147

4248
/* Helper to assign to new connection */
43-
struct nf_conntrack_helper *helper;
49+
struct nf_conntrack_helper __rcu *helper;
4450

4551
/* The conntrack of the master connection */
4652
struct nf_conn *master;
@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
6268

6369
static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
6470
{
65-
return nf_ct_net(exp->master);
71+
return read_pnet(&exp->net);
72+
}
73+
74+
static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
75+
const struct nf_conntrack_zone *b)
76+
{
77+
#ifdef CONFIG_NF_CONNTRACK_ZONES
78+
return a->zone.id == b->id;
79+
#else
80+
return true;
81+
#endif
6682
}
6783

6884
#define NF_CT_EXP_POLICY_NAME_LEN 16

include/uapi/linux/netfilter/nf_conntrack_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,5 +159,9 @@ enum ip_conntrack_expect_events {
159159
#define NF_CT_EXPECT_INACTIVE 0x2
160160
#define NF_CT_EXPECT_USERSPACE 0x4
161161

162+
#ifdef __KERNEL__
163+
#define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \
164+
NF_CT_EXPECT_USERSPACE)
165+
#endif
162166

163167
#endif /* _UAPI_NF_CONNTRACK_COMMON_H */

net/ipv6/netfilter/ip6t_rt.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ static int rt_mt6_check(const struct xt_mtchk_param *par)
157157
pr_debug("unknown flags %X\n", rtinfo->invflags);
158158
return -EINVAL;
159159
}
160+
if (rtinfo->addrnr > IP6T_RT_HOPS) {
161+
pr_debug("too many addresses specified\n");
162+
return -EINVAL;
163+
}
160164
if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
161165
(!(rtinfo->flags & IP6T_RT_TYP) ||
162166
(rtinfo->rt_type != 0) ||

net/netfilter/nf_conntrack_broadcast.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
2121
unsigned int timeout)
2222
{
2323
const struct nf_conntrack_helper *helper;
24+
struct net *net = read_pnet(&ct->ct_net);
2425
struct nf_conntrack_expect *exp;
2526
struct iphdr *iph = ip_hdr(skb);
2627
struct rtable *rt = skb_rtable(skb);
@@ -70,8 +71,11 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
7071
exp->expectfn = NULL;
7172
exp->flags = NF_CT_EXPECT_PERMANENT;
7273
exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
73-
exp->helper = NULL;
74-
74+
rcu_assign_pointer(exp->helper, helper);
75+
write_pnet(&exp->net, net);
76+
#ifdef CONFIG_NF_CONNTRACK_ZONES
77+
exp->zone = ct->zone;
78+
#endif
7579
nf_ct_expect_related(exp, 0);
7680
nf_ct_expect_put(exp);
7781

net/netfilter/nf_conntrack_ecache.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
247247
struct nf_ct_event_notifier *notify;
248248
struct nf_conntrack_ecache *e;
249249

250+
lockdep_nfct_expect_lock_held();
251+
250252
rcu_read_lock();
251253
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
252254
if (!notify)

net/netfilter/nf_conntrack_expect.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
5151
struct net *net = nf_ct_exp_net(exp);
5252
struct nf_conntrack_net *cnet;
5353

54+
lockdep_nfct_expect_lock_held();
5455
WARN_ON(!master_help);
5556
WARN_ON(timer_pending(&exp->timeout));
5657

@@ -112,12 +113,14 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
112113
const struct net *net)
113114
{
114115
return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
115-
net_eq(net, nf_ct_net(i->master)) &&
116-
nf_ct_zone_equal_any(i->master, zone);
116+
net_eq(net, read_pnet(&i->net)) &&
117+
nf_ct_exp_zone_equal_any(i, zone);
117118
}
118119

119120
bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
120121
{
122+
lockdep_nfct_expect_lock_held();
123+
121124
if (timer_delete(&exp->timeout)) {
122125
nf_ct_unlink_expect(exp);
123126
nf_ct_expect_put(exp);
@@ -177,6 +180,8 @@ nf_ct_find_expectation(struct net *net,
177180
struct nf_conntrack_expect *i, *exp = NULL;
178181
unsigned int h;
179182

183+
lockdep_nfct_expect_lock_held();
184+
180185
if (!cnet->expect_count)
181186
return NULL;
182187

@@ -309,12 +314,20 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
309314
}
310315
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
311316

317+
/* This function can only be used from packet path, where accessing
318+
* master's helper is safe, because the packet holds a reference on
319+
* the conntrack object. Never use it from control plane.
320+
*/
312321
void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
313322
u_int8_t family,
314323
const union nf_inet_addr *saddr,
315324
const union nf_inet_addr *daddr,
316325
u_int8_t proto, const __be16 *src, const __be16 *dst)
317326
{
327+
struct nf_conntrack_helper *helper = NULL;
328+
struct nf_conn *ct = exp->master;
329+
struct net *net = read_pnet(&ct->ct_net);
330+
struct nf_conn_help *help;
318331
int len;
319332

320333
if (family == AF_INET)
@@ -325,7 +338,16 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
325338
exp->flags = 0;
326339
exp->class = class;
327340
exp->expectfn = NULL;
328-
exp->helper = NULL;
341+
342+
help = nfct_help(ct);
343+
if (help)
344+
helper = rcu_dereference(help->helper);
345+
346+
rcu_assign_pointer(exp->helper, helper);
347+
write_pnet(&exp->net, net);
348+
#ifdef CONFIG_NF_CONNTRACK_ZONES
349+
exp->zone = ct->zone;
350+
#endif
329351
exp->tuple.src.l3num = family;
330352
exp->tuple.dst.protonum = proto;
331353

@@ -442,6 +464,8 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
442464
unsigned int h;
443465
int ret = 0;
444466

467+
lockdep_nfct_expect_lock_held();
468+
445469
if (!master_help) {
446470
ret = -ESHUTDOWN;
447471
goto out;
@@ -498,8 +522,9 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
498522

499523
nf_ct_expect_insert(expect);
500524

501-
spin_unlock_bh(&nf_conntrack_expect_lock);
502525
nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
526+
spin_unlock_bh(&nf_conntrack_expect_lock);
527+
503528
return 0;
504529
out:
505530
spin_unlock_bh(&nf_conntrack_expect_lock);
@@ -627,11 +652,15 @@ static int exp_seq_show(struct seq_file *s, void *v)
627652
{
628653
struct nf_conntrack_expect *expect;
629654
struct nf_conntrack_helper *helper;
655+
struct net *net = seq_file_net(s);
630656
struct hlist_node *n = v;
631657
char *delim = "";
632658

633659
expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
634660

661+
if (!net_eq(nf_ct_exp_net(expect), net))
662+
return 0;
663+
635664
if (expect->timeout.function)
636665
seq_printf(s, "%ld ", timer_pending(&expect->timeout)
637666
? (long)(expect->timeout.expires - jiffies)/HZ : 0);
@@ -654,7 +683,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
654683
if (expect->flags & NF_CT_EXPECT_USERSPACE)
655684
seq_printf(s, "%sUSERSPACE", delim);
656685

657-
helper = rcu_dereference(nfct_help(expect->master)->helper);
686+
helper = rcu_dereference(expect->helper);
658687
if (helper) {
659688
seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
660689
if (helper->expect_policy[expect->class].name[0])

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 & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,10 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
395395

396396
static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
397397
{
398-
struct nf_conn_help *help = nfct_help(exp->master);
399398
const struct nf_conntrack_helper *me = data;
400399
const struct nf_conntrack_helper *this;
401400

402-
if (exp->helper == me)
403-
return true;
404-
405-
this = rcu_dereference_protected(help->helper,
401+
this = rcu_dereference_protected(exp->helper,
406402
lockdep_is_held(&nf_conntrack_expect_lock));
407403
return this == me;
408404
}
@@ -421,6 +417,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
421417

422418
nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
423419
nf_ct_iterate_destroy(unhelp, me);
420+
421+
/* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
422+
* last step, this ensures rcu readers of exp->helper are done.
423+
* No need for another synchronize_rcu() here.
424+
*/
424425
}
425426
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
426427

0 commit comments

Comments
 (0)