Blame view

net/netfilter/nft_compat.c 23.6 KB
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/netlink.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter/nfnetlink.h>
  #include <linux/netfilter/nf_tables.h>
  #include <linux/netfilter/nf_tables_compat.h>
  #include <linux/netfilter/x_tables.h>
  #include <linux/netfilter_ipv4/ip_tables.h>
  #include <linux/netfilter_ipv6/ip6_tables.h>
5191f4d82   Arturo Borrero   netfilter: nft_co...
22
  #include <linux/netfilter_bridge/ebtables.h>
5f1589394   Arturo Borrero   netfilter: nft_co...
23
  #include <linux/netfilter_arp/arp_tables.h>
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
24
  #include <net/netfilter/nf_tables.h>
4b512e1c1   Liping Zhang   netfilter: nft_co...
25
26
27
28
  struct nft_xt {
  	struct list_head	head;
  	struct nft_expr_ops	ops;
  	unsigned int		refcnt;
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
29
30
31
32
33
34
35
  
  	/* Unlike other expressions, ops doesn't have static storage duration.
  	 * nft core assumes they do.  We use kfree_rcu so that nft core can
  	 * can check expr->ops->size even after nft_compat->destroy() frees
  	 * the nft_xt struct that holds the ops structure.
  	 */
  	struct rcu_head		rcu_head;
4b512e1c1   Liping Zhang   netfilter: nft_co...
36
  };
365e73e07   Florian Westphal   netfilter: nft_co...
37
38
39
40
41
42
  /* Used for matches where *info is larger than X byte */
  #define NFT_MATCH_LARGE_THRESH	192
  
  struct nft_xt_match_priv {
  	void *info;
  };
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
43
  static bool nft_xt_put(struct nft_xt *xt)
4b512e1c1   Liping Zhang   netfilter: nft_co...
44
45
46
  {
  	if (--xt->refcnt == 0) {
  		list_del(&xt->head);
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
47
48
  		kfree_rcu(xt, rcu_head);
  		return true;
4b512e1c1   Liping Zhang   netfilter: nft_co...
49
  	}
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
50
51
  
  	return false;
4b512e1c1   Liping Zhang   netfilter: nft_co...
52
  }
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
53
54
55
  static int nft_compat_chain_validate_dependency(const char *tablename,
  						const struct nft_chain *chain)
  {
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
56
  	const struct nft_base_chain *basechain;
f323d9546   Pablo Neira Ayuso   netfilter: nf_tab...
57
58
  	if (!tablename ||
  	    !nft_is_base_chain(chain))
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
59
  		return 0;
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
60
  	basechain = nft_base_chain(chain);
c918687f5   Pablo Neira Ayuso   netfilter: nft_co...
61
62
  	if (strcmp(tablename, "nat") == 0 &&
  	    basechain->type->type != NFT_CHAIN_T_NAT)
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
63
64
65
66
  		return -EINVAL;
  
  	return 0;
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
67
68
69
  union nft_entry {
  	struct ipt_entry e4;
  	struct ip6t_entry e6;
5191f4d82   Arturo Borrero   netfilter: nft_co...
70
  	struct ebt_entry ebt;
5f1589394   Arturo Borrero   netfilter: nft_co...
71
  	struct arpt_entry arp;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
72
73
74
75
76
77
78
79
80
  };
  
  static inline void
  nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
  {
  	par->target	= xt;
  	par->targinfo	= xt_info;
  	par->hotdrop	= false;
  }
5191f4d82   Arturo Borrero   netfilter: nft_co...
81
  static void nft_target_eval_xt(const struct nft_expr *expr,
a55e22e92   Patrick McHardy   netfilter: nf_tab...
82
  			       struct nft_regs *regs,
5191f4d82   Arturo Borrero   netfilter: nft_co...
83
  			       const struct nft_pktinfo *pkt)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
84
85
86
87
88
89
90
91
92
93
94
95
  {
  	void *info = nft_expr_priv(expr);
  	struct xt_target *target = expr->ops->data;
  	struct sk_buff *skb = pkt->skb;
  	int ret;
  
  	nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
  
  	ret = target->target(skb, &pkt->xt);
  
  	if (pkt->xt.hotdrop)
  		ret = NF_DROP;
5191f4d82   Arturo Borrero   netfilter: nft_co...
96
  	switch (ret) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
97
  	case XT_CONTINUE:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
98
  		regs->verdict.code = NFT_CONTINUE;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
99
100
  		break;
  	default:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
101
  		regs->verdict.code = ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
102
103
  		break;
  	}
5191f4d82   Arturo Borrero   netfilter: nft_co...
104
105
106
  }
  
  static void nft_target_eval_bridge(const struct nft_expr *expr,
a55e22e92   Patrick McHardy   netfilter: nf_tab...
107
  				   struct nft_regs *regs,
5191f4d82   Arturo Borrero   netfilter: nft_co...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  				   const struct nft_pktinfo *pkt)
  {
  	void *info = nft_expr_priv(expr);
  	struct xt_target *target = expr->ops->data;
  	struct sk_buff *skb = pkt->skb;
  	int ret;
  
  	nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
  
  	ret = target->target(skb, &pkt->xt);
  
  	if (pkt->xt.hotdrop)
  		ret = NF_DROP;
  
  	switch (ret) {
  	case EBT_ACCEPT:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
124
  		regs->verdict.code = NF_ACCEPT;
5191f4d82   Arturo Borrero   netfilter: nft_co...
125
126
  		break;
  	case EBT_DROP:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
127
  		regs->verdict.code = NF_DROP;
5191f4d82   Arturo Borrero   netfilter: nft_co...
128
129
  		break;
  	case EBT_CONTINUE:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
130
  		regs->verdict.code = NFT_CONTINUE;
5191f4d82   Arturo Borrero   netfilter: nft_co...
131
132
  		break;
  	case EBT_RETURN:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
133
  		regs->verdict.code = NFT_RETURN;
5191f4d82   Arturo Borrero   netfilter: nft_co...
134
135
  		break;
  	default:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
136
  		regs->verdict.code = ret;
5191f4d82   Arturo Borrero   netfilter: nft_co...
137
138
  		break;
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
139
140
141
142
143
144
145
146
147
148
149
150
  }
  
  static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
  	[NFTA_TARGET_NAME]	= { .type = NLA_NUL_STRING },
  	[NFTA_TARGET_REV]	= { .type = NLA_U32 },
  	[NFTA_TARGET_INFO]	= { .type = NLA_BINARY },
  };
  
  static void
  nft_target_set_tgchk_param(struct xt_tgchk_param *par,
  			   const struct nft_ctx *ctx,
  			   struct xt_target *target, void *info,
2156d321b   Arturo Borrero   netfilter: nft_co...
151
  			   union nft_entry *entry, u16 proto, bool inv)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
152
  {
2daf1b4d1   Pablo Neira Ayuso   netfilter: nft_co...
153
  	par->net	= ctx->net;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
154
155
156
157
158
159
160
  	par->table	= ctx->table->name;
  	switch (ctx->afi->family) {
  	case AF_INET:
  		entry->e4.ip.proto = proto;
  		entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
  		break;
  	case AF_INET6:
749177ccc   Pablo Neira Ayuso   netfilter: nft_co...
161
162
  		if (proto)
  			entry->e6.ipv6.flags |= IP6T_F_PROTO;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
163
164
165
  		entry->e6.ipv6.proto = proto;
  		entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
  		break;
5191f4d82   Arturo Borrero   netfilter: nft_co...
166
  	case NFPROTO_BRIDGE:
2156d321b   Arturo Borrero   netfilter: nft_co...
167
  		entry->ebt.ethproto = (__force __be16)proto;
5191f4d82   Arturo Borrero   netfilter: nft_co...
168
169
  		entry->ebt.invflags = inv ? EBT_IPROTO : 0;
  		break;
5f1589394   Arturo Borrero   netfilter: nft_co...
170
171
  	case NFPROTO_ARP:
  		break;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
172
173
174
175
  	}
  	par->entryinfo	= entry;
  	par->target	= target;
  	par->targinfo	= info;
f323d9546   Pablo Neira Ayuso   netfilter: nf_tab...
176
  	if (nft_is_base_chain(ctx->chain)) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
177
178
  		const struct nft_base_chain *basechain =
  						nft_base_chain(ctx->chain);
115a60b17   Patrick McHardy   netfilter: nf_tab...
179
  		const struct nf_hook_ops *ops = &basechain->ops[0];
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
180
181
  
  		par->hook_mask = 1 << ops->hooknum;
493618a92   Pablo Neira Ayuso   netfilter: nft_co...
182
183
  	} else {
  		par->hook_mask = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
184
185
  	}
  	par->family	= ctx->afi->family;
55917a21d   Pablo Neira Ayuso   netfilter: x_tabl...
186
  	par->nft_compat = true;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
187
188
189
190
  }
  
  static void target_compat_from_user(struct xt_target *t, void *in, void *out)
  {
756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
191
  	int pad;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
192

756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
193
194
195
196
  	memcpy(out, in, t->targetsize);
  	pad = XT_ALIGN(t->targetsize) - t->targetsize;
  	if (pad > 0)
  		memset(out + t->targetsize, 0, pad);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
197
198
199
200
201
202
  }
  
  static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
  	[NFTA_RULE_COMPAT_PROTO]	= { .type = NLA_U32 },
  	[NFTA_RULE_COMPAT_FLAGS]	= { .type = NLA_U32 },
  };
2156d321b   Arturo Borrero   netfilter: nft_co...
203
  static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
204
205
206
207
208
209
  {
  	struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
  	u32 flags;
  	int err;
  
  	err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
fceb6435e   Johannes Berg   netlink: pass ext...
210
  			       nft_rule_compat_policy, NULL);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
211
212
213
214
215
216
217
218
219
220
221
  	if (err < 0)
  		return err;
  
  	if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
  		return -EINVAL;
  
  	flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
  	if (flags & ~NFT_RULE_COMPAT_F_MASK)
  		return -EINVAL;
  	if (flags & NFT_RULE_COMPAT_F_INV)
  		*inv = true;
8691a9a33   Pablo Neira Ayuso   netfilter: nft_co...
222
223
  	*proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
  	return 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
224
225
226
227
228
229
230
231
232
233
  }
  
  static int
  nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  		const struct nlattr * const tb[])
  {
  	void *info = nft_expr_priv(expr);
  	struct xt_target *target = expr->ops->data;
  	struct xt_tgchk_param par;
  	size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
234
  	struct nft_xt *nft_xt;
2156d321b   Arturo Borrero   netfilter: nft_co...
235
  	u16 proto = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
236
237
238
239
240
  	bool inv = false;
  	union nft_entry e = {};
  	int ret;
  
  	target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
8691a9a33   Pablo Neira Ayuso   netfilter: nft_co...
241
242
243
  	if (ctx->nla[NFTA_RULE_COMPAT]) {
  		ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
  		if (ret < 0)
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
244
  			return ret;
8691a9a33   Pablo Neira Ayuso   netfilter: nft_co...
245
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
246
247
248
249
250
  
  	nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
  
  	ret = xt_check_target(&par, size, proto, inv);
  	if (ret < 0)
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
251
  		return ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
252
253
  
  	/* The standard target cannot be used */
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
254
255
  	if (!target->target)
  		return -EINVAL;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
256

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
257
258
  	nft_xt = container_of(expr->ops, struct nft_xt, ops);
  	nft_xt->refcnt++;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
259
  	return 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
260
261
262
  }
  
  static void
62472bcef   Patrick McHardy   netfilter: nf_tab...
263
  nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
264
265
  {
  	struct xt_target *target = expr->ops->data;
3d9b14213   Pablo Neira Ayuso   netfilter: nft_co...
266
267
268
269
270
271
272
273
274
  	void *info = nft_expr_priv(expr);
  	struct xt_tgdtor_param par;
  
  	par.net = ctx->net;
  	par.target = target;
  	par.targinfo = info;
  	par.family = ctx->afi->family;
  	if (par.target->destroy != NULL)
  		par.target->destroy(&par);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
275

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
276
277
  	if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops)))
  		module_put(target->me);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
278
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
279
280
281
282
283
284
285
  static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
  {
  	const struct xt_target *target = expr->ops->data;
  	void *info = nft_expr_priv(expr);
  
  	if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
  	    nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
286
  	    nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info))
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  		goto nla_put_failure;
  
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
  
  static int nft_target_validate(const struct nft_ctx *ctx,
  			       const struct nft_expr *expr,
  			       const struct nft_data **data)
  {
  	struct xt_target *target = expr->ops->data;
  	unsigned int hook_mask = 0;
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
301
  	int ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
302

f323d9546   Pablo Neira Ayuso   netfilter: nf_tab...
303
  	if (nft_is_base_chain(ctx->chain)) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
304
305
  		const struct nft_base_chain *basechain =
  						nft_base_chain(ctx->chain);
115a60b17   Patrick McHardy   netfilter: nf_tab...
306
  		const struct nf_hook_ops *ops = &basechain->ops[0];
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
307
308
  
  		hook_mask = 1 << ops->hooknum;
f7fb77fc1   Pablo Neira Ayuso   netfilter: nft_co...
309
  		if (target->hooks && !(hook_mask & target->hooks))
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
310
  			return -EINVAL;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
311

f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
312
313
314
315
  		ret = nft_compat_chain_validate_dependency(target->table,
  							   ctx->chain);
  		if (ret < 0)
  			return ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
316
317
318
  	}
  	return 0;
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
319
320
321
322
  static void __nft_match_eval(const struct nft_expr *expr,
  			     struct nft_regs *regs,
  			     const struct nft_pktinfo *pkt,
  			     void *info)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
323
  {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
324
325
326
327
328
329
330
331
332
  	struct xt_match *match = expr->ops->data;
  	struct sk_buff *skb = pkt->skb;
  	bool ret;
  
  	nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
  
  	ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
  
  	if (pkt->xt.hotdrop) {
a55e22e92   Patrick McHardy   netfilter: nf_tab...
333
  		regs->verdict.code = NF_DROP;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
334
335
  		return;
  	}
c1f866767   David Miller   netfilter: Fix sw...
336
337
  	switch (ret ? 1 : 0) {
  	case 1:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
338
  		regs->verdict.code = NFT_CONTINUE;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
339
  		break;
c1f866767   David Miller   netfilter: Fix sw...
340
  	case 0:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
341
  		regs->verdict.code = NFT_BREAK;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
342
343
344
  		break;
  	}
  }
365e73e07   Florian Westphal   netfilter: nft_co...
345
346
347
348
349
350
351
352
  static void nft_match_large_eval(const struct nft_expr *expr,
  				 struct nft_regs *regs,
  				 const struct nft_pktinfo *pkt)
  {
  	struct nft_xt_match_priv *priv = nft_expr_priv(expr);
  
  	__nft_match_eval(expr, regs, pkt, priv->info);
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
353
354
355
356
357
358
  static void nft_match_eval(const struct nft_expr *expr,
  			   struct nft_regs *regs,
  			   const struct nft_pktinfo *pkt)
  {
  	__nft_match_eval(expr, regs, pkt, nft_expr_priv(expr));
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
359
360
361
362
363
364
365
366
367
368
  static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
  	[NFTA_MATCH_NAME]	= { .type = NLA_NUL_STRING },
  	[NFTA_MATCH_REV]	= { .type = NLA_U32 },
  	[NFTA_MATCH_INFO]	= { .type = NLA_BINARY },
  };
  
  /* struct xt_mtchk_param and xt_tgchk_param look very similar */
  static void
  nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
  			  struct xt_match *match, void *info,
2156d321b   Arturo Borrero   netfilter: nft_co...
369
  			  union nft_entry *entry, u16 proto, bool inv)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
370
  {
2daf1b4d1   Pablo Neira Ayuso   netfilter: nft_co...
371
  	par->net	= ctx->net;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
372
373
374
375
376
377
378
  	par->table	= ctx->table->name;
  	switch (ctx->afi->family) {
  	case AF_INET:
  		entry->e4.ip.proto = proto;
  		entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
  		break;
  	case AF_INET6:
749177ccc   Pablo Neira Ayuso   netfilter: nft_co...
379
380
  		if (proto)
  			entry->e6.ipv6.flags |= IP6T_F_PROTO;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
381
382
383
  		entry->e6.ipv6.proto = proto;
  		entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
  		break;
5191f4d82   Arturo Borrero   netfilter: nft_co...
384
  	case NFPROTO_BRIDGE:
2156d321b   Arturo Borrero   netfilter: nft_co...
385
  		entry->ebt.ethproto = (__force __be16)proto;
5191f4d82   Arturo Borrero   netfilter: nft_co...
386
387
  		entry->ebt.invflags = inv ? EBT_IPROTO : 0;
  		break;
5f1589394   Arturo Borrero   netfilter: nft_co...
388
389
  	case NFPROTO_ARP:
  		break;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
390
391
392
393
  	}
  	par->entryinfo	= entry;
  	par->match	= match;
  	par->matchinfo	= info;
f323d9546   Pablo Neira Ayuso   netfilter: nf_tab...
394
  	if (nft_is_base_chain(ctx->chain)) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
395
396
  		const struct nft_base_chain *basechain =
  						nft_base_chain(ctx->chain);
115a60b17   Patrick McHardy   netfilter: nf_tab...
397
  		const struct nf_hook_ops *ops = &basechain->ops[0];
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
398
399
  
  		par->hook_mask = 1 << ops->hooknum;
493618a92   Pablo Neira Ayuso   netfilter: nft_co...
400
401
  	} else {
  		par->hook_mask = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
402
403
  	}
  	par->family	= ctx->afi->family;
55917a21d   Pablo Neira Ayuso   netfilter: x_tabl...
404
  	par->nft_compat = true;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
405
406
407
408
  }
  
  static void match_compat_from_user(struct xt_match *m, void *in, void *out)
  {
756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
409
410
411
412
413
414
  	int pad;
  
  	memcpy(out, in, m->matchsize);
  	pad = XT_ALIGN(m->matchsize) - m->matchsize;
  	if (pad > 0)
  		memset(out + m->matchsize, 0, pad);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
415
416
417
  }
  
  static int
ea200cdd6   Florian Westphal   netfilter: nft_co...
418
419
420
  __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  		 const struct nlattr * const tb[],
  		 void *info)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
421
  {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
422
423
424
  	struct xt_match *match = expr->ops->data;
  	struct xt_mtchk_param par;
  	size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
425
  	struct nft_xt *nft_xt;
2156d321b   Arturo Borrero   netfilter: nft_co...
426
  	u16 proto = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
427
428
429
430
431
  	bool inv = false;
  	union nft_entry e = {};
  	int ret;
  
  	match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
8691a9a33   Pablo Neira Ayuso   netfilter: nft_co...
432
433
434
  	if (ctx->nla[NFTA_RULE_COMPAT]) {
  		ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
  		if (ret < 0)
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
435
  			return ret;
8691a9a33   Pablo Neira Ayuso   netfilter: nft_co...
436
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
437
438
439
440
441
  
  	nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
  
  	ret = xt_check_match(&par, size, proto, inv);
  	if (ret < 0)
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
442
  		return ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
443

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
444
445
  	nft_xt = container_of(expr->ops, struct nft_xt, ops);
  	nft_xt->refcnt++;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
446
  	return 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
447
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
448
449
450
451
452
453
  static int
  nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  	       const struct nlattr * const tb[])
  {
  	return __nft_match_init(ctx, expr, tb, nft_expr_priv(expr));
  }
365e73e07   Florian Westphal   netfilter: nft_co...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  static int
  nft_match_large_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  		     const struct nlattr * const tb[])
  {
  	struct nft_xt_match_priv *priv = nft_expr_priv(expr);
  	struct xt_match *m = expr->ops->data;
  	int ret;
  
  	priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL);
  	if (!priv->info)
  		return -ENOMEM;
  
  	ret = __nft_match_init(ctx, expr, tb, priv->info);
  	if (ret)
  		kfree(priv->info);
  	return ret;
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
471
  static void
ea200cdd6   Florian Westphal   netfilter: nft_co...
472
473
  __nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr,
  		    void *info)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
474
475
  {
  	struct xt_match *match = expr->ops->data;
38e229479   Florian Westphal   netfilter: nf_tab...
476
  	struct module *me = match->me;
3d9b14213   Pablo Neira Ayuso   netfilter: nft_co...
477
478
479
480
481
482
483
484
  	struct xt_mtdtor_param par;
  
  	par.net = ctx->net;
  	par.match = match;
  	par.matchinfo = info;
  	par.family = ctx->afi->family;
  	if (par.match->destroy != NULL)
  		par.match->destroy(&par);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
485

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
486
  	if (nft_xt_put(container_of(expr->ops, struct nft_xt, ops)))
38e229479   Florian Westphal   netfilter: nf_tab...
487
  		module_put(me);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
488
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
489
490
491
492
493
  static void
  nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
  {
  	__nft_match_destroy(ctx, expr, nft_expr_priv(expr));
  }
365e73e07   Florian Westphal   netfilter: nft_co...
494
495
496
497
498
499
500
501
  static void
  nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
  {
  	struct nft_xt_match_priv *priv = nft_expr_priv(expr);
  
  	__nft_match_destroy(ctx, expr, priv->info);
  	kfree(priv->info);
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
502
503
  static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr,
  			    void *info)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
504
  {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
505
506
507
508
  	struct xt_match *match = expr->ops->data;
  
  	if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
  	    nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
509
  	    nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info))
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
510
511
512
513
514
515
516
  		goto nla_put_failure;
  
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
ea200cdd6   Florian Westphal   netfilter: nft_co...
517
518
519
520
  static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
  {
  	return __nft_match_dump(skb, expr, nft_expr_priv(expr));
  }
365e73e07   Florian Westphal   netfilter: nft_co...
521
522
523
524
525
526
  static int nft_match_large_dump(struct sk_buff *skb, const struct nft_expr *e)
  {
  	struct nft_xt_match_priv *priv = nft_expr_priv(e);
  
  	return __nft_match_dump(skb, e, priv->info);
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
527
528
529
530
531
532
  static int nft_match_validate(const struct nft_ctx *ctx,
  			      const struct nft_expr *expr,
  			      const struct nft_data **data)
  {
  	struct xt_match *match = expr->ops->data;
  	unsigned int hook_mask = 0;
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
533
  	int ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
534

f323d9546   Pablo Neira Ayuso   netfilter: nf_tab...
535
  	if (nft_is_base_chain(ctx->chain)) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
536
537
  		const struct nft_base_chain *basechain =
  						nft_base_chain(ctx->chain);
115a60b17   Patrick McHardy   netfilter: nf_tab...
538
  		const struct nf_hook_ops *ops = &basechain->ops[0];
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
539
540
  
  		hook_mask = 1 << ops->hooknum;
f7fb77fc1   Pablo Neira Ayuso   netfilter: nft_co...
541
  		if (match->hooks && !(hook_mask & match->hooks))
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
542
  			return -EINVAL;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
543

afefb6f92   Pablo Neira Ayuso   netfilter: nft_co...
544
  		ret = nft_compat_chain_validate_dependency(match->table,
f3f5ddedd   Pablo Neira Ayuso   netfilter: nft_co...
545
546
547
  							   ctx->chain);
  		if (ret < 0)
  			return ret;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
548
549
550
551
552
553
554
555
556
557
558
559
  	}
  	return 0;
  }
  
  static int
  nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
  		      int event, u16 family, const char *name,
  		      int rev, int target)
  {
  	struct nlmsghdr *nlh;
  	struct nfgenmsg *nfmsg;
  	unsigned int flags = portid ? NLM_F_MULTI : 0;
dedb67c4b   Pablo Neira Ayuso   netfilter: Add nf...
560
  	event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
  	if (nlh == NULL)
  		goto nlmsg_failure;
  
  	nfmsg = nlmsg_data(nlh);
  	nfmsg->nfgen_family = family;
  	nfmsg->version = NFNETLINK_V0;
  	nfmsg->res_id = 0;
  
  	if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
  	    nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
  	    nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
  		goto nla_put_failure;
  
  	nlmsg_end(skb, nlh);
  	return skb->len;
  
  nlmsg_failure:
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -1;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
583
584
  static int nfnl_compat_get(struct net *net, struct sock *nfnl,
  			   struct sk_buff *skb, const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
585
586
  			   const struct nlattr * const tb[],
  			   struct netlink_ext_ack *extack)
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  {
  	int ret = 0, target;
  	struct nfgenmsg *nfmsg;
  	const char *fmt;
  	const char *name;
  	u32 rev;
  	struct sk_buff *skb2;
  
  	if (tb[NFTA_COMPAT_NAME] == NULL ||
  	    tb[NFTA_COMPAT_REV] == NULL ||
  	    tb[NFTA_COMPAT_TYPE] == NULL)
  		return -EINVAL;
  
  	name = nla_data(tb[NFTA_COMPAT_NAME]);
  	rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
  	target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
  
  	nfmsg = nlmsg_data(nlh);
  
  	switch(nfmsg->nfgen_family) {
  	case AF_INET:
  		fmt = "ipt_%s";
  		break;
  	case AF_INET6:
  		fmt = "ip6t_%s";
  		break;
5191f4d82   Arturo Borrero   netfilter: nft_co...
613
614
615
  	case NFPROTO_BRIDGE:
  		fmt = "ebt_%s";
  		break;
5f1589394   Arturo Borrero   netfilter: nft_co...
616
617
618
  	case NFPROTO_ARP:
  		fmt = "arpt_%s";
  		break;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  	default:
  		pr_err("nft_compat: unsupported protocol %d
  ",
  			nfmsg->nfgen_family);
  		return -EINVAL;
  	}
  
  	try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
  						 rev, target, &ret),
  						 fmt, name);
  
  	if (ret < 0)
  		return ret;
  
  	skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  	if (skb2 == NULL)
  		return -ENOMEM;
  
  	/* include the best revision for this extension in the message */
  	if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
  				  nlh->nlmsg_seq,
  				  NFNL_MSG_TYPE(nlh->nlmsg_type),
  				  NFNL_MSG_COMPAT_GET,
  				  nfmsg->nfgen_family,
  				  name, ret, target) <= 0) {
  		kfree_skb(skb2);
  		return -ENOSPC;
  	}
  
  	ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
  				MSG_DONTWAIT);
  	if (ret > 0)
  		ret = 0;
  
  	return ret == -EAGAIN ? -ENOBUFS : ret;
  }
  
  static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
  	[NFTA_COMPAT_NAME]	= { .type = NLA_NUL_STRING,
  				    .len = NFT_COMPAT_NAME_MAX-1 },
  	[NFTA_COMPAT_REV]	= { .type = NLA_U32 },
  	[NFTA_COMPAT_TYPE]	= { .type = NLA_U32 },
  };
  
  static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
  	[NFNL_MSG_COMPAT_GET]		= { .call = nfnl_compat_get,
  					    .attr_count = NFTA_COMPAT_MAX,
  					    .policy = nfnl_compat_policy_get },
  };
  
  static const struct nfnetlink_subsystem nfnl_compat_subsys = {
  	.name		= "nft-compat",
  	.subsys_id	= NFNL_SUBSYS_NFT_COMPAT,
  	.cb_count	= NFNL_MSG_COMPAT_MAX,
  	.cb		= nfnl_nft_compat_cb,
  };
  
  static LIST_HEAD(nft_match_list);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
677
  static struct nft_expr_type nft_match_type;
ba378ca9c   Pablo Neira Ayuso   netfilter: nft_co...
678
679
680
681
682
683
  static bool nft_match_cmp(const struct xt_match *match,
  			  const char *name, u32 rev, u32 family)
  {
  	return strcmp(match->name, name) == 0 && match->revision == rev &&
  	       (match->family == NFPROTO_UNSPEC || match->family == family);
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
684
685
686
687
688
689
  static const struct nft_expr_ops *
  nft_match_select_ops(const struct nft_ctx *ctx,
  		     const struct nlattr * const tb[])
  {
  	struct nft_xt *nft_match;
  	struct xt_match *match;
365e73e07   Florian Westphal   netfilter: nft_co...
690
  	unsigned int matchsize;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
691
  	char *mt_name;
ba378ca9c   Pablo Neira Ayuso   netfilter: nft_co...
692
  	u32 rev, family;
2bf4fade5   Liping Zhang   netfilter: nft_co...
693
  	int err;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
694
695
696
697
698
699
700
701
702
703
704
705
706
  
  	if (tb[NFTA_MATCH_NAME] == NULL ||
  	    tb[NFTA_MATCH_REV] == NULL ||
  	    tb[NFTA_MATCH_INFO] == NULL)
  		return ERR_PTR(-EINVAL);
  
  	mt_name = nla_data(tb[NFTA_MATCH_NAME]);
  	rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
  	family = ctx->afi->family;
  
  	/* Re-use the existing match if it's already loaded. */
  	list_for_each_entry(nft_match, &nft_match_list, head) {
  		struct xt_match *match = nft_match->ops.data;
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
707
  		if (nft_match_cmp(match, mt_name, rev, family))
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
708
709
710
711
712
713
  			return &nft_match->ops;
  	}
  
  	match = xt_request_find_match(family, mt_name, rev);
  	if (IS_ERR(match))
  		return ERR_PTR(-ENOENT);
2bf4fade5   Liping Zhang   netfilter: nft_co...
714
715
716
717
  	if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) {
  		err = -EINVAL;
  		goto err;
  	}
f0716cd6e   Florian Westphal   netfilter: nft_co...
718

0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
719
720
  	/* This is the first time we use this match, allocate operations */
  	nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
2bf4fade5   Liping Zhang   netfilter: nft_co...
721
722
723
724
  	if (nft_match == NULL) {
  		err = -ENOMEM;
  		goto err;
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
725

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
726
  	nft_match->refcnt = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
727
  	nft_match->ops.type = &nft_match_type;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
728
729
730
731
732
733
  	nft_match->ops.eval = nft_match_eval;
  	nft_match->ops.init = nft_match_init;
  	nft_match->ops.destroy = nft_match_destroy;
  	nft_match->ops.dump = nft_match_dump;
  	nft_match->ops.validate = nft_match_validate;
  	nft_match->ops.data = match;
365e73e07   Florian Westphal   netfilter: nft_co...
734
735
736
737
738
739
740
741
742
743
744
  	matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
  	if (matchsize > NFT_MATCH_LARGE_THRESH) {
  		matchsize = NFT_EXPR_SIZE(sizeof(struct nft_xt_match_priv));
  
  		nft_match->ops.eval = nft_match_large_eval;
  		nft_match->ops.init = nft_match_large_init;
  		nft_match->ops.destroy = nft_match_large_destroy;
  		nft_match->ops.dump = nft_match_large_dump;
  	}
  
  	nft_match->ops.size = matchsize;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
745
746
747
  	list_add(&nft_match->head, &nft_match_list);
  
  	return &nft_match->ops;
2bf4fade5   Liping Zhang   netfilter: nft_co...
748
749
750
  err:
  	module_put(match->me);
  	return ERR_PTR(err);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
751
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
752
753
754
755
756
757
758
759
760
761
762
  static struct nft_expr_type nft_match_type __read_mostly = {
  	.name		= "match",
  	.select_ops	= nft_match_select_ops,
  	.policy		= nft_match_policy,
  	.maxattr	= NFTA_MATCH_MAX,
  	.owner		= THIS_MODULE,
  };
  
  static LIST_HEAD(nft_target_list);
  
  static struct nft_expr_type nft_target_type;
ba378ca9c   Pablo Neira Ayuso   netfilter: nft_co...
763
764
765
766
767
768
  static bool nft_target_cmp(const struct xt_target *tg,
  			   const char *name, u32 rev, u32 family)
  {
  	return strcmp(tg->name, name) == 0 && tg->revision == rev &&
  	       (tg->family == NFPROTO_UNSPEC || tg->family == family);
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
769
770
771
772
773
774
775
  static const struct nft_expr_ops *
  nft_target_select_ops(const struct nft_ctx *ctx,
  		      const struct nlattr * const tb[])
  {
  	struct nft_xt *nft_target;
  	struct xt_target *target;
  	char *tg_name;
ba378ca9c   Pablo Neira Ayuso   netfilter: nft_co...
776
  	u32 rev, family;
2bf4fade5   Liping Zhang   netfilter: nft_co...
777
  	int err;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
778
779
780
781
782
783
784
785
786
  
  	if (tb[NFTA_TARGET_NAME] == NULL ||
  	    tb[NFTA_TARGET_REV] == NULL ||
  	    tb[NFTA_TARGET_INFO] == NULL)
  		return ERR_PTR(-EINVAL);
  
  	tg_name = nla_data(tb[NFTA_TARGET_NAME]);
  	rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
  	family = ctx->afi->family;
a76e62b50   Florian Westphal   netfilter: nft_co...
787
788
789
790
  	if (strcmp(tg_name, XT_ERROR_TARGET) == 0 ||
  	    strcmp(tg_name, XT_STANDARD_TARGET) == 0 ||
  	    strcmp(tg_name, "standard") == 0)
  		return ERR_PTR(-EINVAL);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
791
  	/* Re-use the existing target if it's already loaded. */
7965ee937   Arturo Borrero   netfilter: nft_co...
792
  	list_for_each_entry(nft_target, &nft_target_list, head) {
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
793
  		struct xt_target *target = nft_target->ops.data;
a76e62b50   Florian Westphal   netfilter: nft_co...
794
795
  		if (!target->target)
  			continue;
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
796
  		if (nft_target_cmp(target, tg_name, rev, family))
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
797
798
799
800
801
802
  			return &nft_target->ops;
  	}
  
  	target = xt_request_find_target(family, tg_name, rev);
  	if (IS_ERR(target))
  		return ERR_PTR(-ENOENT);
a76e62b50   Florian Westphal   netfilter: nft_co...
803
804
805
806
  	if (!target->target) {
  		err = -EINVAL;
  		goto err;
  	}
2bf4fade5   Liping Zhang   netfilter: nft_co...
807
808
809
810
  	if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) {
  		err = -EINVAL;
  		goto err;
  	}
f0716cd6e   Florian Westphal   netfilter: nft_co...
811

0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
812
813
  	/* This is the first time we use this target, allocate operations */
  	nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
2bf4fade5   Liping Zhang   netfilter: nft_co...
814
815
816
817
  	if (nft_target == NULL) {
  		err = -ENOMEM;
  		goto err;
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
818

1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
819
  	nft_target->refcnt = 0;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
820
  	nft_target->ops.type = &nft_target_type;
756c1b1a7   Pablo Neira Ayuso   netfilter: nft_co...
821
  	nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
822
823
824
825
826
  	nft_target->ops.init = nft_target_init;
  	nft_target->ops.destroy = nft_target_destroy;
  	nft_target->ops.dump = nft_target_dump;
  	nft_target->ops.validate = nft_target_validate;
  	nft_target->ops.data = target;
5191f4d82   Arturo Borrero   netfilter: nft_co...
827
828
829
830
  	if (family == NFPROTO_BRIDGE)
  		nft_target->ops.eval = nft_target_eval_bridge;
  	else
  		nft_target->ops.eval = nft_target_eval_xt;
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
831
832
833
  	list_add(&nft_target->head, &nft_target_list);
  
  	return &nft_target->ops;
2bf4fade5   Liping Zhang   netfilter: nft_co...
834
835
836
  err:
  	module_put(target->me);
  	return ERR_PTR(err);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
837
  }
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  static struct nft_expr_type nft_target_type __read_mostly = {
  	.name		= "target",
  	.select_ops	= nft_target_select_ops,
  	.policy		= nft_target_policy,
  	.maxattr	= NFTA_TARGET_MAX,
  	.owner		= THIS_MODULE,
  };
  
  static int __init nft_compat_module_init(void)
  {
  	int ret;
  
  	ret = nft_register_expr(&nft_match_type);
  	if (ret < 0)
  		return ret;
  
  	ret = nft_register_expr(&nft_target_type);
  	if (ret < 0)
  		goto err_match;
  
  	ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
  	if (ret < 0) {
  		pr_err("nft_compat: cannot register with nfnetlink.
  ");
  		goto err_target;
  	}
  
  	pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
  ");
  
  	return ret;
  
  err_target:
  	nft_unregister_expr(&nft_target_type);
  err_match:
  	nft_unregister_expr(&nft_match_type);
  	return ret;
  }
  
  static void __exit nft_compat_module_exit(void)
  {
1ea5ed0ca   Florian Westphal   netfilter: nf_tab...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
  	struct nft_xt *xt, *next;
  
  	/* list should be empty here, it can be non-empty only in case there
  	 * was an error that caused nft_xt expr to not be initialized fully
  	 * and noone else requested the same expression later.
  	 *
  	 * In this case, the lists contain 0-refcount entries that still
  	 * hold module reference.
  	 */
  	list_for_each_entry_safe(xt, next, &nft_target_list, head) {
  		struct xt_target *target = xt->ops.data;
  
  		if (WARN_ON_ONCE(xt->refcnt))
  			continue;
  		module_put(target->me);
  		kfree(xt);
  	}
  
  	list_for_each_entry_safe(xt, next, &nft_match_list, head) {
  		struct xt_match *match = xt->ops.data;
  
  		if (WARN_ON_ONCE(xt->refcnt))
  			continue;
  		module_put(match->me);
  		kfree(xt);
  	}
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
905
906
907
  	nfnetlink_subsys_unregister(&nfnl_compat_subsys);
  	nft_unregister_expr(&nft_target_type);
  	nft_unregister_expr(&nft_match_type);
0ca743a55   Pablo Neira Ayuso   netfilter: nf_tab...
908
909
910
911
912
913
914
915
916
917
918
  }
  
  MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
  
  module_init(nft_compat_module_init);
  module_exit(nft_compat_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  MODULE_ALIAS_NFT_EXPR("match");
  MODULE_ALIAS_NFT_EXPR("target");