netfilter: nf_tables: introduce nft_validate_register_load()

Change nft_validate_input_register() to not only validate the input
register number, but also the length of the load, and rename it to
nft_validate_register_load() to reflect that change.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Patrick McHardy 2015-04-11 02:27:30 +01:00 committed by Pablo Neira Ayuso
parent 27e6d2017a
commit d07db9884a
11 changed files with 62 additions and 40 deletions

View File

@ -112,13 +112,12 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1; return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1;
} }
int nft_validate_input_register(enum nft_registers reg); int nft_validate_register_load(enum nft_registers reg, unsigned int len);
int nft_validate_register_store(const struct nft_ctx *ctx, int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_registers reg, enum nft_registers reg,
const struct nft_data *data, const struct nft_data *data,
enum nft_data_types type, unsigned int len); enum nft_data_types type, unsigned int len);
/** /**
* struct nft_userdata - user defined data associated with an object * struct nft_userdata - user defined data associated with an object
* *

View File

@ -4122,22 +4122,27 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
} }
/** /**
* nft_validate_input_register - validate an expressions' input register * nft_validate_register_load - validate a load from a register
* *
* @reg: the register number * @reg: the register number
* @len: the length of the data
* *
* Validate that the input register is one of the general purpose * Validate that the input register is one of the general purpose
* registers. * registers and that the length of the load is within the bounds.
*/ */
int nft_validate_input_register(enum nft_registers reg) int nft_validate_register_load(enum nft_registers reg, unsigned int len)
{ {
if (reg <= NFT_REG_VERDICT) if (reg <= NFT_REG_VERDICT)
return -EINVAL; return -EINVAL;
if (reg > NFT_REG_MAX) if (reg > NFT_REG_MAX)
return -ERANGE; return -ERANGE;
if (len == 0)
return -EINVAL;
if (len > FIELD_SIZEOF(struct nft_data, data))
return -ERANGE;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(nft_validate_input_register); EXPORT_SYMBOL_GPL(nft_validate_register_load);
/** /**
* nft_validate_register_store - validate an expressions' register store * nft_validate_register_store - validate an expressions' register store

View File

@ -63,10 +63,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
tb[NFTA_BITWISE_XOR] == NULL) tb[NFTA_BITWISE_XOR] == NULL)
return -EINVAL; return -EINVAL;
priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN])); priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG])); priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, priv->len);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -96,10 +96,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
return -EINVAL; return -EINVAL;
} }
priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
if (priv->len == 0 || priv->len > FIELD_SIZEOF(struct nft_data, data))
return -EINVAL;
priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE])); priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
switch (priv->size) { switch (priv->size) {
case 2: case 2:
@ -110,7 +106,8 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG])); priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
err = nft_validate_input_register(priv->sreg); priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
err = nft_validate_register_load(priv->sreg, priv->len);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -75,12 +75,15 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
struct nft_data_desc desc; struct nft_data_desc desc;
int err; int err;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]); err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
BUG_ON(err < 0); BUG_ON(err < 0);
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
err = nft_validate_register_load(priv->sreg, desc.len);
if (err < 0)
return err;
priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
priv->len = desc.len; priv->len = desc.len;
return 0; return 0;
} }
@ -122,13 +125,17 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
u32 mask; u32 mask;
int err; int err;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]); err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
BUG_ON(err < 0); BUG_ON(err < 0);
desc.len *= BITS_PER_BYTE;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
err = nft_validate_register_load(priv->sreg, desc.len);
if (err < 0)
return err;
desc.len *= BITS_PER_BYTE;
mask = nft_cmp_fast_mask(desc.len); mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & mask; priv->data = data.data[0] & mask;
priv->len = desc.len; priv->len = desc.len;
return 0; return 0;
@ -167,7 +174,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
{ {
struct nft_data_desc desc; struct nft_data_desc desc;
struct nft_data data; struct nft_data data;
enum nft_registers sreg;
enum nft_cmp_ops op; enum nft_cmp_ops op;
int err; int err;
@ -176,11 +182,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
tb[NFTA_CMP_DATA] == NULL) tb[NFTA_CMP_DATA] == NULL)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
err = nft_validate_input_register(sreg);
if (err < 0)
return ERR_PTR(err);
op = ntohl(nla_get_be32(tb[NFTA_CMP_OP])); op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
switch (op) { switch (op) {
case NFT_CMP_EQ: case NFT_CMP_EQ:

View File

@ -324,12 +324,14 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_ct *priv = nft_expr_priv(expr); struct nft_ct *priv = nft_expr_priv(expr);
unsigned int len;
int err; int err;
priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
switch (priv->key) { switch (priv->key) {
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK: case NFT_CT_MARK:
len = FIELD_SIZEOF(struct nf_conn, mark);
break; break;
#endif #endif
default: default:
@ -337,7 +339,7 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG])); priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG]));
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, len);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -124,7 +124,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
} }
priv->sreg_key = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_KEY])); priv->sreg_key = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_KEY]));
err = nft_validate_input_register(priv->sreg_key); err = nft_validate_register_load(priv->sreg_key, set->klen);;
if (err < 0) if (err < 0)
return err; return err;
@ -135,7 +135,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
return -EOPNOTSUPP; return -EOPNOTSUPP;
priv->sreg_data = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_DATA])); priv->sreg_data = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_DATA]));
err = nft_validate_input_register(priv->sreg_data); err = nft_validate_register_load(priv->sreg_data, set->dlen);
if (err < 0) if (err < 0)
return err; return err;
} else if (set->flags & NFT_SET_MAP) } else if (set->flags & NFT_SET_MAP)

View File

@ -71,7 +71,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG])); priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, set->klen);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -267,20 +267,24 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_meta *priv = nft_expr_priv(expr); struct nft_meta *priv = nft_expr_priv(expr);
unsigned int len;
int err; int err;
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
switch (priv->key) { switch (priv->key) {
case NFT_META_MARK: case NFT_META_MARK:
case NFT_META_PRIORITY: case NFT_META_PRIORITY:
len = sizeof(u32);
break;
case NFT_META_NFTRACE: case NFT_META_NFTRACE:
len = sizeof(u8);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG]));
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, len);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -119,6 +119,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_nat *priv = nft_expr_priv(expr); struct nft_nat *priv = nft_expr_priv(expr);
unsigned int alen, plen;
u32 family; u32 family;
int err; int err;
@ -146,17 +147,25 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
return -EINVAL; return -EINVAL;
family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
if (family != AF_INET && family != AF_INET6)
return -EAFNOSUPPORT;
if (family != ctx->afi->family) if (family != ctx->afi->family)
return -EOPNOTSUPP; return -EOPNOTSUPP;
switch (family) {
case NFPROTO_IPV4:
alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip);
break;
case NFPROTO_IPV6:
alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip6);
break;
default:
return -EAFNOSUPPORT;
}
priv->family = family; priv->family = family;
if (tb[NFTA_NAT_REG_ADDR_MIN]) { if (tb[NFTA_NAT_REG_ADDR_MIN]) {
priv->sreg_addr_min = priv->sreg_addr_min =
ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN])); ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));
err = nft_validate_register_load(priv->sreg_addr_min, alen);
err = nft_validate_input_register(priv->sreg_addr_min);
if (err < 0) if (err < 0)
return err; return err;
@ -164,7 +173,8 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
priv->sreg_addr_max = priv->sreg_addr_max =
ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX])); ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));
err = nft_validate_input_register(priv->sreg_addr_max); err = nft_validate_register_load(priv->sreg_addr_max,
alen);
if (err < 0) if (err < 0)
return err; return err;
} else { } else {
@ -172,11 +182,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
} }
} }
plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
if (tb[NFTA_NAT_REG_PROTO_MIN]) { if (tb[NFTA_NAT_REG_PROTO_MIN]) {
priv->sreg_proto_min = priv->sreg_proto_min =
ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN])); ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));
err = nft_validate_input_register(priv->sreg_proto_min); err = nft_validate_register_load(priv->sreg_proto_min, plen);
if (err < 0) if (err < 0)
return err; return err;
@ -184,7 +195,8 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
priv->sreg_proto_max = priv->sreg_proto_max =
ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX])); ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));
err = nft_validate_input_register(priv->sreg_proto_max); err = nft_validate_register_load(priv->sreg_proto_max,
plen);
if (err < 0) if (err < 0)
return err; return err;
} else { } else {

View File

@ -44,17 +44,19 @@ int nft_redir_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_redir *priv = nft_expr_priv(expr); struct nft_redir *priv = nft_expr_priv(expr);
unsigned int plen;
int err; int err;
err = nft_redir_validate(ctx, expr, NULL); err = nft_redir_validate(ctx, expr, NULL);
if (err < 0) if (err < 0)
return err; return err;
plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
if (tb[NFTA_REDIR_REG_PROTO_MIN]) { if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
priv->sreg_proto_min = priv->sreg_proto_min =
ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MIN])); ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MIN]));
err = nft_validate_input_register(priv->sreg_proto_min); err = nft_validate_register_load(priv->sreg_proto_min, plen);
if (err < 0) if (err < 0)
return err; return err;
@ -62,7 +64,8 @@ int nft_redir_init(const struct nft_ctx *ctx,
priv->sreg_proto_max = priv->sreg_proto_max =
ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MAX])); ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MAX]));
err = nft_validate_input_register(priv->sreg_proto_max); err = nft_validate_register_load(priv->sreg_proto_max,
plen);
if (err < 0) if (err < 0)
return err; return err;
} else { } else {