diff options
author | Patrick McHardy <kaber@trash.net> | 2015-03-03 15:04:20 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-03-04 12:46:06 -0500 |
commit | 86f1ec32318159a24de349f0a38e79b9d2b3131a (patch) | |
tree | 6533fb1a3354201a635cf4dfdeaa143e2d3de12a | |
parent | 9889840f5988ecfd43b00c9abb83c1804e21406b (diff) |
netfilter: nf_tables: fix userdata length overflow
The NFT_USERDATA_MAXLEN is defined to 256, however we only have a u8
to store its size. Introduce a struct nft_userdata which contains a
length field and indicate its presence using a single bit in the rule.
The length field of struct nft_userdata is also a u8, however we don't
store zero sized data, so the actual length is udata->len + 1.
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 | 22 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 28 |
2 files changed, 38 insertions, 12 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 9eaaa7884586..decb9a095ae7 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -119,6 +119,22 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, | |||
119 | const struct nft_data *data, | 119 | const struct nft_data *data, |
120 | enum nft_data_types type); | 120 | enum nft_data_types type); |
121 | 121 | ||
122 | |||
123 | /** | ||
124 | * struct nft_userdata - user defined data associated with an object | ||
125 | * | ||
126 | * @len: length of the data | ||
127 | * @data: content | ||
128 | * | ||
129 | * The presence of user data is indicated in an object specific fashion, | ||
130 | * so a length of zero can't occur and the value "len" indicates data | ||
131 | * of length len + 1. | ||
132 | */ | ||
133 | struct nft_userdata { | ||
134 | u8 len; | ||
135 | unsigned char data[0]; | ||
136 | }; | ||
137 | |||
122 | /** | 138 | /** |
123 | * struct nft_set_elem - generic representation of set elements | 139 | * struct nft_set_elem - generic representation of set elements |
124 | * | 140 | * |
@@ -380,7 +396,7 @@ static inline void *nft_expr_priv(const struct nft_expr *expr) | |||
380 | * @handle: rule handle | 396 | * @handle: rule handle |
381 | * @genmask: generation mask | 397 | * @genmask: generation mask |
382 | * @dlen: length of expression data | 398 | * @dlen: length of expression data |
383 | * @ulen: length of user data (used for comments) | 399 | * @udata: user data is appended to the rule |
384 | * @data: expression data | 400 | * @data: expression data |
385 | */ | 401 | */ |
386 | struct nft_rule { | 402 | struct nft_rule { |
@@ -388,7 +404,7 @@ struct nft_rule { | |||
388 | u64 handle:42, | 404 | u64 handle:42, |
389 | genmask:2, | 405 | genmask:2, |
390 | dlen:12, | 406 | dlen:12, |
391 | ulen:8; | 407 | udata:1; |
392 | unsigned char data[] | 408 | unsigned char data[] |
393 | __attribute__((aligned(__alignof__(struct nft_expr)))); | 409 | __attribute__((aligned(__alignof__(struct nft_expr)))); |
394 | }; | 410 | }; |
@@ -476,7 +492,7 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule) | |||
476 | return (struct nft_expr *)&rule->data[rule->dlen]; | 492 | return (struct nft_expr *)&rule->data[rule->dlen]; |
477 | } | 493 | } |
478 | 494 | ||
479 | static inline void *nft_userdata(const struct nft_rule *rule) | 495 | static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule) |
480 | { | 496 | { |
481 | return (void *)&rule->data[rule->dlen]; | 497 | return (void *)&rule->data[rule->dlen]; |
482 | } | 498 | } |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 7baafd5ab520..74e4b876c96e 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -1711,9 +1711,12 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, | |||
1711 | } | 1711 | } |
1712 | nla_nest_end(skb, list); | 1712 | nla_nest_end(skb, list); |
1713 | 1713 | ||
1714 | if (rule->ulen && | 1714 | if (rule->udata) { |
1715 | nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule))) | 1715 | struct nft_userdata *udata = nft_userdata(rule); |
1716 | goto nla_put_failure; | 1716 | if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1, |
1717 | udata->data) < 0) | ||
1718 | goto nla_put_failure; | ||
1719 | } | ||
1717 | 1720 | ||
1718 | nlmsg_end(skb, nlh); | 1721 | nlmsg_end(skb, nlh); |
1719 | return 0; | 1722 | return 0; |
@@ -1896,11 +1899,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1896 | struct nft_table *table; | 1899 | struct nft_table *table; |
1897 | struct nft_chain *chain; | 1900 | struct nft_chain *chain; |
1898 | struct nft_rule *rule, *old_rule = NULL; | 1901 | struct nft_rule *rule, *old_rule = NULL; |
1902 | struct nft_userdata *udata; | ||
1899 | struct nft_trans *trans = NULL; | 1903 | struct nft_trans *trans = NULL; |
1900 | struct nft_expr *expr; | 1904 | struct nft_expr *expr; |
1901 | struct nft_ctx ctx; | 1905 | struct nft_ctx ctx; |
1902 | struct nlattr *tmp; | 1906 | struct nlattr *tmp; |
1903 | unsigned int size, i, n, ulen = 0; | 1907 | unsigned int size, i, n, ulen = 0, usize = 0; |
1904 | int err, rem; | 1908 | int err, rem; |
1905 | bool create; | 1909 | bool create; |
1906 | u64 handle, pos_handle; | 1910 | u64 handle, pos_handle; |
@@ -1973,11 +1977,14 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1973 | if (size >= 1 << 12) | 1977 | if (size >= 1 << 12) |
1974 | goto err1; | 1978 | goto err1; |
1975 | 1979 | ||
1976 | if (nla[NFTA_RULE_USERDATA]) | 1980 | if (nla[NFTA_RULE_USERDATA]) { |
1977 | ulen = nla_len(nla[NFTA_RULE_USERDATA]); | 1981 | ulen = nla_len(nla[NFTA_RULE_USERDATA]); |
1982 | if (ulen > 0) | ||
1983 | usize = sizeof(struct nft_userdata) + ulen; | ||
1984 | } | ||
1978 | 1985 | ||
1979 | err = -ENOMEM; | 1986 | err = -ENOMEM; |
1980 | rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL); | 1987 | rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL); |
1981 | if (rule == NULL) | 1988 | if (rule == NULL) |
1982 | goto err1; | 1989 | goto err1; |
1983 | 1990 | ||
@@ -1985,10 +1992,13 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1985 | 1992 | ||
1986 | rule->handle = handle; | 1993 | rule->handle = handle; |
1987 | rule->dlen = size; | 1994 | rule->dlen = size; |
1988 | rule->ulen = ulen; | 1995 | rule->udata = ulen ? 1 : 0; |
1989 | 1996 | ||
1990 | if (ulen) | 1997 | if (ulen) { |
1991 | nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen); | 1998 | udata = nft_userdata(rule); |
1999 | udata->len = ulen - 1; | ||
2000 | nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen); | ||
2001 | } | ||
1992 | 2002 | ||
1993 | expr = nft_expr_first(rule); | 2003 | expr = nft_expr_first(rule); |
1994 | for (i = 0; i < n; i++) { | 2004 | for (i = 0; i < n; i++) { |