Skip to content

Commit 925781a

Browse files
committed
Merge tag 'nf-24-01-18' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following batch contains Netfilter fixes for net. Slightly larger than usual because this batch includes several patches to tighten the nf_tables control plane to reject inconsistent configuration: 1) Restrict NFTA_SET_POLICY to NFT_SET_POL_PERFORMANCE and NFT_SET_POL_MEMORY. 2) Bail out if a nf_tables expression registers more than 16 netlink attributes which is what struct nft_expr_info allows. 3) Bail out if NFT_EXPR_STATEFUL provides no .clone interface, remove existing fallback to memcpy() when cloning which might accidentally duplicate memory reference to the same object. 4) Fix br_netfilter interaction with neighbour layer. This requires three preparation patches: - Use nf_bridge_get_physinif() in nfnetlink_log - Use nf_bridge_info_exists() to check in br_netfilter context is available in nf_queue. - Pass net to nf_bridge_get_physindev() And finally, the fix which replaces physindev with physinif in nf_bridge_info. Patches from Pavel Tikhomirov. 5) Catch-all deactivation happens in the transaction, hence this oneliner to check for the next generation. This bug uncovered after the removal of the _BUSY bit, which happened in set elements back in summer 2023. 6) Ensure set (total) key length size and concat field length description is consistent, otherwise bail out. 7) Skip set element with the _DEAD flag on from the netlink dump path. A tests occasionally shows that dump is mismatching because GC might lose race to get rid of this element while a netlink dump is in progress. 8) Reject NFT_SET_CONCAT for field_count < 1. 9) Use IP6_INC_STATS in ipvs to fix preemption BUG splat, patch from Fedor Pchelkin. * tag 'nf-24-01-18' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: ipvs: avoid stat macros calls from preemptible context netfilter: nf_tables: reject NFT_SET_CONCAT with not field length description netfilter: nf_tables: skip dead set elements in netlink dump netfilter: nf_tables: do not allow mismatch field size and set key length netfilter: nf_tables: check if catch-all set element is active in next generation netfilter: bridge: replace physindev with physinif in nf_bridge_info netfilter: propagate net to nf_bridge_get_physindev netfilter: nf_queue: remove excess nf_bridge variable netfilter: nfnetlink_log: use proper helper for fetching physinif netfilter: nft_limit: do not ignore unsupported flags netfilter: nf_tables: bail out if stateful expression provides no .clone netfilter: nf_tables: validate .maxattr at expression registration netfilter: nf_tables: reject invalid set policy ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 4349efc + d6938c1 commit 925781a

File tree

14 files changed

+125
-63
lines changed

14 files changed

+125
-63
lines changed

include/linux/netfilter_bridge.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static inline int nf_bridge_get_physinif(const struct sk_buff *skb)
4242
if (!nf_bridge)
4343
return 0;
4444

45-
return nf_bridge->physindev ? nf_bridge->physindev->ifindex : 0;
45+
return nf_bridge->physinif;
4646
}
4747

4848
static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
@@ -56,11 +56,11 @@ static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
5656
}
5757

5858
static inline struct net_device *
59-
nf_bridge_get_physindev(const struct sk_buff *skb)
59+
nf_bridge_get_physindev(const struct sk_buff *skb, struct net *net)
6060
{
6161
const struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
6262

63-
return nf_bridge ? nf_bridge->physindev : NULL;
63+
return nf_bridge ? dev_get_by_index_rcu(net, nf_bridge->physinif) : NULL;
6464
}
6565

6666
static inline struct net_device *

include/linux/skbuff.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ struct nf_bridge_info {
295295
u8 bridged_dnat:1;
296296
u8 sabotage_in_done:1;
297297
__u16 frag_max_size;
298-
struct net_device *physindev;
298+
int physinif;
299299

300300
/* always valid & non-NULL from FORWARD on, for physdev match */
301301
struct net_device *physoutdev;

net/bridge/br_netfilter_hooks.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,17 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
279279

280280
if ((READ_ONCE(neigh->nud_state) & NUD_CONNECTED) &&
281281
READ_ONCE(neigh->hh.hh_len)) {
282+
struct net_device *br_indev;
283+
284+
br_indev = nf_bridge_get_physindev(skb, net);
285+
if (!br_indev) {
286+
neigh_release(neigh);
287+
goto free_skb;
288+
}
289+
282290
neigh_hh_bridge(&neigh->hh, skb);
283-
skb->dev = nf_bridge->physindev;
291+
skb->dev = br_indev;
292+
284293
ret = br_handle_frame_finish(net, sk, skb);
285294
} else {
286295
/* the neighbour function below overwrites the complete
@@ -352,12 +361,18 @@ br_nf_ipv4_daddr_was_changed(const struct sk_buff *skb,
352361
*/
353362
static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
354363
{
355-
struct net_device *dev = skb->dev;
364+
struct net_device *dev = skb->dev, *br_indev;
356365
struct iphdr *iph = ip_hdr(skb);
357366
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
358367
struct rtable *rt;
359368
int err;
360369

370+
br_indev = nf_bridge_get_physindev(skb, net);
371+
if (!br_indev) {
372+
kfree_skb(skb);
373+
return 0;
374+
}
375+
361376
nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
362377

363378
if (nf_bridge->pkt_otherhost) {
@@ -397,7 +412,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
397412
} else {
398413
if (skb_dst(skb)->dev == dev) {
399414
bridged_dnat:
400-
skb->dev = nf_bridge->physindev;
415+
skb->dev = br_indev;
401416
nf_bridge_update_protocol(skb);
402417
nf_bridge_push_encap_header(skb);
403418
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
@@ -410,7 +425,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
410425
skb->pkt_type = PACKET_HOST;
411426
}
412427
} else {
413-
rt = bridge_parent_rtable(nf_bridge->physindev);
428+
rt = bridge_parent_rtable(br_indev);
414429
if (!rt) {
415430
kfree_skb(skb);
416431
return 0;
@@ -419,7 +434,7 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
419434
skb_dst_set_noref(skb, &rt->dst);
420435
}
421436

422-
skb->dev = nf_bridge->physindev;
437+
skb->dev = br_indev;
423438
nf_bridge_update_protocol(skb);
424439
nf_bridge_push_encap_header(skb);
425440
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
@@ -456,7 +471,7 @@ struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
456471
}
457472

458473
nf_bridge->in_prerouting = 1;
459-
nf_bridge->physindev = skb->dev;
474+
nf_bridge->physinif = skb->dev->ifindex;
460475
skb->dev = brnf_get_logical_dev(skb, skb->dev, net);
461476

462477
if (skb->protocol == htons(ETH_P_8021Q))
@@ -553,7 +568,11 @@ static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff
553568
if (skb->protocol == htons(ETH_P_IPV6))
554569
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
555570

556-
in = nf_bridge->physindev;
571+
in = nf_bridge_get_physindev(skb, net);
572+
if (!in) {
573+
kfree_skb(skb);
574+
return 0;
575+
}
557576
if (nf_bridge->pkt_otherhost) {
558577
skb->pkt_type = PACKET_OTHERHOST;
559578
nf_bridge->pkt_otherhost = false;
@@ -899,6 +918,13 @@ static unsigned int ip_sabotage_in(void *priv,
899918
static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
900919
{
901920
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
921+
struct net_device *br_indev;
922+
923+
br_indev = nf_bridge_get_physindev(skb, dev_net(skb->dev));
924+
if (!br_indev) {
925+
kfree_skb(skb);
926+
return;
927+
}
902928

903929
skb_pull(skb, ETH_HLEN);
904930
nf_bridge->bridged_dnat = 0;
@@ -908,7 +934,7 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
908934
skb_copy_to_linear_data_offset(skb, -(ETH_HLEN - ETH_ALEN),
909935
nf_bridge->neigh_header,
910936
ETH_HLEN - ETH_ALEN);
911-
skb->dev = nf_bridge->physindev;
937+
skb->dev = br_indev;
912938

913939
nf_bridge->physoutdev = NULL;
914940
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);

net/bridge/br_netfilter_ipv6.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,15 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
102102
{
103103
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
104104
struct rtable *rt;
105-
struct net_device *dev = skb->dev;
105+
struct net_device *dev = skb->dev, *br_indev;
106106
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
107107

108+
br_indev = nf_bridge_get_physindev(skb, net);
109+
if (!br_indev) {
110+
kfree_skb(skb);
111+
return 0;
112+
}
113+
108114
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
109115

110116
if (nf_bridge->pkt_otherhost) {
@@ -122,7 +128,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
122128
}
123129

124130
if (skb_dst(skb)->dev == dev) {
125-
skb->dev = nf_bridge->physindev;
131+
skb->dev = br_indev;
126132
nf_bridge_update_protocol(skb);
127133
nf_bridge_push_encap_header(skb);
128134
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
@@ -133,7 +139,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
133139
ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
134140
skb->pkt_type = PACKET_HOST;
135141
} else {
136-
rt = bridge_parent_rtable(nf_bridge->physindev);
142+
rt = bridge_parent_rtable(br_indev);
137143
if (!rt) {
138144
kfree_skb(skb);
139145
return 0;
@@ -142,7 +148,7 @@ static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struc
142148
skb_dst_set_noref(skb, &rt->dst);
143149
}
144150

145-
skb->dev = nf_bridge->physindev;
151+
skb->dev = br_indev;
146152
nf_bridge_update_protocol(skb);
147153
nf_bridge_push_encap_header(skb);
148154
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,

net/ipv4/netfilter/nf_reject_ipv4.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
239239
void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
240240
int hook)
241241
{
242-
struct net_device *br_indev __maybe_unused;
243242
struct sk_buff *nskb;
244243
struct iphdr *niph;
245244
const struct tcphdr *oth;
@@ -289,9 +288,13 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
289288
* build the eth header using the original destination's MAC as the
290289
* source, and send the RST packet directly.
291290
*/
292-
br_indev = nf_bridge_get_physindev(oldskb);
293-
if (br_indev) {
291+
if (nf_bridge_info_exists(oldskb)) {
294292
struct ethhdr *oeth = eth_hdr(oldskb);
293+
struct net_device *br_indev;
294+
295+
br_indev = nf_bridge_get_physindev(oldskb, net);
296+
if (!br_indev)
297+
goto free_nskb;
295298

296299
nskb->dev = br_indev;
297300
niph->tot_len = htons(nskb->len);

net/ipv6/netfilter/nf_reject_ipv6.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
278278
void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
279279
int hook)
280280
{
281-
struct net_device *br_indev __maybe_unused;
282281
struct sk_buff *nskb;
283282
struct tcphdr _otcph;
284283
const struct tcphdr *otcph;
@@ -354,9 +353,15 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
354353
* build the eth header using the original destination's MAC as the
355354
* source, and send the RST packet directly.
356355
*/
357-
br_indev = nf_bridge_get_physindev(oldskb);
358-
if (br_indev) {
356+
if (nf_bridge_info_exists(oldskb)) {
359357
struct ethhdr *oeth = eth_hdr(oldskb);
358+
struct net_device *br_indev;
359+
360+
br_indev = nf_bridge_get_physindev(oldskb, net);
361+
if (!br_indev) {
362+
kfree_skb(nskb);
363+
return;
364+
}
360365

361366
nskb->dev = br_indev;
362367
nskb->protocol = htons(ETH_P_IPV6);

net/netfilter/ipset/ip_set_hash_netiface.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ hash_netiface4_data_next(struct hash_netiface4_elem *next,
138138
#include "ip_set_hash_gen.h"
139139

140140
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
141-
static const char *get_physindev_name(const struct sk_buff *skb)
141+
static const char *get_physindev_name(const struct sk_buff *skb, struct net *net)
142142
{
143-
struct net_device *dev = nf_bridge_get_physindev(skb);
143+
struct net_device *dev = nf_bridge_get_physindev(skb, net);
144144

145145
return dev ? dev->name : NULL;
146146
}
@@ -177,7 +177,7 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
177177

178178
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
179179
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
180-
const char *eiface = SRCDIR ? get_physindev_name(skb) :
180+
const char *eiface = SRCDIR ? get_physindev_name(skb, xt_net(par)) :
181181
get_physoutdev_name(skb);
182182

183183
if (!eiface)
@@ -395,7 +395,7 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
395395

396396
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
397397
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
398-
const char *eiface = SRCDIR ? get_physindev_name(skb) :
398+
const char *eiface = SRCDIR ? get_physindev_name(skb, xt_net(par)) :
399399
get_physoutdev_name(skb);
400400

401401
if (!eiface)

net/netfilter/ipvs/ip_vs_xmit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
271271
skb->dev = dst->dev;
272272
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
273273
ICMPV6_EXC_HOPLIMIT, 0);
274-
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
274+
IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
275275

276276
return false;
277277
}
@@ -286,7 +286,7 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
286286
{
287287
if (ip_hdr(skb)->ttl <= 1) {
288288
/* Tell the sender its packet died... */
289-
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
289+
IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
290290
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
291291
return false;
292292
}

net/netfilter/nf_log_syslog.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u8 pf,
111111
unsigned int hooknum, const struct sk_buff *skb,
112112
const struct net_device *in,
113113
const struct net_device *out,
114-
const struct nf_loginfo *loginfo, const char *prefix)
114+
const struct nf_loginfo *loginfo, const char *prefix,
115+
struct net *net)
115116
{
116117
const struct net_device *physoutdev __maybe_unused;
117118
const struct net_device *physindev __maybe_unused;
@@ -121,7 +122,7 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u8 pf,
121122
in ? in->name : "",
122123
out ? out->name : "");
123124
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
124-
physindev = nf_bridge_get_physindev(skb);
125+
physindev = nf_bridge_get_physindev(skb, net);
125126
if (physindev && in != physindev)
126127
nf_log_buf_add(m, "PHYSIN=%s ", physindev->name);
127128
physoutdev = nf_bridge_get_physoutdev(skb);
@@ -148,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,
148149
loginfo = &default_loginfo;
149150

150151
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
151-
prefix);
152+
prefix, net);
152153
dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));
153154

154155
nf_log_buf_close(m);
@@ -845,7 +846,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
845846
loginfo = &default_loginfo;
846847

847848
nf_log_dump_packet_common(m, pf, hooknum, skb, in,
848-
out, loginfo, prefix);
849+
out, loginfo, prefix, net);
849850

850851
if (in)
851852
dump_mac_header(m, loginfo, skb);
@@ -880,7 +881,7 @@ static void nf_log_ip6_packet(struct net *net, u_int8_t pf,
880881
loginfo = &default_loginfo;
881882

882883
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out,
883-
loginfo, prefix);
884+
loginfo, prefix, net);
884885

885886
if (in)
886887
dump_mac_header(m, loginfo, skb);
@@ -916,7 +917,7 @@ static void nf_log_unknown_packet(struct net *net, u_int8_t pf,
916917
loginfo = &default_loginfo;
917918

918919
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
919-
prefix);
920+
prefix, net);
920921

921922
dump_mac_header(m, loginfo, skb);
922923

net/netfilter/nf_queue.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,9 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
8282
{
8383
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
8484
const struct sk_buff *skb = entry->skb;
85-
struct nf_bridge_info *nf_bridge;
8685

87-
nf_bridge = nf_bridge_info_get(skb);
88-
if (nf_bridge) {
89-
entry->physin = nf_bridge_get_physindev(skb);
86+
if (nf_bridge_info_exists(skb)) {
87+
entry->physin = nf_bridge_get_physindev(skb, entry->state.net);
9088
entry->physout = nf_bridge_get_physoutdev(skb);
9189
} else {
9290
entry->physin = NULL;

0 commit comments

Comments
 (0)