Skip to content

Commit 45d9bcd

Browse files
kaberummakynes
authored andcommitted
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>
1 parent e60a9de commit 45d9bcd

File tree

10 files changed

+97
-46
lines changed

10 files changed

+97
-46
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ int nft_validate_input_register(enum nft_registers reg);
116116
int nft_validate_output_register(enum nft_registers reg);
117117
int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
118118
const struct nft_data *data,
119-
enum nft_data_types type);
119+
enum nft_data_types type, unsigned int len);
120120

121121

122122
/**

net/bridge/netfilter/nft_meta_bridge.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
5353
const struct nlattr * const tb[])
5454
{
5555
struct nft_meta *priv = nft_expr_priv(expr);
56+
unsigned int len;
5657
int err;
5758

5859
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
5960
switch (priv->key) {
6061
case NFT_META_BRI_IIFNAME:
6162
case NFT_META_BRI_OIFNAME:
63+
len = IFNAMSIZ;
6264
break;
6365
default:
6466
return nft_meta_get_init(ctx, expr, tb);
@@ -69,7 +71,8 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
6971
if (err < 0)
7072
return err;
7173

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);
7376
if (err < 0)
7477
return err;
7578

net/netfilter/nf_tables_api.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,7 +2799,8 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
27992799
dreg = nft_type_to_reg(set->dtype);
28002800
return nft_validate_data_load(ctx, dreg, nft_set_ext_data(ext),
28012801
set->dtype == NFT_DATA_VERDICT ?
2802-
NFT_DATA_VERDICT : NFT_DATA_VALUE);
2802+
NFT_DATA_VERDICT : NFT_DATA_VALUE,
2803+
set->dlen);
28032804
}
28042805

28052806
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,
33343335
continue;
33353336

33363337
err = nft_validate_data_load(&bind_ctx, dreg,
3337-
&data, d2.type);
3338+
&data, d2.type, d2.len);
33383339
if (err < 0)
33393340
goto err3;
33403341
}
@@ -4162,15 +4163,16 @@ EXPORT_SYMBOL_GPL(nft_validate_output_register);
41624163
* @reg: the destination register number
41634164
* @data: the data to load
41644165
* @type: the data type
4166+
* @len: the length of the data
41654167
*
41664168
* Validate that a data load uses the appropriate data type for
4167-
* the destination register. A value of NULL for the data means
4168-
* that its runtime gathered data, which is always of type
4169-
* NFT_DATA_VALUE.
4169+
* the destination register and the length is within the bounds.
4170+
* A value of NULL for the data means that its runtime gathered
4171+
* data, which is always of type NFT_DATA_VALUE.
41704172
*/
41714173
int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
41724174
const struct nft_data *data,
4173-
enum nft_data_types type)
4175+
enum nft_data_types type, unsigned int len)
41744176
{
41754177
int err;
41764178

@@ -4193,6 +4195,10 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
41934195

41944196
return 0;
41954197
default:
4198+
if (len == 0)
4199+
return -EINVAL;
4200+
if (len > FIELD_SIZEOF(struct nft_data, data))
4201+
return -ERANGE;
41964202
if (data != NULL && type != NFT_DATA_VALUE)
41974203
return -EINVAL;
41984204
return 0;

net/netfilter/nft_bitwise.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
6363
tb[NFTA_BITWISE_XOR] == NULL)
6464
return -EINVAL;
6565

66+
priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
67+
6668
priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
6769
err = nft_validate_input_register(priv->sreg);
6870
if (err < 0)
@@ -72,12 +74,12 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
7274
err = nft_validate_output_register(priv->dreg);
7375
if (err < 0)
7476
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);
7680
if (err < 0)
7781
return err;
7882

79-
priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
80-
8183
err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
8284
if (err < 0)
8385
return err;

net/netfilter/nft_byteorder.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
8787
tb[NFTA_BYTEORDER_OP] == NULL)
8888
return -EINVAL;
8989

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-
10390
priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
10491
switch (priv->op) {
10592
case NFT_BYTEORDER_NTOH:
@@ -122,6 +109,20 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
122109
return -EINVAL;
123110
}
124111

112+
priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
113+
err = nft_validate_input_register(priv->sreg);
114+
if (err < 0)
115+
return err;
116+
117+
priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG]));
118+
err = nft_validate_output_register(priv->dreg);
119+
if (err < 0)
120+
return err;
121+
err = nft_validate_data_load(ctx, priv->dreg, NULL,
122+
NFT_DATA_VALUE, priv->len);
123+
if (err < 0)
124+
return err;
125+
125126
return 0;
126127
}
127128

net/netfilter/nft_ct.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
9595
helper = rcu_dereference(help->helper);
9696
if (helper == NULL)
9797
goto err;
98-
if (strlen(helper->name) >= sizeof(dest->data))
99-
goto err;
10098
strncpy((char *)dest->data, helper->name, sizeof(dest->data));
10199
return;
102100
#ifdef CONFIG_NF_CONNTRACK_LABELS
@@ -109,9 +107,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
109107
return;
110108
}
111109

112-
BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > sizeof(dest->data));
113110
size = labels->words * sizeof(long);
114-
115111
memcpy(dest->data, labels->bits, size);
116112
if (size < sizeof(dest->data))
117113
memset(((char *) dest->data) + size, 0,
@@ -228,35 +224,72 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
228224
const struct nlattr * const tb[])
229225
{
230226
struct nft_ct *priv = nft_expr_priv(expr);
227+
unsigned int len;
231228
int err;
232229

233230
priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
234231
switch (priv->key) {
235-
case NFT_CT_STATE:
236232
case NFT_CT_DIRECTION:
233+
if (tb[NFTA_CT_DIRECTION] != NULL)
234+
return -EINVAL;
235+
len = sizeof(u8);
236+
break;
237+
case NFT_CT_STATE:
237238
case NFT_CT_STATUS:
238239
#ifdef CONFIG_NF_CONNTRACK_MARK
239240
case NFT_CT_MARK:
240241
#endif
241242
#ifdef CONFIG_NF_CONNTRACK_SECMARK
242243
case NFT_CT_SECMARK:
243244
#endif
245+
case NFT_CT_EXPIRATION:
246+
if (tb[NFTA_CT_DIRECTION] != NULL)
247+
return -EINVAL;
248+
len = sizeof(u32);
249+
break;
244250
#ifdef CONFIG_NF_CONNTRACK_LABELS
245251
case NFT_CT_LABELS:
252+
if (tb[NFTA_CT_DIRECTION] != NULL)
253+
return -EINVAL;
254+
len = NF_CT_LABELS_MAX_SIZE;
255+
break;
246256
#endif
247-
case NFT_CT_EXPIRATION:
248257
case NFT_CT_HELPER:
249258
if (tb[NFTA_CT_DIRECTION] != NULL)
250259
return -EINVAL;
260+
len = NF_CT_HELPER_NAME_LEN;
251261
break;
262+
252263
case NFT_CT_L3PROTOCOL:
253264
case NFT_CT_PROTOCOL:
265+
if (tb[NFTA_CT_DIRECTION] == NULL)
266+
return -EINVAL;
267+
len = sizeof(u8);
268+
break;
254269
case NFT_CT_SRC:
255270
case NFT_CT_DST:
271+
if (tb[NFTA_CT_DIRECTION] == NULL)
272+
return -EINVAL;
273+
274+
switch (ctx->afi->family) {
275+
case NFPROTO_IPV4:
276+
len = FIELD_SIZEOF(struct nf_conntrack_tuple,
277+
src.u3.ip);
278+
break;
279+
case NFPROTO_IPV6:
280+
case NFPROTO_INET:
281+
len = FIELD_SIZEOF(struct nf_conntrack_tuple,
282+
src.u3.ip6);
283+
break;
284+
default:
285+
return -EAFNOSUPPORT;
286+
}
287+
break;
256288
case NFT_CT_PROTO_SRC:
257289
case NFT_CT_PROTO_DST:
258290
if (tb[NFTA_CT_DIRECTION] == NULL)
259291
return -EINVAL;
292+
len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
260293
break;
261294
default:
262295
return -EOPNOTSUPP;
@@ -278,7 +311,8 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
278311
if (err < 0)
279312
return err;
280313

281-
err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
314+
err = nft_validate_data_load(ctx, priv->dreg, NULL,
315+
NFT_DATA_VALUE, len);
282316
if (err < 0)
283317
return err;
284318

net/netfilter/nft_exthdr.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,13 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
6969
priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
7070
priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
7171
priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
72-
if (priv->len == 0 ||
73-
priv->len > FIELD_SIZEOF(struct nft_data, data))
74-
return -EINVAL;
7572

7673
priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG]));
7774
err = nft_validate_output_register(priv->dreg);
7875
if (err < 0)
7976
return err;
80-
return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
77+
return nft_validate_data_load(ctx, priv->dreg, NULL,
78+
NFT_DATA_VALUE, priv->len);
8179
}
8280

8381
static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)

net/netfilter/nft_immediate.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
5959
return err;
6060
priv->dlen = desc.len;
6161

62-
err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
62+
err = nft_validate_data_load(ctx, priv->dreg, &priv->data,
63+
desc.type, desc.len);
6364
if (err < 0)
6465
goto err1;
6566

net/netfilter/nft_meta.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,22 +217,23 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
217217
const struct nlattr * const tb[])
218218
{
219219
struct nft_meta *priv = nft_expr_priv(expr);
220+
unsigned int len;
220221
int err;
221222

222223
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
223224
switch (priv->key) {
224-
case NFT_META_LEN:
225225
case NFT_META_PROTOCOL:
226+
case NFT_META_IIFTYPE:
227+
case NFT_META_OIFTYPE:
228+
len = sizeof(u16);
229+
break;
226230
case NFT_META_NFPROTO:
227231
case NFT_META_L4PROTO:
232+
case NFT_META_LEN:
228233
case NFT_META_PRIORITY:
229234
case NFT_META_MARK:
230235
case NFT_META_IIF:
231236
case NFT_META_OIF:
232-
case NFT_META_IIFNAME:
233-
case NFT_META_OIFNAME:
234-
case NFT_META_IIFTYPE:
235-
case NFT_META_OIFTYPE:
236237
case NFT_META_SKUID:
237238
case NFT_META_SKGID:
238239
#ifdef CONFIG_IP_ROUTE_CLASSID
@@ -246,6 +247,11 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
246247
case NFT_META_IIFGROUP:
247248
case NFT_META_OIFGROUP:
248249
case NFT_META_CGROUP:
250+
len = sizeof(u32);
251+
break;
252+
case NFT_META_IIFNAME:
253+
case NFT_META_OIFNAME:
254+
len = IFNAMSIZ;
249255
break;
250256
default:
251257
return -EOPNOTSUPP;
@@ -256,7 +262,8 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
256262
if (err < 0)
257263
return err;
258264

259-
err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
265+
err = nft_validate_data_load(ctx, priv->dreg, NULL,
266+
NFT_DATA_VALUE, len);
260267
if (err < 0)
261268
return err;
262269

net/netfilter/nft_payload.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ static int nft_payload_init(const struct nft_ctx *ctx,
7272
err = nft_validate_output_register(priv->dreg);
7373
if (err < 0)
7474
return err;
75-
return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
75+
return nft_validate_data_load(ctx, priv->dreg, NULL,
76+
NFT_DATA_VALUE, priv->len);
7677
}
7778

7879
static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
@@ -131,9 +132,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
131132
}
132133

133134
offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
134-
len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
135-
if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
136-
return ERR_PTR(-EINVAL);
135+
len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
137136

138137
if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
139138
base != NFT_PAYLOAD_LL_HEADER)

0 commit comments

Comments
 (0)