mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
netfilter pull request 24-12-05
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmdQ7eIACgkQ1w0aZmrP KyEk+g//VdVM+7cVY+yqV+1gvST4yzCU7OkqGLhUZPYFsvARtLKqeSS2hygZAQzg bEqRuYCYShIh8zSCble9NxWd2u6h+QQWEkvxaWldsOHQ3olDBpzM0vWuqfbRV+GO TXtLwXXTzktMIW+itsZm2Dkz7MWhwcllKHuQRc6t5cu82Lm7vLjXRxEYyhcFbg7n 2waSwhPsRKkNY3dLiIkJQS/4FXp7SQM+kRv0jyeQQ4oC9mmPYYyteVpjphTIPji7 wpu1GgnmWEyMwNxYeoO7JZ69ESIc6wwUr712WB1FnGhjwQ1D0KdfgYnSxoc81TC4 BGyP5i4yYHU9DmAKb04zve+LaF1gR6L51agi6sYcIsZQw3Cnr/YIY7w8O+EavwHb VDPvDouMtvDIKd4Hdtsna2o8d/UrkuE5/AuijHU40eEEEuMeuqiaby6Dj3ORYFrs edWjnkSqcvLGhx0bXzuFAWm/CxYqZsPcH0rWSUfuJu4wLevlrvKF0bkcA3NtcjDc bOEwXB1McKnWNBFeOnetf3PvA5Eu2HbYtt87rO1UeeBS+Bw8IO2uTu5X73suSb4f TJyWcQk51HMNa230tT2vEjsA5+FhXL/ZUYGu1ckVfghmoYdmWAEx8fuzec2Lqe/V hsn3Csl+JOPmqOEHyRvQ7t0UL4j3918hNP21RWyee6qTYK09YSM= =3N6k -----END PGP SIGNATURE----- Merge tag 'nf-24-12-05' 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: 1) Fix esoteric undefined behaviour due to uninitialized stack access in ip_vs_protocol_init(), from Jinghao Jia. 2) Fix iptables xt_LED slab-out-of-bounds due to incorrect sanitization of the led string identifier, reported by syzbot. Patch from Dmitry Antipov. 3) Remove WARN_ON_ONCE reachable from userspace to check for the maximum cgroup level, nft_socket cgroup matching is restricted to 255 levels, but cgroups allow for INT_MAX levels by default. Reported by syzbot. 4) Fix nft_inner incorrect use of percpu area to store tunnel parser context with softirqs, resulting in inconsistent inner header offsets that could lead to bogus rule mismatches, reported by syzbot. 5) Grab module reference on ipset core while requesting set type modules, otherwise kernel crash is possible by removing ipset core module, patch from Phil Sutter. 6) Fix possible double-free in nft_hash garbage collector due to unstable walk interator that can provide twice the same element. Use a sequence number to skip expired/dead elements that have been already scheduled for removal. Based on patch from Laurent Fasnach netfilter pull request 24-12-05 * tag 'nf-24-12-05' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nft_set_hash: skip duplicated elements pending gc run netfilter: ipset: Hold module reference while requesting a module netfilter: nft_inner: incorrect percpu area handling under softirq netfilter: nft_socket: remove WARN_ON_ONCE on maximum cgroup level netfilter: x_tables: fix LED ID check in led_tg_check() ipvs: fix UB due to uninitialized stack access in ip_vs_protocol_init() ==================== Link: https://patch.msgid.link/20241205002854.162490-1-pablo@netfilter.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
7b998e073f
@ -161,6 +161,7 @@ enum {
|
||||
};
|
||||
|
||||
struct nft_inner_tun_ctx {
|
||||
unsigned long cookie;
|
||||
u16 type;
|
||||
u16 inner_tunoff;
|
||||
u16 inner_lloff;
|
||||
|
@ -104,14 +104,19 @@ find_set_type(const char *name, u8 family, u8 revision)
|
||||
static bool
|
||||
load_settype(const char *name)
|
||||
{
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return false;
|
||||
|
||||
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||
pr_debug("try to load ip_set_%s\n", name);
|
||||
if (request_module("ip_set_%s", name) < 0) {
|
||||
pr_warn("Can't find ip_set type %s\n", name);
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
module_put(THIS_MODULE);
|
||||
return false;
|
||||
}
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
module_put(THIS_MODULE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -340,7 +340,7 @@ void __net_exit ip_vs_protocol_net_cleanup(struct netns_ipvs *ipvs)
|
||||
|
||||
int __init ip_vs_protocol_init(void)
|
||||
{
|
||||
char protocols[64];
|
||||
char protocols[64] = { 0 };
|
||||
#define REGISTER_PROTOCOL(p) \
|
||||
do { \
|
||||
register_ip_vs_protocol(p); \
|
||||
@ -348,8 +348,6 @@ int __init ip_vs_protocol_init(void)
|
||||
strcat(protocols, (p)->name); \
|
||||
} while (0)
|
||||
|
||||
protocols[0] = '\0';
|
||||
protocols[2] = '\0';
|
||||
#ifdef CONFIG_IP_VS_PROTO_TCP
|
||||
REGISTER_PROTOCOL(&ip_vs_protocol_tcp);
|
||||
#endif
|
||||
|
@ -210,35 +210,66 @@ static int nft_inner_parse(const struct nft_inner *priv,
|
||||
struct nft_pktinfo *pkt,
|
||||
struct nft_inner_tun_ctx *tun_ctx)
|
||||
{
|
||||
struct nft_inner_tun_ctx ctx = {};
|
||||
u32 off = pkt->inneroff;
|
||||
|
||||
if (priv->flags & NFT_INNER_HDRSIZE &&
|
||||
nft_inner_parse_tunhdr(priv, pkt, &ctx, &off) < 0)
|
||||
nft_inner_parse_tunhdr(priv, pkt, tun_ctx, &off) < 0)
|
||||
return -1;
|
||||
|
||||
if (priv->flags & (NFT_INNER_LL | NFT_INNER_NH)) {
|
||||
if (nft_inner_parse_l2l3(priv, pkt, &ctx, off) < 0)
|
||||
if (nft_inner_parse_l2l3(priv, pkt, tun_ctx, off) < 0)
|
||||
return -1;
|
||||
} else if (priv->flags & NFT_INNER_TH) {
|
||||
ctx.inner_thoff = off;
|
||||
ctx.flags |= NFT_PAYLOAD_CTX_INNER_TH;
|
||||
tun_ctx->inner_thoff = off;
|
||||
tun_ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH;
|
||||
}
|
||||
|
||||
*tun_ctx = ctx;
|
||||
tun_ctx->type = priv->type;
|
||||
tun_ctx->cookie = (unsigned long)pkt->skb;
|
||||
pkt->flags |= NFT_PKTINFO_INNER_FULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool nft_inner_parse_needed(const struct nft_inner *priv,
|
||||
const struct nft_pktinfo *pkt,
|
||||
static bool nft_inner_restore_tun_ctx(const struct nft_pktinfo *pkt,
|
||||
struct nft_inner_tun_ctx *tun_ctx)
|
||||
{
|
||||
struct nft_inner_tun_ctx *this_cpu_tun_ctx;
|
||||
|
||||
local_bh_disable();
|
||||
this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
|
||||
if (this_cpu_tun_ctx->cookie != (unsigned long)pkt->skb) {
|
||||
local_bh_enable();
|
||||
return false;
|
||||
}
|
||||
*tun_ctx = *this_cpu_tun_ctx;
|
||||
local_bh_enable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nft_inner_save_tun_ctx(const struct nft_pktinfo *pkt,
|
||||
const struct nft_inner_tun_ctx *tun_ctx)
|
||||
{
|
||||
struct nft_inner_tun_ctx *this_cpu_tun_ctx;
|
||||
|
||||
local_bh_disable();
|
||||
this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
|
||||
if (this_cpu_tun_ctx->cookie != tun_ctx->cookie)
|
||||
*this_cpu_tun_ctx = *tun_ctx;
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static bool nft_inner_parse_needed(const struct nft_inner *priv,
|
||||
const struct nft_pktinfo *pkt,
|
||||
struct nft_inner_tun_ctx *tun_ctx)
|
||||
{
|
||||
if (!(pkt->flags & NFT_PKTINFO_INNER_FULL))
|
||||
return true;
|
||||
|
||||
if (!nft_inner_restore_tun_ctx(pkt, tun_ctx))
|
||||
return true;
|
||||
|
||||
if (priv->type != tun_ctx->type)
|
||||
return true;
|
||||
|
||||
@ -248,27 +279,29 @@ static bool nft_inner_parse_needed(const struct nft_inner *priv,
|
||||
static void nft_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
struct nft_inner_tun_ctx *tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
|
||||
const struct nft_inner *priv = nft_expr_priv(expr);
|
||||
struct nft_inner_tun_ctx tun_ctx = {};
|
||||
|
||||
if (nft_payload_inner_offset(pkt) < 0)
|
||||
goto err;
|
||||
|
||||
if (nft_inner_parse_needed(priv, pkt, tun_ctx) &&
|
||||
nft_inner_parse(priv, (struct nft_pktinfo *)pkt, tun_ctx) < 0)
|
||||
if (nft_inner_parse_needed(priv, pkt, &tun_ctx) &&
|
||||
nft_inner_parse(priv, (struct nft_pktinfo *)pkt, &tun_ctx) < 0)
|
||||
goto err;
|
||||
|
||||
switch (priv->expr_type) {
|
||||
case NFT_INNER_EXPR_PAYLOAD:
|
||||
nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
|
||||
nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx);
|
||||
break;
|
||||
case NFT_INNER_EXPR_META:
|
||||
nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
|
||||
nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx);
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
goto err;
|
||||
}
|
||||
nft_inner_save_tun_ctx(pkt, &tun_ctx);
|
||||
|
||||
return;
|
||||
err:
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
|
@ -24,11 +24,13 @@
|
||||
struct nft_rhash {
|
||||
struct rhashtable ht;
|
||||
struct delayed_work gc_work;
|
||||
u32 wq_gc_seq;
|
||||
};
|
||||
|
||||
struct nft_rhash_elem {
|
||||
struct nft_elem_priv priv;
|
||||
struct rhash_head node;
|
||||
u32 wq_gc_seq;
|
||||
struct nft_set_ext ext;
|
||||
};
|
||||
|
||||
@ -338,6 +340,10 @@ static void nft_rhash_gc(struct work_struct *work)
|
||||
if (!gc)
|
||||
goto done;
|
||||
|
||||
/* Elements never collected use a zero gc worker sequence number. */
|
||||
if (unlikely(++priv->wq_gc_seq == 0))
|
||||
priv->wq_gc_seq++;
|
||||
|
||||
rhashtable_walk_enter(&priv->ht, &hti);
|
||||
rhashtable_walk_start(&hti);
|
||||
|
||||
@ -355,6 +361,14 @@ static void nft_rhash_gc(struct work_struct *work)
|
||||
goto try_later;
|
||||
}
|
||||
|
||||
/* rhashtable walk is unstable, already seen in this gc run?
|
||||
* Then, skip this element. In case of (unlikely) sequence
|
||||
* wraparound and stale element wq_gc_seq, next gc run will
|
||||
* just find this expired element.
|
||||
*/
|
||||
if (he->wq_gc_seq == priv->wq_gc_seq)
|
||||
continue;
|
||||
|
||||
if (nft_set_elem_is_dead(&he->ext))
|
||||
goto dead_elem;
|
||||
|
||||
@ -371,6 +385,8 @@ static void nft_rhash_gc(struct work_struct *work)
|
||||
if (!gc)
|
||||
goto try_later;
|
||||
|
||||
/* annotate gc sequence for this attempt. */
|
||||
he->wq_gc_seq = priv->wq_gc_seq;
|
||||
nft_trans_gc_elem_add(gc, he);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ static noinline int nft_socket_cgroup_subtree_level(void)
|
||||
|
||||
cgroup_put(cgrp);
|
||||
|
||||
if (WARN_ON_ONCE(level > 255))
|
||||
if (level > 255)
|
||||
return -ERANGE;
|
||||
|
||||
if (WARN_ON_ONCE(level < 0))
|
||||
|
@ -96,7 +96,9 @@ static int led_tg_check(const struct xt_tgchk_param *par)
|
||||
struct xt_led_info_internal *ledinternal;
|
||||
int err;
|
||||
|
||||
if (ledinfo->id[0] == '\0')
|
||||
/* Bail out if empty string or not a string at all. */
|
||||
if (ledinfo->id[0] == '\0' ||
|
||||
!memchr(ledinfo->id, '\0', sizeof(ledinfo->id)))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&xt_led_mutex);
|
||||
|
Loading…
Reference in New Issue
Block a user