mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== netfilter fixes for net The following patchset contains netfilter fixes for your net tree, they are: 1) Fix missing MODULE_LICENSE() in the new nf_reject_ipv{4,6} modules. 2) Restrict nat and masq expressions to the nat chain type. Otherwise, users may crash their kernel if they attach a nat/masq rule to a non nat chain. 3) Fix hook validation in nft_compat when non-base chains are used. Basically, initialize hook_mask to zero. 4) Make sure you use match/targets in nft_compat from the right chain type. The existing validation relies on the table name which can be avoided by 5) Better netlink attribute validation in nft_nat. This expression has to reject the configuration when no address and proto configurations are specified. 6) Interpret NFTA_NAT_REG_*_MAX if only if NFTA_NAT_REG_*_MIN is set. Yet another sanity check to reject incorrect configurations from userspace. 7) Conditional NAT attribute dumping depending on the existing configuration. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ce8ec48967
@ -530,6 +530,9 @@ enum nft_chain_type {
|
||||
NFT_CHAIN_T_MAX
|
||||
};
|
||||
|
||||
int nft_chain_validate_dependency(const struct nft_chain *chain,
|
||||
enum nft_chain_type type);
|
||||
|
||||
struct nft_stats {
|
||||
u64 bytes;
|
||||
u64 pkts;
|
||||
|
@ -13,4 +13,7 @@ int nft_masq_init(const struct nft_ctx *ctx,
|
||||
|
||||
int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr);
|
||||
|
||||
int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
const struct nft_data **data);
|
||||
|
||||
#endif /* _NFT_MASQ_H_ */
|
||||
|
@ -6,6 +6,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/route.h>
|
||||
@ -125,3 +126,5 @@ void nf_send_reset(struct sk_buff *oldskb, int hook)
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_send_reset);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = {
|
||||
.eval = nft_masq_ipv4_eval,
|
||||
.init = nft_masq_init,
|
||||
.dump = nft_masq_dump,
|
||||
.validate = nft_masq_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
|
||||
|
@ -5,6 +5,8 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/ip6_fib.h>
|
||||
@ -161,3 +163,5 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
|
||||
ip6_local_out(nskb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_send_reset6);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = {
|
||||
.eval = nft_masq_ipv6_eval,
|
||||
.init = nft_masq_init,
|
||||
.dump = nft_masq_dump,
|
||||
.validate = nft_masq_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
|
||||
|
@ -3744,6 +3744,20 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
|
||||
.abort = nf_tables_abort,
|
||||
};
|
||||
|
||||
int nft_chain_validate_dependency(const struct nft_chain *chain,
|
||||
enum nft_chain_type type)
|
||||
{
|
||||
const struct nft_base_chain *basechain;
|
||||
|
||||
if (chain->flags & NFT_BASE_CHAIN) {
|
||||
basechain = nft_base_chain(chain);
|
||||
if (basechain->type->type != type)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nft_chain_validate_dependency);
|
||||
|
||||
/*
|
||||
* Loop detection - walk through the ruleset beginning at the destination chain
|
||||
* of a new jump until either the source chain is reached (loop) or all
|
||||
|
@ -19,9 +19,52 @@
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <asm/uaccess.h> /* for set_fs */
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
u8 type;
|
||||
} table_to_chaintype[] = {
|
||||
{ "filter", NFT_CHAIN_T_DEFAULT },
|
||||
{ "raw", NFT_CHAIN_T_DEFAULT },
|
||||
{ "security", NFT_CHAIN_T_DEFAULT },
|
||||
{ "mangle", NFT_CHAIN_T_ROUTE },
|
||||
{ "nat", NFT_CHAIN_T_NAT },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int nft_compat_table_to_chaintype(const char *table)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; table_to_chaintype[i].name != NULL; i++) {
|
||||
if (strcmp(table_to_chaintype[i].name, table) == 0)
|
||||
return table_to_chaintype[i].type;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nft_compat_chain_validate_dependency(const char *tablename,
|
||||
const struct nft_chain *chain)
|
||||
{
|
||||
enum nft_chain_type type;
|
||||
const struct nft_base_chain *basechain;
|
||||
|
||||
if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
|
||||
return 0;
|
||||
|
||||
type = nft_compat_table_to_chaintype(tablename);
|
||||
if (type < 0)
|
||||
return -EINVAL;
|
||||
|
||||
basechain = nft_base_chain(chain);
|
||||
if (basechain->type->type != type)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
union nft_entry {
|
||||
struct ipt_entry e4;
|
||||
struct ip6t_entry e6;
|
||||
@ -95,6 +138,8 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
|
||||
const struct nf_hook_ops *ops = &basechain->ops[0];
|
||||
|
||||
par->hook_mask = 1 << ops->hooknum;
|
||||
} else {
|
||||
par->hook_mask = 0;
|
||||
}
|
||||
par->family = ctx->afi->family;
|
||||
}
|
||||
@ -151,6 +196,10 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
union nft_entry e = {};
|
||||
int ret;
|
||||
|
||||
ret = nft_compat_chain_validate_dependency(target->table, ctx->chain);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
|
||||
|
||||
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
||||
@ -216,6 +265,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
|
||||
{
|
||||
struct xt_target *target = expr->ops->data;
|
||||
unsigned int hook_mask = 0;
|
||||
int ret;
|
||||
|
||||
if (ctx->chain->flags & NFT_BASE_CHAIN) {
|
||||
const struct nft_base_chain *basechain =
|
||||
@ -223,11 +273,13 @@ static int nft_target_validate(const struct nft_ctx *ctx,
|
||||
const struct nf_hook_ops *ops = &basechain->ops[0];
|
||||
|
||||
hook_mask = 1 << ops->hooknum;
|
||||
if (hook_mask & target->hooks)
|
||||
return 0;
|
||||
if (!(hook_mask & target->hooks))
|
||||
return -EINVAL;
|
||||
|
||||
/* This target is being called from an invalid chain */
|
||||
return -EINVAL;
|
||||
ret = nft_compat_chain_validate_dependency(target->table,
|
||||
ctx->chain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -293,6 +345,8 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
|
||||
const struct nf_hook_ops *ops = &basechain->ops[0];
|
||||
|
||||
par->hook_mask = 1 << ops->hooknum;
|
||||
} else {
|
||||
par->hook_mask = 0;
|
||||
}
|
||||
par->family = ctx->afi->family;
|
||||
}
|
||||
@ -320,6 +374,10 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
union nft_entry e = {};
|
||||
int ret;
|
||||
|
||||
ret = nft_compat_chain_validate_dependency(match->name, ctx->chain);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
|
||||
|
||||
if (ctx->nla[NFTA_RULE_COMPAT]) {
|
||||
@ -379,6 +437,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
|
||||
{
|
||||
struct xt_match *match = expr->ops->data;
|
||||
unsigned int hook_mask = 0;
|
||||
int ret;
|
||||
|
||||
if (ctx->chain->flags & NFT_BASE_CHAIN) {
|
||||
const struct nft_base_chain *basechain =
|
||||
@ -386,11 +445,13 @@ static int nft_match_validate(const struct nft_ctx *ctx,
|
||||
const struct nf_hook_ops *ops = &basechain->ops[0];
|
||||
|
||||
hook_mask = 1 << ops->hooknum;
|
||||
if (hook_mask & match->hooks)
|
||||
return 0;
|
||||
if (!(hook_mask & match->hooks))
|
||||
return -EINVAL;
|
||||
|
||||
/* This match is being called from an invalid chain */
|
||||
return -EINVAL;
|
||||
ret = nft_compat_chain_validate_dependency(match->name,
|
||||
ctx->chain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ int nft_masq_init(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_masq *priv = nft_expr_priv(expr);
|
||||
int err;
|
||||
|
||||
err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (tb[NFTA_MASQ_FLAGS] == NULL)
|
||||
return 0;
|
||||
@ -55,5 +60,12 @@ nla_put_failure:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nft_masq_dump);
|
||||
|
||||
int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
const struct nft_data **data)
|
||||
{
|
||||
return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nft_masq_validate);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
|
||||
|
@ -95,7 +95,13 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
u32 family;
|
||||
int err;
|
||||
|
||||
if (tb[NFTA_NAT_TYPE] == NULL)
|
||||
err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (tb[NFTA_NAT_TYPE] == NULL ||
|
||||
(tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
|
||||
tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
|
||||
@ -120,38 +126,44 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
||||
priv->family = family;
|
||||
|
||||
if (tb[NFTA_NAT_REG_ADDR_MIN]) {
|
||||
priv->sreg_addr_min = ntohl(nla_get_be32(
|
||||
tb[NFTA_NAT_REG_ADDR_MIN]));
|
||||
priv->sreg_addr_min =
|
||||
ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));
|
||||
|
||||
err = nft_validate_input_register(priv->sreg_addr_min);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (tb[NFTA_NAT_REG_ADDR_MAX]) {
|
||||
priv->sreg_addr_max =
|
||||
ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));
|
||||
|
||||
err = nft_validate_input_register(priv->sreg_addr_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
priv->sreg_addr_max = priv->sreg_addr_min;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_REG_ADDR_MAX]) {
|
||||
priv->sreg_addr_max = ntohl(nla_get_be32(
|
||||
tb[NFTA_NAT_REG_ADDR_MAX]));
|
||||
err = nft_validate_input_register(priv->sreg_addr_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else
|
||||
priv->sreg_addr_max = priv->sreg_addr_min;
|
||||
|
||||
if (tb[NFTA_NAT_REG_PROTO_MIN]) {
|
||||
priv->sreg_proto_min = ntohl(nla_get_be32(
|
||||
tb[NFTA_NAT_REG_PROTO_MIN]));
|
||||
priv->sreg_proto_min =
|
||||
ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));
|
||||
|
||||
err = nft_validate_input_register(priv->sreg_proto_min);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_REG_PROTO_MAX]) {
|
||||
priv->sreg_proto_max = ntohl(nla_get_be32(
|
||||
tb[NFTA_NAT_REG_PROTO_MAX]));
|
||||
err = nft_validate_input_register(priv->sreg_proto_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else
|
||||
priv->sreg_proto_max = priv->sreg_proto_min;
|
||||
if (tb[NFTA_NAT_REG_PROTO_MAX]) {
|
||||
priv->sreg_proto_max =
|
||||
ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));
|
||||
|
||||
err = nft_validate_input_register(priv->sreg_proto_max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
priv->sreg_proto_max = priv->sreg_proto_min;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[NFTA_NAT_FLAGS]) {
|
||||
priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
|
||||
@ -179,17 +191,19 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
|
||||
if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb,
|
||||
NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb,
|
||||
NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (priv->sreg_addr_min) {
|
||||
if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN,
|
||||
htonl(priv->sreg_addr_min)) ||
|
||||
nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX,
|
||||
htonl(priv->sreg_addr_max)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (priv->sreg_proto_min) {
|
||||
if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN,
|
||||
htonl(priv->sreg_proto_min)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
|
||||
htonl(priv->sreg_proto_min)) ||
|
||||
nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
|
||||
htonl(priv->sreg_proto_max)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@ -205,6 +219,13 @@ nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nft_nat_validate(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nft_data **data)
|
||||
{
|
||||
return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
|
||||
}
|
||||
|
||||
static struct nft_expr_type nft_nat_type;
|
||||
static const struct nft_expr_ops nft_nat_ops = {
|
||||
.type = &nft_nat_type,
|
||||
@ -212,6 +233,7 @@ static const struct nft_expr_ops nft_nat_ops = {
|
||||
.eval = nft_nat_eval,
|
||||
.init = nft_nat_init,
|
||||
.dump = nft_nat_dump,
|
||||
.validate = nft_nat_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_nat_type __read_mostly = {
|
||||
|
Loading…
Reference in New Issue
Block a user