diff options
| author | Patrick McHardy <kaber@trash.net> | 2015-04-10 21:27:26 -0400 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-04-13 10:25:49 -0400 |
| commit | 45d9bcda21f4c13be75e3571b0f0ef39e77934b5 (patch) | |
| tree | 54312412f1a9253360db901877e8b51991777562 | |
| parent | e60a9de49c3744aa44128eaaed3aca965911ca2e (diff) | |
netfilter: nf_tables: validate len in nft_validate_data_load()
For values spanning multiple registers, we need to validate that enough
space is available from the destination register onwards. Add a len
argument to nft_validate_data_load() and consolidate the existing length
validations in preparation of that.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
| -rw-r--r-- | include/net/netfilter/nf_tables.h | 2 | ||||
| -rw-r--r-- | net/bridge/netfilter/nft_meta_bridge.c | 5 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_api.c | 18 | ||||
| -rw-r--r-- | net/netfilter/nft_bitwise.c | 8 | ||||
| -rw-r--r-- | net/netfilter/nft_byteorder.c | 27 | ||||
| -rw-r--r-- | net/netfilter/nft_ct.c | 48 | ||||
| -rw-r--r-- | net/netfilter/nft_exthdr.c | 6 | ||||
| -rw-r--r-- | net/netfilter/nft_immediate.c | 3 | ||||
| -rw-r--r-- | net/netfilter/nft_meta.c | 19 | ||||
| -rw-r--r-- | net/netfilter/nft_payload.c | 7 |
10 files changed, 97 insertions, 46 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index d6a2f0ed5130..f491243ff58b 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
| @@ -116,7 +116,7 @@ int nft_validate_input_register(enum nft_registers reg); | |||
| 116 | int nft_validate_output_register(enum nft_registers reg); | 116 | int nft_validate_output_register(enum nft_registers reg); |
| 117 | int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, | 117 | int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, |
| 118 | const struct nft_data *data, | 118 | const struct nft_data *data, |
| 119 | enum nft_data_types type); | 119 | enum nft_data_types type, unsigned int len); |
| 120 | 120 | ||
| 121 | 121 | ||
| 122 | /** | 122 | /** |
diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c index 4f02109d708f..2011b89690f7 100644 --- a/net/bridge/netfilter/nft_meta_bridge.c +++ b/net/bridge/netfilter/nft_meta_bridge.c | |||
| @@ -53,12 +53,14 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx, | |||
| 53 | const struct nlattr * const tb[]) | 53 | const struct nlattr * const tb[]) |
| 54 | { | 54 | { |
| 55 | struct nft_meta *priv = nft_expr_priv(expr); | 55 | struct nft_meta *priv = nft_expr_priv(expr); |
| 56 | unsigned int len; | ||
| 56 | int err; | 57 | int err; |
| 57 | 58 | ||
| 58 | priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | 59 | priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); |
| 59 | switch (priv->key) { | 60 | switch (priv->key) { |
| 60 | case NFT_META_BRI_IIFNAME: | 61 | case NFT_META_BRI_IIFNAME: |
| 61 | case NFT_META_BRI_OIFNAME: | 62 | case NFT_META_BRI_OIFNAME: |
| 63 | len = IFNAMSIZ; | ||
| 62 | break; | 64 | break; |
| 63 | default: | 65 | default: |
| 64 | return nft_meta_get_init(ctx, expr, tb); | 66 | return nft_meta_get_init(ctx, expr, tb); |
| @@ -69,7 +71,8 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx, | |||
| 69 | if (err < 0) | 71 | if (err < 0) |
| 70 | return err; | 72 | return err; |
| 71 | 73 | ||
| 72 | err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | 74 | err = nft_validate_data_load(ctx, priv->dreg, NULL, |
| 75 | NFT_DATA_VALUE, len); | ||
| 73 | if (err < 0) | 76 | if (err < 0) |
| 74 | return err; | 77 | return err; |
| 75 | 78 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 0b96fa0d64b2..564f9ed6680d 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -2799,7 +2799,8 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, | |||
| 2799 | dreg = nft_type_to_reg(set->dtype); | 2799 | dreg = nft_type_to_reg(set->dtype); |
| 2800 | return nft_validate_data_load(ctx, dreg, nft_set_ext_data(ext), | 2800 | return nft_validate_data_load(ctx, dreg, nft_set_ext_data(ext), |
| 2801 | set->dtype == NFT_DATA_VERDICT ? | 2801 | set->dtype == NFT_DATA_VERDICT ? |
| 2802 | NFT_DATA_VERDICT : NFT_DATA_VALUE); | 2802 | NFT_DATA_VERDICT : NFT_DATA_VALUE, |
| 2803 | set->dlen); | ||
| 2803 | } | 2804 | } |
| 2804 | 2805 | ||
| 2805 | int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, | 2806 | int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, |
| @@ -3334,7 +3335,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
| 3334 | continue; | 3335 | continue; |
| 3335 | 3336 | ||
| 3336 | err = nft_validate_data_load(&bind_ctx, dreg, | 3337 | err = nft_validate_data_load(&bind_ctx, dreg, |
| 3337 | &data, d2.type); | 3338 | &data, d2.type, d2.len); |
| 3338 | if (err < 0) | 3339 | if (err < 0) |
| 3339 | goto err3; | 3340 | goto err3; |
| 3340 | } | 3341 | } |
| @@ -4162,15 +4163,16 @@ EXPORT_SYMBOL_GPL(nft_validate_output_register); | |||
| 4162 | * @reg: the destination register number | 4163 | * @reg: the destination register number |
| 4163 | * @data: the data to load | 4164 | * @data: the data to load |
| 4164 | * @type: the data type | 4165 | * @type: the data type |
| 4166 | * @len: the length of the data | ||
| 4165 | * | 4167 | * |
| 4166 | * Validate that a data load uses the appropriate data type for | 4168 | * Validate that a data load uses the appropriate data type for |
| 4167 | * the destination register. A value of NULL for the data means | 4169 | * the destination register and the length is within the bounds. |
| 4168 | * that its runtime gathered data, which is always of type | 4170 | * A value of NULL for the data means that its runtime gathered |
| 4169 | * NFT_DATA_VALUE. | 4171 | * data, which is always of type NFT_DATA_VALUE. |
| 4170 | */ | 4172 | */ |
| 4171 | int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, | 4173 | int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, |
| 4172 | const struct nft_data *data, | 4174 | const struct nft_data *data, |
| 4173 | enum nft_data_types type) | 4175 | enum nft_data_types type, unsigned int len) |
| 4174 | { | 4176 | { |
| 4175 | int err; | 4177 | int err; |
| 4176 | 4178 | ||
| @@ -4193,6 +4195,10 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, | |||
| 4193 | 4195 | ||
| 4194 | return 0; | 4196 | return 0; |
| 4195 | default: | 4197 | default: |
| 4198 | if (len == 0) | ||
| 4199 | return -EINVAL; | ||
| 4200 | if (len > FIELD_SIZEOF(struct nft_data, data)) | ||
| 4201 | return -ERANGE; | ||
| 4196 | if (data != NULL && type != NFT_DATA_VALUE) | 4202 | if (data != NULL && type != NFT_DATA_VALUE) |
| 4197 | return -EINVAL; | 4203 | return -EINVAL; |
| 4198 | return 0; | 4204 | return 0; |
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index 4fb6ee2c1106..fcd951f24779 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c | |||
| @@ -63,6 +63,8 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, | |||
| 63 | tb[NFTA_BITWISE_XOR] == NULL) | 63 | tb[NFTA_BITWISE_XOR] == NULL) |
| 64 | return -EINVAL; | 64 | return -EINVAL; |
| 65 | 65 | ||
| 66 | priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN])); | ||
| 67 | |||
| 66 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG])); | 68 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG])); |
| 67 | err = nft_validate_input_register(priv->sreg); | 69 | err = nft_validate_input_register(priv->sreg); |
| 68 | if (err < 0) | 70 | if (err < 0) |
| @@ -72,12 +74,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx, | |||
| 72 | err = nft_validate_output_register(priv->dreg); | 74 | err = nft_validate_output_register(priv->dreg); |
| 73 | if (err < 0) | 75 | if (err < 0) |
| 74 | return err; | 76 | return err; |
| 75 | err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | 77 | |
| 78 | err = nft_validate_data_load(ctx, priv->dreg, NULL, | ||
| 79 | NFT_DATA_VALUE, priv->len); | ||
| 76 | if (err < 0) | 80 | if (err < 0) |
| 77 | return err; | 81 | return err; |
| 78 | 82 | ||
| 79 | priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN])); | ||
| 80 | |||
| 81 | err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]); | 83 | err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]); |
| 82 | if (err < 0) | 84 | if (err < 0) |
| 83 | return err; | 85 | return err; |
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c index c39ed8d29df1..183f13308c94 100644 --- a/net/netfilter/nft_byteorder.c +++ b/net/netfilter/nft_byteorder.c | |||
| @@ -87,19 +87,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, | |||
| 87 | tb[NFTA_BYTEORDER_OP] == NULL) | 87 | tb[NFTA_BYTEORDER_OP] == NULL) |
| 88 | return -EINVAL; | 88 | return -EINVAL; |
| 89 | 89 | ||
| 90 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG])); | ||
| 91 | err = nft_validate_input_register(priv->sreg); | ||
| 92 | if (err < 0) | ||
| 93 | return err; | ||
| 94 | |||
| 95 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG])); | ||
| 96 | err = nft_validate_output_register(priv->dreg); | ||
| 97 | if (err < 0) | ||
| 98 | return err; | ||
| 99 | err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | ||
| 100 | if (err < 0) | ||
| 101 | return err; | ||
| 102 | |||
| 103 | priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP])); | 90 | priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP])); |
| 104 | switch (priv->op) { | 91 | switch (priv->op) { |
| 105 | case NFT_BYTEORDER_NTOH: | 92 | case NFT_BYTEORDER_NTOH: |
| @@ -122,6 +109,20 @@ static int nft_by | |||
