| From: Pablo Neira Ayuso <pablo@netfilter.org> |
| Date: Mon, 15 May 2017 11:17:29 +0100 |
| Subject: netfilter: nf_tables: missing sanitization in data from userspace |
| |
| commit 71df14b0ce094be46d105b5a3ededd83b8e779a0 upstream. |
| |
| Do not assume userspace always sends us NFT_DATA_VALUE for bitwise and |
| cmp expressions. Although NFT_DATA_VERDICT does not make any sense, it |
| is still possible to handcraft a netlink message using this incorrect |
| data type. |
| |
| Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| net/netfilter/nft_bitwise.c | 19 ++++++++++++++----- |
| net/netfilter/nft_cmp.c | 12 ++++++++++-- |
| 2 files changed, 24 insertions(+), 7 deletions(-) |
| |
| --- a/net/netfilter/nft_bitwise.c |
| +++ b/net/netfilter/nft_bitwise.c |
| @@ -86,16 +86,25 @@ static int nft_bitwise_init(const struct |
| err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]); |
| if (err < 0) |
| return err; |
| - if (d1.len != priv->len) |
| - return -EINVAL; |
| + if (d1.len != priv->len) { |
| + err = -EINVAL; |
| + goto err1; |
| + } |
| |
| err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]); |
| if (err < 0) |
| - return err; |
| - if (d2.len != priv->len) |
| - return -EINVAL; |
| + goto err1; |
| + if (d2.len != priv->len) { |
| + err = -EINVAL; |
| + goto err2; |
| + } |
| |
| return 0; |
| +err2: |
| + nft_data_uninit(&priv->xor, d2.type); |
| +err1: |
| + nft_data_uninit(&priv->mask, d1.type); |
| + return err; |
| } |
| |
| static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr) |
| --- a/net/netfilter/nft_cmp.c |
| +++ b/net/netfilter/nft_cmp.c |
| @@ -201,10 +201,18 @@ nft_cmp_select_ops(const struct nft_ctx |
| if (err < 0) |
| return ERR_PTR(err); |
| |
| + if (desc.type != NFT_DATA_VALUE) { |
| + err = -EINVAL; |
| + goto err1; |
| + } |
| + |
| if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ) |
| return &nft_cmp_fast_ops; |
| - else |
| - return &nft_cmp_ops; |
| + |
| + return &nft_cmp_ops; |
| +err1: |
| + nft_data_uninit(&data, desc.type); |
| + return ERR_PTR(-EINVAL); |
| } |
| |
| static struct nft_expr_type nft_cmp_type __read_mostly = { |