Skip to content

Commit e889eb1

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-24-05-29' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: Patch #1 syzbot reports that nf_reinject() could be called without rcu_read_lock() when flushing pending packets at nfnetlink queue removal, from Eric Dumazet. Patch #2 flushes ipset list:set when canceling garbage collection to reference to other lists to fix a race, from Jozsef Kadlecsik. Patch #3 restores q-in-q matching with nft_payload by reverting f6ae9f1 ("netfilter: nft_payload: add C-VLAN support"). Patch #4 fixes vlan mangling in skbuff when vlan offload is present in skbuff, without this patch nft_payload corrupts packets in this case. Patch #5 fixes possible nul-deref in tproxy no IP address is found in netdevice, reported by syzbot and patch from Florian Westphal. Patch #6 removes a superfluous restriction which prevents loose fib lookups from input and forward hooks, from Eric Garver. My assessment is that patches #1, #2 and #5 address possible kernel crash, anything else in this batch fixes broken features. netfilter pull request 24-05-29 * tag 'nf-24-05-29' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nft_fib: allow from forward/input without iif selector netfilter: tproxy: bail out if IP has been disabled on the device netfilter: nft_payload: skbuff vlan metadata mangle support netfilter: nft_payload: restore vlan q-in-q match support netfilter: ipset: Add list flush to cancel_gc netfilter: nfnetlink_queue: acquire rcu_read_lock() in instance_destroy_rcu() ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 2dc8b1e + e8ded22 commit e889eb1

File tree

5 files changed

+82
-28
lines changed

5 files changed

+82
-28
lines changed

net/ipv4/netfilter/nf_tproxy_ipv4.c

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ __be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
5858

5959
laddr = 0;
6060
indev = __in_dev_get_rcu(skb->dev);
61+
if (!indev)
62+
return daddr;
6163

6264
in_dev_for_each_ifa_rcu(ifa, indev) {
6365
if (ifa->ifa_flags & IFA_F_SECONDARY)

net/netfilter/ipset/ip_set_list_set.c

+3
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ list_set_cancel_gc(struct ip_set *set)
549549

550550
if (SET_WITH_TIMEOUT(set))
551551
timer_shutdown_sync(&map->gc);
552+
553+
/* Flush list to drop references to other ipsets */
554+
list_set_flush(set);
552555
}
553556

554557
static const struct ip_set_type_variant set_variant = {

net/netfilter/nfnetlink_queue.c

+2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ instance_destroy_rcu(struct rcu_head *head)
169169
struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
170170
rcu);
171171

172+
rcu_read_lock();
172173
nfqnl_flush(inst, NULL, 0);
174+
rcu_read_unlock();
173175
kfree(inst);
174176
module_put(THIS_MODULE);
175177
}

net/netfilter/nft_fib.c

+3-5
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,9 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
3535
switch (priv->result) {
3636
case NFT_FIB_RESULT_OIF:
3737
case NFT_FIB_RESULT_OIFNAME:
38-
hooks = (1 << NF_INET_PRE_ROUTING);
39-
if (priv->flags & NFTA_FIB_F_IIF) {
40-
hooks |= (1 << NF_INET_LOCAL_IN) |
41-
(1 << NF_INET_FORWARD);
42-
}
38+
hooks = (1 << NF_INET_PRE_ROUTING) |
39+
(1 << NF_INET_LOCAL_IN) |
40+
(1 << NF_INET_FORWARD);
4341
break;
4442
case NFT_FIB_RESULT_ADDRTYPE:
4543
if (priv->flags & NFTA_FIB_F_IIF)

net/netfilter/nft_payload.c

+72-23
Original file line numberDiff line numberDiff line change
@@ -45,36 +45,27 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
4545
int mac_off = skb_mac_header(skb) - skb->data;
4646
u8 *vlanh, *dst_u8 = (u8 *) d;
4747
struct vlan_ethhdr veth;
48-
u8 vlan_hlen = 0;
49-
50-
if ((skb->protocol == htons(ETH_P_8021AD) ||
51-
skb->protocol == htons(ETH_P_8021Q)) &&
52-
offset >= VLAN_ETH_HLEN && offset < VLAN_ETH_HLEN + VLAN_HLEN)
53-
vlan_hlen += VLAN_HLEN;
5448

5549
vlanh = (u8 *) &veth;
56-
if (offset < VLAN_ETH_HLEN + vlan_hlen) {
50+
if (offset < VLAN_ETH_HLEN) {
5751
u8 ethlen = len;
5852

59-
if (vlan_hlen &&
60-
skb_copy_bits(skb, mac_off, &veth, VLAN_ETH_HLEN) < 0)
61-
return false;
62-
else if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth))
53+
if (!nft_payload_rebuild_vlan_hdr(skb, mac_off, &veth))
6354
return false;
6455

65-
if (offset + len > VLAN_ETH_HLEN + vlan_hlen)
66-
ethlen -= offset + len - VLAN_ETH_HLEN - vlan_hlen;
56+
if (offset + len > VLAN_ETH_HLEN)
57+
ethlen -= offset + len - VLAN_ETH_HLEN;
6758

68-
memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen);
59+
memcpy(dst_u8, vlanh + offset, ethlen);
6960

7061
len -= ethlen;
7162
if (len == 0)
7263
return true;
7364

7465
dst_u8 += ethlen;
75-
offset = ETH_HLEN + vlan_hlen;
66+
offset = ETH_HLEN;
7667
} else {
77-
offset -= VLAN_HLEN + vlan_hlen;
68+
offset -= VLAN_HLEN;
7869
}
7970

8071
return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;
@@ -154,12 +145,12 @@ int nft_payload_inner_offset(const struct nft_pktinfo *pkt)
154145
return pkt->inneroff;
155146
}
156147

157-
static bool nft_payload_need_vlan_copy(const struct nft_payload *priv)
148+
static bool nft_payload_need_vlan_adjust(u32 offset, u32 len)
158149
{
159-
unsigned int len = priv->offset + priv->len;
150+
unsigned int boundary = offset + len;
160151

161152
/* data past ether src/dst requested, copy needed */
162-
if (len > offsetof(struct ethhdr, h_proto))
153+
if (boundary > offsetof(struct ethhdr, h_proto))
163154
return true;
164155

165156
return false;
@@ -183,7 +174,7 @@ void nft_payload_eval(const struct nft_expr *expr,
183174
goto err;
184175

185176
if (skb_vlan_tag_present(skb) &&
186-
nft_payload_need_vlan_copy(priv)) {
177+
nft_payload_need_vlan_adjust(priv->offset, priv->len)) {
187178
if (!nft_payload_copy_vlan(dest, skb,
188179
priv->offset, priv->len))
189180
goto err;
@@ -810,21 +801,79 @@ struct nft_payload_set {
810801
u8 csum_flags;
811802
};
812803

804+
/* This is not struct vlan_hdr. */
805+
struct nft_payload_vlan_hdr {
806+
__be16 h_vlan_proto;
807+
__be16 h_vlan_TCI;
808+
};
809+
810+
static bool
811+
nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u8 offset, u8 len,
812+
int *vlan_hlen)
813+
{
814+
struct nft_payload_vlan_hdr *vlanh;
815+
__be16 vlan_proto;
816+
u16 vlan_tci;
817+
818+
if (offset >= offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto)) {
819+
*vlan_hlen = VLAN_HLEN;
820+
return true;
821+
}
822+
823+
switch (offset) {
824+
case offsetof(struct vlan_ethhdr, h_vlan_proto):
825+
if (len == 2) {
826+
vlan_proto = nft_reg_load_be16(src);
827+
skb->vlan_proto = vlan_proto;
828+
} else if (len == 4) {
829+
vlanh = (struct nft_payload_vlan_hdr *)src;
830+
__vlan_hwaccel_put_tag(skb, vlanh->h_vlan_proto,
831+
ntohs(vlanh->h_vlan_TCI));
832+
} else {
833+
return false;
834+
}
835+
break;
836+
case offsetof(struct vlan_ethhdr, h_vlan_TCI):
837+
if (len != 2)
838+
return false;
839+
840+
vlan_tci = ntohs(nft_reg_load_be16(src));
841+
skb->vlan_tci = vlan_tci;
842+
break;
843+
default:
844+
return false;
845+
}
846+
847+
return true;
848+
}
849+
813850
static void nft_payload_set_eval(const struct nft_expr *expr,
814851
struct nft_regs *regs,
815852
const struct nft_pktinfo *pkt)
816853
{
817854
const struct nft_payload_set *priv = nft_expr_priv(expr);
818-
struct sk_buff *skb = pkt->skb;
819855
const u32 *src = &regs->data[priv->sreg];
820-
int offset, csum_offset;
856+
int offset, csum_offset, vlan_hlen = 0;
857+
struct sk_buff *skb = pkt->skb;
821858
__wsum fsum, tsum;
822859

823860
switch (priv->base) {
824861
case NFT_PAYLOAD_LL_HEADER:
825862
if (!skb_mac_header_was_set(skb))
826863
goto err;
827-
offset = skb_mac_header(skb) - skb->data;
864+
865+
if (skb_vlan_tag_present(skb) &&
866+
nft_payload_need_vlan_adjust(priv->offset, priv->len)) {
867+
if (!nft_payload_set_vlan(src, skb,
868+
priv->offset, priv->len,
869+
&vlan_hlen))
870+
goto err;
871+
872+
if (!vlan_hlen)
873+
return;
874+
}
875+
876+
offset = skb_mac_header(skb) - skb->data - vlan_hlen;
828877
break;
829878
case NFT_PAYLOAD_NETWORK_HEADER:
830879
offset = skb_network_offset(skb);

0 commit comments

Comments
 (0)