netfilter: nf_tables: introduce nft_validate_register_load()
authorPatrick McHardy <kaber@trash.net>
Sat, 11 Apr 2015 01:27:30 +0000 (02:27 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 13 Apr 2015 14:25:50 +0000 (16:25 +0200)
Change nft_validate_input_register() to not only validate the input
register number, but also the length of the load, and rename it to
nft_validate_register_load() to reflect that change.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_bitwise.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_cmp.c
net/netfilter/nft_ct.c
net/netfilter/nft_dynset.c
net/netfilter/nft_lookup.c
net/netfilter/nft_meta.c
net/netfilter/nft_nat.c
net/netfilter/nft_redir.c

index a8d4bd3edb26cca9dc4f10dfc8ad0ae596b76f05..9cc3d55d8fa13c922e8f4933ae195cf97e06d3a0 100644 (file)
@@ -112,13 +112,12 @@ 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;
 }
 
-int nft_validate_input_register(enum nft_registers reg);
+int nft_validate_register_load(enum nft_registers reg, unsigned int len);
 int nft_validate_register_store(const struct nft_ctx *ctx,
                                enum nft_registers reg,
                                const struct nft_data *data,
                                enum nft_data_types type, unsigned int len);
 
-
 /**
  *     struct nft_userdata - user defined data associated with an object
  *
index f01e89fe3c359d84e616c3afd54197d9f8ce2e83..d47f12b2af25024637b62d7db7c81bcda69e2838 100644 (file)
@@ -4122,22 +4122,27 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
 }
 
 /**
- *     nft_validate_input_register - validate an expressions' input register
+ *     nft_validate_register_load - validate a load from a register
  *
  *     @reg: the register number
+ *     @len: the length of the data
  *
  *     Validate that the input register is one of the general purpose
- *     registers.
+ *     registers and that the length of the load is within the bounds.
  */
-int nft_validate_input_register(enum nft_registers reg)
+int nft_validate_register_load(enum nft_registers reg, unsigned int len)
 {
        if (reg <= NFT_REG_VERDICT)
                return -EINVAL;
        if (reg > NFT_REG_MAX)
                return -ERANGE;
+       if (len == 0)
+               return -EINVAL;
+       if (len > FIELD_SIZEOF(struct nft_data, data))
+               return -ERANGE;
        return 0;
 }
-EXPORT_SYMBOL_GPL(nft_validate_input_register);
+EXPORT_SYMBOL_GPL(nft_validate_register_load);
 
 /**
  *     nft_validate_register_store - validate an expressions' register store
index d312052873666999ee8dce6987985ca9cca3c47f..60050eeca1f6b75624a9b251b8ea75d8b6f65775 100644 (file)
@@ -63,10 +63,9 @@ 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]));
-
+       priv->len  = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
        priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       err = nft_validate_register_load(priv->sreg, priv->len);
        if (err < 0)
                return err;
 
index 848bce0323501a14032879179d8c04cfc491b6e2..f34bfbdd6ba2a4e4e90c2b13455beb62a1b8b242 100644 (file)
@@ -96,10 +96,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
                return -EINVAL;
        }
 
-       priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_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]));
        switch (priv->size) {
        case 2:
@@ -110,7 +106,8 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
        }
 
        priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       priv->len  = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
+       err = nft_validate_register_load(priv->sreg, priv->len);
        if (err < 0)
                return err;
 
index e2b3f51c81f1df0289d75142689fcd109c351d0b..17e9b8beaa1d034ad37efd8ea63f024015d588af 100644 (file)
@@ -75,12 +75,15 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct nft_data_desc desc;
        int err;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-       priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
-
        err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
        BUG_ON(err < 0);
 
+       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
+       err = nft_validate_register_load(priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+
+       priv->op  = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
        priv->len = desc.len;
        return 0;
 }
@@ -122,13 +125,17 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
        u32 mask;
        int err;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-
        err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
        BUG_ON(err < 0);
-       desc.len *= BITS_PER_BYTE;
 
+       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
+       err = nft_validate_register_load(priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+
+       desc.len *= BITS_PER_BYTE;
        mask = nft_cmp_fast_mask(desc.len);
+
        priv->data = data.data[0] & mask;
        priv->len  = desc.len;
        return 0;
@@ -167,7 +174,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
 {
        struct nft_data_desc desc;
        struct nft_data data;
-       enum nft_registers sreg;
        enum nft_cmp_ops op;
        int err;
 
@@ -176,11 +182,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
            tb[NFTA_CMP_DATA] == NULL)
                return ERR_PTR(-EINVAL);
 
-       sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-       err = nft_validate_input_register(sreg);
-       if (err < 0)
-               return ERR_PTR(err);
-
        op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
        switch (op) {
        case NFT_CMP_EQ:
index d85f9ad921f29eec6aeb87b1039b73939cb920dc..6bf6ed710de1da6d95fac022e479a30a945c1fca 100644 (file)
@@ -324,12 +324,14 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_ct *priv = nft_expr_priv(expr);
+       unsigned int len;
        int err;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
        switch (priv->key) {
 #ifdef CONFIG_NF_CONNTRACK_MARK
        case NFT_CT_MARK:
+               len = FIELD_SIZEOF(struct nf_conn, mark);
                break;
 #endif
        default:
@@ -337,7 +339,7 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
        }
 
        priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       err = nft_validate_register_load(priv->sreg, len);
        if (err < 0)
                return err;
 
index eeb72dee78ef0d92b65886fb90a8ce1983a60f3b..3ea52b701e2b816dbe0be486ae49a1b99a5a22a6 100644 (file)
@@ -124,7 +124,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
        }
 
        priv->sreg_key = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_KEY]));
-       err = nft_validate_input_register(priv->sreg_key);
+       err = nft_validate_register_load(priv->sreg_key, set->klen);;
        if (err < 0)
                return err;
 
@@ -135,7 +135,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                        return -EOPNOTSUPP;
 
                priv->sreg_data = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_DATA]));
-               err = nft_validate_input_register(priv->sreg_data);
+               err = nft_validate_register_load(priv->sreg_data, set->dlen);
                if (err < 0)
                        return err;
        } else if (set->flags & NFT_SET_MAP)
index 3574543475c2ee2f43d13370a8a1a752efb05d61..8fc0d186e0fa35fed02cc9ff3b22201aa9806e5b 100644 (file)
@@ -71,7 +71,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
        }
 
        priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       err = nft_validate_register_load(priv->sreg, set->klen);
        if (err < 0)
                return err;
 
index fbaee1d373bb3eb3201fdac2dfd1a9012ca35030..0ae6bb73241814b87e4bd6135b3557c5ad7f9d1c 100644 (file)
@@ -267,20 +267,24 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
                      const struct nlattr * const tb[])
 {
        struct nft_meta *priv = nft_expr_priv(expr);
+       unsigned int len;
        int err;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
        switch (priv->key) {
        case NFT_META_MARK:
        case NFT_META_PRIORITY:
+               len = sizeof(u32);
+               break;
        case NFT_META_NFTRACE:
+               len = sizeof(u8);
                break;
        default:
                return -EOPNOTSUPP;
        }
 
        priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       err = nft_validate_register_load(priv->sreg, len);
        if (err < 0)
                return err;
 
index a0837c6c9283dc90b043750ffe1d7217c95ab239..0897a807a2a6fe8d93152cc1189992cf7a15e428 100644 (file)
@@ -119,6 +119,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        const struct nlattr * const tb[])
 {
        struct nft_nat *priv = nft_expr_priv(expr);
+       unsigned int alen, plen;
        u32 family;
        int err;
 
@@ -146,17 +147,25 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                return -EINVAL;
 
        family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
-       if (family != AF_INET && family != AF_INET6)
-               return -EAFNOSUPPORT;
        if (family != ctx->afi->family)
                return -EOPNOTSUPP;
+
+       switch (family) {
+       case NFPROTO_IPV4:
+               alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip);
+               break;
+       case NFPROTO_IPV6:
+               alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip6);
+               break;
+       default:
+               return -EAFNOSUPPORT;
+       }
        priv->family = family;
 
        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
                priv->sreg_addr_min =
                        ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));
-
-               err = nft_validate_input_register(priv->sreg_addr_min);
+               err = nft_validate_register_load(priv->sreg_addr_min, alen);
                if (err < 0)
                        return err;
 
@@ -164,7 +173,8 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        priv->sreg_addr_max =
                                ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));
 
-                       err = nft_validate_input_register(priv->sreg_addr_max);
+                       err = nft_validate_register_load(priv->sreg_addr_max,
+                                                        alen);
                        if (err < 0)
                                return err;
                } else {
@@ -172,11 +182,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                }
        }
 
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
        if (tb[NFTA_NAT_REG_PROTO_MIN]) {
                priv->sreg_proto_min =
                        ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));
 
-               err = nft_validate_input_register(priv->sreg_proto_min);
+               err = nft_validate_register_load(priv->sreg_proto_min, plen);
                if (err < 0)
                        return err;
 
@@ -184,7 +195,8 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        priv->sreg_proto_max =
                                ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));
 
-                       err = nft_validate_input_register(priv->sreg_proto_max);
+                       err = nft_validate_register_load(priv->sreg_proto_max,
+                                                        plen);
                        if (err < 0)
                                return err;
                } else {
index d7e9e93a4e90f498f7a002c33840c928a3ab17e2..981946635c7132e5221ea19a5cf2b067f2b55059 100644 (file)
@@ -44,17 +44,19 @@ int nft_redir_init(const struct nft_ctx *ctx,
                   const struct nlattr * const tb[])
 {
        struct nft_redir *priv = nft_expr_priv(expr);
+       unsigned int plen;
        int err;
 
        err = nft_redir_validate(ctx, expr, NULL);
        if (err < 0)
                return err;
 
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
        if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
                priv->sreg_proto_min =
                        ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MIN]));
 
-               err = nft_validate_input_register(priv->sreg_proto_min);
+               err = nft_validate_register_load(priv->sreg_proto_min, plen);
                if (err < 0)
                        return err;
 
@@ -62,7 +64,8 @@ int nft_redir_init(const struct nft_ctx *ctx,
                        priv->sreg_proto_max =
                                ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MAX]));
 
-                       err = nft_validate_input_register(priv->sreg_proto_max);
+                       err = nft_validate_register_load(priv->sreg_proto_max,
+                                                        plen);
                        if (err < 0)
                                return err;
                } else {