Skip to content

Commit 90be7a5

Browse files
committed
Merge tag 'nf-24-04-11' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
netfilter pull request 24-04-11 Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: Patches #1 and #2 add missing rcu read side lock when iterating over expression and object type list which could race with module removal. Patch #3 prevents promisc packet from visiting the bridge/input hook to amend a recent fix to address conntrack confirmation race in br_netfilter and nf_conntrack_bridge. Patch #4 adds and uses iterate decorator type to fetch the current pipapo set backend datastructure view when netlink dumps the set elements. Patch #5 fixes removal of duplicate elements in the pipapo set backend. Patch #6 flowtable validates pppoe header before accessing it. Patch #7 fixes flowtable datapath for pppoe packets, otherwise lookup fails and pppoe packets follow classic path. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 2ae9a89 + 6db5dc7 commit 90be7a5

File tree

10 files changed

+91
-25
lines changed

10 files changed

+91
-25
lines changed

include/net/netfilter/nf_flow_table.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow,
336336
int nf_flow_table_offload_init(void);
337337
void nf_flow_table_offload_exit(void);
338338

339-
static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
339+
static inline __be16 __nf_flow_pppoe_proto(const struct sk_buff *skb)
340340
{
341341
__be16 proto;
342342

@@ -352,6 +352,16 @@ static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
352352
return 0;
353353
}
354354

355+
static inline bool nf_flow_pppoe_proto(struct sk_buff *skb, __be16 *inner_proto)
356+
{
357+
if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
358+
return false;
359+
360+
*inner_proto = __nf_flow_pppoe_proto(skb);
361+
362+
return true;
363+
}
364+
355365
#define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count)
356366
#define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count)
357367
#define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \

include/net/netfilter/nf_tables.h

+14
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,23 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
307307
return (void *)priv;
308308
}
309309

310+
311+
/**
312+
* enum nft_iter_type - nftables set iterator type
313+
*
314+
* @NFT_ITER_READ: read-only iteration over set elements
315+
* @NFT_ITER_UPDATE: iteration under mutex to update set element state
316+
*/
317+
enum nft_iter_type {
318+
NFT_ITER_UNSPEC,
319+
NFT_ITER_READ,
320+
NFT_ITER_UPDATE,
321+
};
322+
310323
struct nft_set;
311324
struct nft_set_iter {
312325
u8 genmask;
326+
enum nft_iter_type type:8;
313327
unsigned int count;
314328
unsigned int skip;
315329
int err;

net/bridge/br_input.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
3030
return netif_receive_skb(skb);
3131
}
3232

33-
static int br_pass_frame_up(struct sk_buff *skb)
33+
static int br_pass_frame_up(struct sk_buff *skb, bool promisc)
3434
{
3535
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
3636
struct net_bridge *br = netdev_priv(brdev);
@@ -65,6 +65,8 @@ static int br_pass_frame_up(struct sk_buff *skb)
6565
br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
6666
BR_MCAST_DIR_TX);
6767

68+
BR_INPUT_SKB_CB(skb)->promisc = promisc;
69+
6870
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
6971
dev_net(indev), NULL, skb, indev, NULL,
7072
br_netif_receive_skb);
@@ -82,6 +84,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
8284
struct net_bridge_mcast *brmctx;
8385
struct net_bridge_vlan *vlan;
8486
struct net_bridge *br;
87+
bool promisc;
8588
u16 vid = 0;
8689
u8 state;
8790

@@ -137,7 +140,9 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
137140
if (p->flags & BR_LEARNING)
138141
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 0);
139142

140-
local_rcv = !!(br->dev->flags & IFF_PROMISC);
143+
promisc = !!(br->dev->flags & IFF_PROMISC);
144+
local_rcv = promisc;
145+
141146
if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
142147
/* by definition the broadcast is also a multicast address */
143148
if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
@@ -200,7 +205,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
200205
unsigned long now = jiffies;
201206

202207
if (test_bit(BR_FDB_LOCAL, &dst->flags))
203-
return br_pass_frame_up(skb);
208+
return br_pass_frame_up(skb, false);
204209

205210
if (now != dst->used)
206211
dst->used = now;
@@ -213,7 +218,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
213218
}
214219

215220
if (local_rcv)
216-
return br_pass_frame_up(skb);
221+
return br_pass_frame_up(skb, promisc);
217222

218223
out:
219224
return 0;
@@ -386,6 +391,8 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
386391
goto forward;
387392
}
388393

394+
BR_INPUT_SKB_CB(skb)->promisc = false;
395+
389396
/* The else clause should be hit when nf_hook():
390397
* - returns < 0 (drop/error)
391398
* - returns = 0 (stolen/nf_queue)

net/bridge/br_netfilter_hooks.c

+6
Original file line numberDiff line numberDiff line change
@@ -600,11 +600,17 @@ static unsigned int br_nf_local_in(void *priv,
600600
struct sk_buff *skb,
601601
const struct nf_hook_state *state)
602602
{
603+
bool promisc = BR_INPUT_SKB_CB(skb)->promisc;
603604
struct nf_conntrack *nfct = skb_nfct(skb);
604605
const struct nf_ct_hook *ct_hook;
605606
struct nf_conn *ct;
606607
int ret;
607608

609+
if (promisc) {
610+
nf_reset_ct(skb);
611+
return NF_ACCEPT;
612+
}
613+
608614
if (!nfct || skb->pkt_type == PACKET_HOST)
609615
return NF_ACCEPT;
610616

net/bridge/br_private.h

+1
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ struct br_input_skb_cb {
589589
#endif
590590
u8 proxyarp_replied:1;
591591
u8 src_port_isolated:1;
592+
u8 promisc:1;
592593
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
593594
u8 vlan_filtered:1;
594595
#endif

net/bridge/netfilter/nf_conntrack_bridge.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,24 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
294294
static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
295295
const struct nf_hook_state *state)
296296
{
297-
enum ip_conntrack_info ctinfo;
297+
bool promisc = BR_INPUT_SKB_CB(skb)->promisc;
298+
struct nf_conntrack *nfct = skb_nfct(skb);
298299
struct nf_conn *ct;
299300

300-
if (skb->pkt_type == PACKET_HOST)
301+
if (promisc) {
302+
nf_reset_ct(skb);
303+
return NF_ACCEPT;
304+
}
305+
306+
if (!nfct || skb->pkt_type == PACKET_HOST)
301307
return NF_ACCEPT;
302308

303309
/* nf_conntrack_confirm() cannot handle concurrent clones,
304310
* this happens for broad/multicast frames with e.g. macvlan on top
305311
* of the bridge device.
306312
*/
307-
ct = nf_ct_get(skb, &ctinfo);
308-
if (!ct || nf_ct_is_confirmed(ct) || nf_ct_is_template(ct))
313+
ct = container_of(nfct, struct nf_conn, ct_general);
314+
if (nf_ct_is_confirmed(ct) || nf_ct_is_template(ct))
309315
return NF_ACCEPT;
310316

311317
/* let inet prerouting call conntrack again */

net/netfilter/nf_flow_table_inet.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
2121
proto = veth->h_vlan_encapsulated_proto;
2222
break;
2323
case htons(ETH_P_PPP_SES):
24-
proto = nf_flow_pppoe_proto(skb);
24+
if (!nf_flow_pppoe_proto(skb, &proto))
25+
return NF_ACCEPT;
2526
break;
2627
default:
2728
proto = skb->protocol;

net/netfilter/nf_flow_table_ip.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static void nf_flow_tuple_encap(struct sk_buff *skb,
157157
tuple->encap[i].proto = skb->protocol;
158158
break;
159159
case htons(ETH_P_PPP_SES):
160-
phdr = (struct pppoe_hdr *)skb_mac_header(skb);
160+
phdr = (struct pppoe_hdr *)skb_network_header(skb);
161161
tuple->encap[i].id = ntohs(phdr->sid);
162162
tuple->encap[i].proto = skb->protocol;
163163
break;
@@ -273,10 +273,11 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
273273
return NF_STOLEN;
274274
}
275275

276-
static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
276+
static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto,
277277
u32 *offset)
278278
{
279279
struct vlan_ethhdr *veth;
280+
__be16 inner_proto;
280281

281282
switch (skb->protocol) {
282283
case htons(ETH_P_8021Q):
@@ -287,7 +288,8 @@ static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
287288
}
288289
break;
289290
case htons(ETH_P_PPP_SES):
290-
if (nf_flow_pppoe_proto(skb) == proto) {
291+
if (nf_flow_pppoe_proto(skb, &inner_proto) &&
292+
inner_proto == proto) {
291293
*offset += PPPOE_SES_HLEN;
292294
return true;
293295
}
@@ -316,7 +318,7 @@ static void nf_flow_encap_pop(struct sk_buff *skb,
316318
skb_reset_network_header(skb);
317319
break;
318320
case htons(ETH_P_PPP_SES):
319-
skb->protocol = nf_flow_pppoe_proto(skb);
321+
skb->protocol = __nf_flow_pppoe_proto(skb);
320322
skb_pull(skb, PPPOE_SES_HLEN);
321323
skb_reset_network_header(skb);
322324
break;

net/netfilter/nf_tables_api.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
626626
{
627627
struct nft_set_iter iter = {
628628
.genmask = nft_genmask_next(ctx->net),
629+
.type = NFT_ITER_UPDATE,
629630
.fn = nft_mapelem_deactivate,
630631
};
631632

@@ -3060,7 +3061,7 @@ static const struct nft_expr_type *__nft_expr_type_get(u8 family,
30603061
{
30613062
const struct nft_expr_type *type, *candidate = NULL;
30623063

3063-
list_for_each_entry(type, &nf_tables_expressions, list) {
3064+
list_for_each_entry_rcu(type, &nf_tables_expressions, list) {
30643065
if (!nla_strcmp(nla, type->name)) {
30653066
if (!type->family && !candidate)
30663067
candidate = type;
@@ -3092,9 +3093,13 @@ static const struct nft_expr_type *nft_expr_type_get(struct net *net,
30923093
if (nla == NULL)
30933094
return ERR_PTR(-EINVAL);
30943095

3096+
rcu_read_lock();
30953097
type = __nft_expr_type_get(family, nla);
3096-
if (type != NULL && try_module_get(type->owner))
3098+
if (type != NULL && try_module_get(type->owner)) {
3099+
rcu_read_unlock();
30973100
return type;
3101+
}
3102+
rcu_read_unlock();
30983103

30993104
lockdep_nfnl_nft_mutex_not_held();
31003105
#ifdef CONFIG_MODULES
@@ -5441,6 +5446,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
54415446
}
54425447

54435448
iter.genmask = nft_genmask_next(ctx->net);
5449+
iter.type = NFT_ITER_UPDATE;
54445450
iter.skip = 0;
54455451
iter.count = 0;
54465452
iter.err = 0;
@@ -5514,6 +5520,7 @@ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
55145520
{
55155521
struct nft_set_iter iter = {
55165522
.genmask = nft_genmask_next(ctx->net),
5523+
.type = NFT_ITER_UPDATE,
55175524
.fn = nft_mapelem_activate,
55185525
};
55195526

@@ -5888,6 +5895,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
58885895
args.skb = skb;
58895896
args.reset = dump_ctx->reset;
58905897
args.iter.genmask = nft_genmask_cur(net);
5898+
args.iter.type = NFT_ITER_READ;
58915899
args.iter.skip = cb->args[0];
58925900
args.iter.count = 0;
58935901
args.iter.err = 0;
@@ -7372,6 +7380,7 @@ static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
73727380
{
73737381
struct nft_set_iter iter = {
73747382
.genmask = genmask,
7383+
.type = NFT_ITER_UPDATE,
73757384
.fn = nft_setelem_flush,
73767385
};
73777386

@@ -7607,7 +7616,7 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype, u8 family)
76077616
{
76087617
const struct nft_object_type *type;
76097618

7610-
list_for_each_entry(type, &nf_tables_objects, list) {
7619+
list_for_each_entry_rcu(type, &nf_tables_objects, list) {
76117620
if (type->family != NFPROTO_UNSPEC &&
76127621
type->family != family)
76137622
continue;
@@ -7623,9 +7632,13 @@ nft_obj_type_get(struct net *net, u32 objtype, u8 family)
76237632
{
76247633
const struct nft_object_type *type;
76257634

7635+
rcu_read_lock();
76267636
type = __nft_obj_type_get(objtype, family);
7627-
if (type != NULL && try_module_get(type->owner))
7637+
if (type != NULL && try_module_get(type->owner)) {
7638+
rcu_read_unlock();
76287639
return type;
7640+
}
7641+
rcu_read_unlock();
76297642

76307643
lockdep_nfnl_nft_mutex_not_held();
76317644
#ifdef CONFIG_MODULES
@@ -10871,6 +10884,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
1087110884
continue;
1087210885

1087310886
iter.genmask = nft_genmask_next(ctx->net);
10887+
iter.type = NFT_ITER_UPDATE;
1087410888
iter.skip = 0;
1087510889
iter.count = 0;
1087610890
iter.err = 0;

net/netfilter/nft_set_pipapo.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,8 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
20772077
rules_fx = rules_f0;
20782078

20792079
nft_pipapo_for_each_field(f, i, m) {
2080+
bool last = i == m->field_count - 1;
2081+
20802082
if (!pipapo_match_field(f, start, rules_fx,
20812083
match_start, match_end))
20822084
break;
@@ -2089,16 +2091,18 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
20892091

20902092
match_start += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
20912093
match_end += NFT_PIPAPO_GROUPS_PADDED_SIZE(f);
2092-
}
20932094

2094-
if (i == m->field_count) {
2095-
priv->dirty = true;
2096-
pipapo_drop(m, rulemap);
2097-
return;
2095+
if (last && f->mt[rulemap[i].to].e == e) {
2096+
priv->dirty = true;
2097+
pipapo_drop(m, rulemap);
2098+
return;
2099+
}
20982100
}
20992101

21002102
first_rule += rules_f0;
21012103
}
2104+
2105+
WARN_ON_ONCE(1); /* elem_priv not found */
21022106
}
21032107

21042108
/**
@@ -2115,13 +2119,14 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
21152119
struct nft_set_iter *iter)
21162120
{
21172121
struct nft_pipapo *priv = nft_set_priv(set);
2118-
struct net *net = read_pnet(&set->net);
21192122
const struct nft_pipapo_match *m;
21202123
const struct nft_pipapo_field *f;
21212124
unsigned int i, r;
21222125

2126+
WARN_ON_ONCE(iter->type == NFT_ITER_UNSPEC);
2127+
21232128
rcu_read_lock();
2124-
if (iter->genmask == nft_genmask_cur(net))
2129+
if (iter->type == NFT_ITER_READ)
21252130
m = rcu_dereference(priv->match);
21262131
else
21272132
m = priv->clone;

0 commit comments

Comments
 (0)