Skip to content

Commit

Permalink
netfilter: nf_tables: validate maximum value of u32 netlink attributes
Browse files Browse the repository at this point in the history
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 4da449a ("netfilter: nft_exthdr: Add size check
on u8 nft_exthdr attributes").

Fixes: 9651851 ("netfilter: add nftables")
Suggested-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Laura Garcia Liebana authored and Pablo Neira Ayuso committed Sep 23, 2016
1 parent 2b03bf7 commit 36b701f
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 8 deletions.
1 change: 1 addition & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,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 * NFT_REG_SIZE / NFT_REG32_SIZE;
}

unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
unsigned int nft_parse_register(const struct nlattr *attr);
int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);

Expand Down
25 changes: 25 additions & 0 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -4409,6 +4409,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_parse_register - parse a register value from a netlink attribute
*
Expand Down
8 changes: 7 additions & 1 deletion net/netfilter/nft_bitwise.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,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 ||
Expand All @@ -61,7 +62,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
tb[NFTA_BITWISE_XOR] == NULL)
return -EINVAL;

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;

priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
err = nft_validate_register_load(priv->sreg, priv->len);
if (err < 0)
Expand Down
15 changes: 13 additions & 2 deletions net/netfilter/nft_byteorder.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,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 ||
Expand All @@ -117,7 +118,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
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:
Expand All @@ -128,7 +134,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
}

priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
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;

err = nft_validate_register_load(priv->sreg, priv->len);
if (err < 0)
return err;
Expand Down
3 changes: 3 additions & 0 deletions net/netfilter/nft_cmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
if (err < 0)
return err;

if (desc.len > U8_MAX)
return -ERANGE;

priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
priv->len = desc.len;
return 0;
Expand Down
12 changes: 7 additions & 5 deletions net/netfilter/nft_exthdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,21 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
struct nft_exthdr *priv = nft_expr_priv(expr);
u32 offset, len;
u32 offset, len, err;

if (tb[NFTA_EXTHDR_DREG] == NULL ||
tb[NFTA_EXTHDR_TYPE] == NULL ||
tb[NFTA_EXTHDR_OFFSET] == NULL ||
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;
Expand Down
4 changes: 4 additions & 0 deletions net/netfilter/nft_immediate.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
tb[NFTA_IMMEDIATE_DATA]);
if (err < 0)
return err;

if (desc.len > U8_MAX)
return -ERANGE;

priv->dlen = desc.len;

priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]);
Expand Down

0 comments on commit 36b701f

Please sign in to comment.