diff options
author | Laura Garcia Liebana <nevola@gmail.com> | 2016-09-14 09:00:02 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-09-23 03:29:02 -0400 |
commit | 36b701fae12ac763a568037e4e7c96b5727a8b3e (patch) | |
tree | 51cf6649e755c9ee786cfdbbd9d03a6d22baf37c | |
parent | 2b03bf732488a3c2e920afe22c03b82cb8477e28 (diff) |
netfilter: nf_tables: validate maximum value of u32 netlink attributes
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 4da449ae1df9 ("netfilter: nft_exthdr: Add size check
on u8 nft_exthdr attributes").
Fixes: 96518518cc41 ("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>
-rw-r--r-- | include/net/netfilter/nf_tables.h | 1 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 25 | ||||
-rw-r--r-- | net/netfilter/nft_bitwise.c | 8 | ||||
-rw-r--r-- | net/netfilter/nft_byteorder.c | 15 | ||||
-rw-r--r-- | net/netfilter/nft_cmp.c | 3 | ||||
-rw-r--r-- | net/netfilter/nft_exthdr.c | 12 | ||||
-rw-r--r-- | net/netfilter/nft_immediate.c | 4 |
7 files changed, 60 insertions, 8 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index a7a7cebc8d07..5031e072567b 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -145,6 +145,7 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type) | |||
145 | return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE; | 145 | return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE; |
146 | } | 146 | } |
147 | 147 | ||
148 | unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest); | ||
148 | unsigned int nft_parse_register(const struct nlattr *attr); | 149 | unsigned int nft_parse_register(const struct nlattr *attr); |
149 | int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg); | 150 | int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg); |
150 | 151 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index bd9715e5ff26..b70d3ea1430e 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -4410,6 +4410,31 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, | |||
4410 | } | 4410 | } |
4411 | 4411 | ||
4412 | /** | 4412 | /** |
4413 | * nft_parse_u32_check - fetch u32 attribute and check for maximum value | ||
4414 | * | ||
4415 | * @attr: netlink attribute to fetch value from | ||
4416 | * @max: maximum value to be stored in dest | ||
4417 | * @dest: pointer to the variable | ||
4418 | * | ||
4419 | * Parse, check and store a given u32 netlink attribute into variable. | ||
4420 | * This function returns -ERANGE if the value goes over maximum value. | ||
4421 | * Otherwise a 0 is returned and the attribute value is stored in the | ||
4422 | * destination variable. | ||
4423 | */ | ||
4424 | unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest) | ||
4425 | { | ||
4426 | int val; | ||
4427 | |||
4428 | val = ntohl(nla_get_be32(attr)); | ||
4429 | if (val > max) | ||
4430 | return -ERANGE; | ||
4431 | |||
4432 | *dest = val; | ||
4433 | return 0; | ||
4434 | } | ||
4435 | EXPORT_SYMBOL_GPL(nft_parse_u32_check); | ||
4436 | |||
4437 | /** | ||
4413 | * nft_parse_register - parse a register value from a netlink attribute | 4438 | * nft_parse_register - parse a register value from a netlink attribute |
4414 | * | 4439 | * |
4415 | * @attr: netlink attribute | 4440 | * @attr: netlink attribute |
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index d71cc18fa35d..31c15ed2e5fc 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c | |||
@@ -52,6 +52,7 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, | |||
52 | { | 52 | { |
53 | struct nft_bitwise *priv = nft_expr_priv(expr); | 53 | struct nft_bitwise *priv = nft_expr_priv(expr); |
54 | struct nft_data_desc d1, d2; | 54 | struct nft_data_desc d1, d2; |
55 | u32 len; | ||
55 | int err; | 56 | int err; |
56 | 57 | ||
57 | if (tb[NFTA_BITWISE_SREG] == NULL || | 58 | if (tb[NFTA_BITWISE_SREG] == NULL || |
@@ -61,7 +62,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, | |||
61 | tb[NFTA_BITWISE_XOR] == NULL) | 62 | tb[NFTA_BITWISE_XOR] == NULL) |
62 | return -EINVAL; | 63 | return -EINVAL; |
63 | 64 | ||
64 | priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN])); | 65 | err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len); |
66 | if (err < 0) | ||
67 | return err; | ||
68 | |||
69 | priv->len = len; | ||
70 | |||
65 | priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]); | 71 | priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]); |
66 | err = nft_validate_register_load(priv->sreg, priv->len); | 72 | err = nft_validate_register_load(priv->sreg, priv->len); |
67 | if (err < 0) | 73 | if (err < 0) |
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c index b78c28ba465f..ee63d981268d 100644 --- a/net/netfilter/nft_byteorder.c +++ b/net/netfilter/nft_byteorder.c | |||
@@ -99,6 +99,7 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, | |||
99 | const struct nlattr * const tb[]) | 99 | const struct nlattr * const tb[]) |
100 | { | 100 | { |
101 | struct nft_byteorder *priv = nft_expr_priv(expr); | 101 | struct nft_byteorder *priv = nft_expr_priv(expr); |
102 | u32 size, len; | ||
102 | int err; | 103 | int err; |
103 | 104 | ||
104 | if (tb[NFTA_BYTEORDER_SREG] == NULL || | 105 | if (tb[NFTA_BYTEORDER_SREG] == NULL || |
@@ -117,7 +118,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, | |||
117 | return -EINVAL; | 118 | return -EINVAL; |
118 | } | 119 | } |
119 | 120 | ||
120 | priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE])); | 121 | err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size); |
122 | if (err < 0) | ||
123 | return err; | ||
124 | |||
125 | priv->size = size; | ||
126 | |||
121 | switch (priv->size) { | 127 | switch (priv->size) { |
122 | case 2: | 128 | case 2: |
123 | case 4: | 129 | case 4: |
@@ -128,7 +134,12 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, | |||
128 | } | 134 | } |
129 | 135 | ||
130 | priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]); | 136 | priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]); |
131 | priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN])); | 137 | err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len); |
138 | if (err < 0) | ||
139 | return err; | ||
140 | |||
141 | priv->len = len; | ||
142 | |||
132 | err = nft_validate_register_load(priv->sreg, priv->len); | 143 | err = nft_validate_register_load(priv->sreg, priv->len); |
133 | if (err < 0) | 144 | if (err < 0) |
134 | return err; | 145 | return err; |
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c index e25b35d70e4d..2e53739812b1 100644 --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c | |||
@@ -84,6 +84,9 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
84 | if (err < 0) | 84 | if (err < 0) |
85 | return err; | 85 | return err; |
86 | 86 | ||
87 | if (desc.len > U8_MAX) | ||
88 | return -ERANGE; | ||
89 | |||
87 | priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP])); | 90 | priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP])); |
88 | priv->len = desc.len; | 91 | priv->len = desc.len; |
89 | return 0; | 92 | return 0; |
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c index 82c264e40278..a84cf3d66056 100644 --- a/net/netfilter/nft_exthdr.c +++ b/net/netfilter/nft_exthdr.c | |||
@@ -59,7 +59,7 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, | |||
59 | const struct nlattr * const tb[]) | 59 | const struct nlattr * const tb[]) |
60 | { | 60 | { |
61 | struct nft_exthdr *priv = nft_expr_priv(expr); | 61 | struct nft_exthdr *priv = nft_expr_priv(expr); |
62 | u32 offset, len; | 62 | u32 offset, len, err; |
63 | 63 | ||
64 | if (tb[NFTA_EXTHDR_DREG] == NULL || | 64 | if (tb[NFTA_EXTHDR_DREG] == NULL || |
65 | tb[NFTA_EXTHDR_TYPE] == NULL || | 65 | tb[NFTA_EXTHDR_TYPE] == NULL || |
@@ -67,11 +67,13 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, | |||
67 | tb[NFTA_EXTHDR_LEN] == NULL) | 67 | tb[NFTA_EXTHDR_LEN] == NULL) |
68 | return -EINVAL; | 68 | return -EINVAL; |
69 | 69 | ||
70 | offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET])); | 70 | err = nft_parse_u32_check(tb[NFTA_EXTHDR_OFFSET], U8_MAX, &offset); |
71 | len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN])); | 71 | if (err < 0) |
72 | return err; | ||
72 | 73 | ||
73 | if (offset > U8_MAX || len > U8_MAX) | 74 | err = nft_parse_u32_check(tb[NFTA_EXTHDR_LEN], U8_MAX, &len); |
74 | return -ERANGE; | 75 | if (err < 0) |
76 | return err; | ||
75 | 77 | ||
76 | priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); | 78 | priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); |
77 | priv->offset = offset; | 79 | priv->offset = offset; |
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c index db3b746858e3..d17018ff54e6 100644 --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c | |||
@@ -53,6 +53,10 @@ static int nft_immediate_init(const struct nft_ctx *ctx, | |||
53 | tb[NFTA_IMMEDIATE_DATA]); | 53 | tb[NFTA_IMMEDIATE_DATA]); |
54 | if (err < 0) | 54 | if (err < 0) |
55 | return err; | 55 | return err; |
56 | |||
57 | if (desc.len > U8_MAX) | ||
58 | return -ERANGE; | ||
59 | |||
56 | priv->dlen = desc.len; | 60 | priv->dlen = desc.len; |
57 | 61 | ||
58 | priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]); | 62 | priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]); |