Commit 4f00b3d7 authored by Laura Garcia Liebana's avatar Laura Garcia Liebana Committed by Ben Hutchings

netfilter: nf_tables: validate maximum value of u32 netlink attributes

commit 36b701fa upstream.

Fetch value and validate u32 netlink attribute. This validation is
usually required when the u32 netlink attributes are being stored in a
field whose size is smaller.

This patch revisits 4da449ae ("netfilter: nft_exthdr: Add size check
on u8 nft_exthdr attributes").

Fixes: 96518518 ("netfilter: add nftables")
Suggested-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarLaura Garcia Liebana <nevola@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent aaf2bb42
......@@ -113,6 +113,7 @@ 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;
}
unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
int nft_validate_input_register(enum nft_registers reg);
int nft_validate_output_register(enum nft_registers reg);
int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
......
......@@ -3711,6 +3711,31 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
return 0;
}
/**
* nft_parse_u32_check - fetch u32 attribute and check for maximum value
*
* @attr: netlink attribute to fetch value from
* @max: maximum value to be stored in dest
* @dest: pointer to the variable
*
* Parse, check and store a given u32 netlink attribute into variable.
* This function returns -ERANGE if the value goes over maximum value.
* Otherwise a 0 is returned and the attribute value is stored in the
* destination variable.
*/
unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
{
int val;
val = ntohl(nla_get_be32(attr));
if (val > max)
return -ERANGE;
*dest = val;
return 0;
}
EXPORT_SYMBOL_GPL(nft_parse_u32_check);
/**
* nft_validate_input_register - validate an expressions' input register
*
......
......@@ -54,6 +54,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
{
struct nft_bitwise *priv = nft_expr_priv(expr);
struct nft_data_desc d1, d2;
u32 len;
int err;
if (tb[NFTA_BITWISE_SREG] == NULL ||
......@@ -76,7 +77,11 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
if (err < 0)
return err;
priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
if (err < 0)
return err;
priv->len = len;
err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
if (err < 0)
......
......@@ -78,6 +78,7 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
struct nft_byteorder *priv = nft_expr_priv(expr);
u32 size, len;
int err;
if (tb[NFTA_BYTEORDER_SREG] == NULL ||
......@@ -109,11 +110,21 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
return -EINVAL;
}
priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
if (err < 0)
return err;
priv->len = 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]));
err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size);
if (err < 0)
return err;
priv->size = size;
switch (priv->size) {
case 2:
case 4:
......
......@@ -81,6 +81,9 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
BUG_ON(err < 0);
if (desc.len > U8_MAX)
return -ERANGE;
priv->len = desc.len;
return 0;
}
......
......@@ -67,11 +67,13 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
tb[NFTA_EXTHDR_LEN] == NULL)
return -EINVAL;
offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
err = nft_parse_u32_check(tb[NFTA_EXTHDR_OFFSET], U8_MAX, &offset);
if (err < 0)
return err;
if (offset > U8_MAX || len > U8_MAX)
return -ERANGE;
err = nft_parse_u32_check(tb[NFTA_EXTHDR_LEN], U8_MAX, &len);
if (err < 0)
return err;
priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
priv->offset = offset;
......
......@@ -57,6 +57,10 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
if (err < 0)
return err;
if (desc.len > U8_MAX)
return -ERANGE;
priv->dlen = desc.len;
err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment