netfilter: xt_hashlimit: validate hashtable supports XT_HASHLIMIT_RATE_MATCH

The XT_HASHLIMIT_RATE_MATCH flag mode changes the semantics of the
dsthash_ent structure which represents an entry in the hashtable.  There
is a union area which uses a different layout to express the rate match
mode.

Update .checkentry path to validate the XT_HASHLIMIT_RATE_MATCH mode
flag is requested by two or more different rules that refer to the same
hashtable. Otherwise, uninitialized access to the burst field in the
union is possible.

Reject the use of the XT_HASHLIMIT_RATE_MATCH mode flag if set on by
revision less than 3 too.

Fixes: bea74641e3 ("netfilter: xt_hashlimit: add rate match mode")
Reported-and-tested-by: Talha Berk Arslan <talha.anything.info@gmail.com>
Link: https://patch.msgid.link/20260721074629.668-1-talha.anything.info@gmail.com/
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Pablo Neira Ayuso
2026-07-21 22:02:46 +02:00
parent f4f6997905
commit 305b63e140

View File

@@ -117,6 +117,7 @@ struct xt_hashlimit_htable {
refcount_t use;
u_int8_t family;
bool rnd_initialized;
bool ratematch;
struct hashlimit_cfg3 cfg; /* config */
@@ -323,6 +324,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,
kvfree(hinfo);
return -ENOMEM;
}
hinfo->ratematch = !!(cfg->mode & XT_HASHLIMIT_RATE_MATCH);
spin_lock_init(&hinfo->lock);
switch (revision) {
@@ -872,7 +874,10 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
}
/* Check for overflow. */
if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
if (cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
if (revision < 3)
return -EINVAL;
if (cfg->avg == 0 || cfg->avg > U32_MAX) {
pr_info_ratelimited("invalid rate\n");
return -ERANGE;
@@ -905,6 +910,15 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
mutex_unlock(&hashlimit_mutex);
return ret;
}
} else {
if ((cfg->mode & XT_HASHLIMIT_RATE_MATCH &&
!(*hinfo)->ratematch) ||
(!(cfg->mode & XT_HASHLIMIT_RATE_MATCH) &&
(*hinfo)->ratematch)) {
mutex_unlock(&hashlimit_mutex);
htable_put(*hinfo);
return -EINVAL;
}
}
mutex_unlock(&hashlimit_mutex);