1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nfnetlink.h>
17#include <linux/netfilter/nf_tables.h>
18#include <linux/netfilter/nf_tables_compat.h>
19#include <linux/netfilter/x_tables.h>
20#include <linux/netfilter_ipv4/ip_tables.h>
21#include <linux/netfilter_ipv6/ip6_tables.h>
22#include <linux/netfilter_bridge/ebtables.h>
23#include <linux/netfilter_arp/arp_tables.h>
24#include <net/netfilter/nf_tables.h>
25#include <net/netfilter/nf_log.h>
26
27
28#define NFT_MATCH_LARGE_THRESH 192
29
30struct nft_xt_match_priv {
31 void *info;
32};
33
34static int nft_compat_chain_validate_dependency(const struct nft_ctx *ctx,
35 const char *tablename)
36{
37 enum nft_chain_types type = NFT_CHAIN_T_DEFAULT;
38 const struct nft_chain *chain = ctx->chain;
39 const struct nft_base_chain *basechain;
40
41 if (!tablename ||
42 !nft_is_base_chain(chain))
43 return 0;
44
45 basechain = nft_base_chain(chain);
46 if (strcmp(tablename, "nat") == 0) {
47 if (ctx->family != NFPROTO_BRIDGE)
48 type = NFT_CHAIN_T_NAT;
49 if (basechain->type->type != type)
50 return -EINVAL;
51 }
52
53 return 0;
54}
55
56union nft_entry {
57 struct ipt_entry e4;
58 struct ip6t_entry e6;
59 struct ebt_entry ebt;
60 struct arpt_entry arp;
61};
62
63static inline void
64nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
65{
66 par->target = xt;
67 par->targinfo = xt_info;
68 par->hotdrop = false;
69}
70
71static void nft_target_eval_xt(const struct nft_expr *expr,
72 struct nft_regs *regs,
73 const struct nft_pktinfo *pkt)
74{
75 void *info = nft_expr_priv(expr);
76 struct xt_target *target = expr->ops->data;
77 struct sk_buff *skb = pkt->skb;
78 int ret;
79
80 nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
81
82 ret = target->target(skb, &pkt->xt);
83
84 if (pkt->xt.hotdrop)
85 ret = NF_DROP;
86
87 switch (ret) {
88 case XT_CONTINUE:
89 regs->verdict.code = NFT_CONTINUE;
90 break;
91 default:
92 regs->verdict.code = ret;
93 break;
94 }
95}
96
97static void nft_target_eval_bridge(const struct nft_expr *expr,
98 struct nft_regs *regs,
99 const struct nft_pktinfo *pkt)
100{
101 void *info = nft_expr_priv(expr);
102 struct xt_target *target = expr->ops->data;
103 struct sk_buff *skb = pkt->skb;
104 int ret;
105
106 nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
107
108 ret = target->target(skb, &pkt->xt);
109
110 if (pkt->xt.hotdrop)
111 ret = NF_DROP;
112
113 switch (ret) {
114 case EBT_ACCEPT:
115 regs->verdict.code = NF_ACCEPT;
116 break;
117 case EBT_DROP:
118 regs->verdict.code = NF_DROP;
119 break;
120 case EBT_CONTINUE:
121 regs->verdict.code = NFT_CONTINUE;
122 break;
123 case EBT_RETURN:
124 regs->verdict.code = NFT_RETURN;
125 break;
126 default:
127 regs->verdict.code = ret;
128 break;
129 }
130}
131
132static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
133 [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
134 [NFTA_TARGET_REV] = { .type = NLA_U32 },
135 [NFTA_TARGET_INFO] = { .type = NLA_BINARY },
136};
137
138static void
139nft_target_set_tgchk_param(struct xt_tgchk_param *par,
140 const struct nft_ctx *ctx,
141 struct xt_target *target, void *info,
142 union nft_entry *entry, u16 proto, bool inv)
143{
144 par->net = ctx->net;
145 par->table = ctx->table->name;
146 switch (ctx->family) {
147 case AF_INET:
148 entry->e4.ip.proto = proto;
149 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
150 break;
151 case AF_INET6:
152 if (proto)
153 entry->e6.ipv6.flags |= IP6T_F_PROTO;
154
155 entry->e6.ipv6.proto = proto;
156 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
157 break;
158 case NFPROTO_BRIDGE:
159 entry->ebt.ethproto = (__force __be16)proto;
160 entry->ebt.invflags = inv ? EBT_IPROTO : 0;
161 break;
162 case NFPROTO_ARP:
163 break;
164 }
165 par->entryinfo = entry;
166 par->target = target;
167 par->targinfo = info;
168 if (nft_is_base_chain(ctx->chain)) {
169 const struct nft_base_chain *basechain =
170 nft_base_chain(ctx->chain);
171 const struct nf_hook_ops *ops = &basechain->ops;
172
173 par->hook_mask = 1 << ops->hooknum;
174 } else {
175 par->hook_mask = 0;
176 }
177 par->family = ctx->family;
178 par->nft_compat = true;
179}
180
181static void target_compat_from_user(struct xt_target *t, void *in, void *out)
182{
183 int pad;
184
185 memcpy(out, in, t->targetsize);
186 pad = XT_ALIGN(t->targetsize) - t->targetsize;
187 if (pad > 0)
188 memset(out + t->targetsize, 0, pad);
189}
190
191static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
192 [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 },
193 [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 },
194};
195
196static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)
197{
198 struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
199 u32 flags;
200 int err;
201
202 err = nla_parse_nested_deprecated(tb, NFTA_RULE_COMPAT_MAX, attr,
203 nft_rule_compat_policy, NULL);
204 if (err < 0)
205 return err;
206
207 if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
208 return -EINVAL;
209
210 flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
211 if (flags & ~NFT_RULE_COMPAT_F_MASK)
212 return -EINVAL;
213 if (flags & NFT_RULE_COMPAT_F_INV)
214 *inv = true;
215
216 *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
217 return 0;
218}
219
220static void nft_compat_wait_for_destructors(void)
221{
222
223
224
225
226
227
228 nf_tables_trans_destroy_flush_work();
229}
230
231static int
232nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
233 const struct nlattr * const tb[])
234{
235 void *info = nft_expr_priv(expr);
236 struct xt_target *target = expr->ops->data;
237 struct xt_tgchk_param par;
238 size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
239 u16 proto = 0;
240 bool inv = false;
241 union nft_entry e = {};
242 int ret;
243
244 target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
245
246 if (ctx->nla[NFTA_RULE_COMPAT]) {
247 ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
248 if (ret < 0)
249 return ret;
250 }
251
252 nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
253
254 nft_compat_wait_for_destructors();
255
256 ret = xt_check_target(&par, size, proto, inv);
257 if (ret < 0) {
258 if (ret == -ENOENT) {
259 const char *modname = NULL;
260
261 if (strcmp(target->name, "LOG") == 0)
262 modname = "nf_log_syslog";
263 else if (strcmp(target->name, "NFLOG") == 0)
264 modname = "nfnetlink_log";
265
266 if (modname &&
267 nft_request_module(ctx->net, "%s", modname) == -EAGAIN)
268 return -EAGAIN;
269 }
270
271 return ret;
272 }
273
274
275 if (!target->target)
276 return -EINVAL;
277
278 return 0;
279}
280
281static void __nft_mt_tg_destroy(struct module *me, const struct nft_expr *expr)
282{
283 module_put(me);
284 kfree(expr->ops);
285}
286
287static void
288nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
289{
290 struct xt_target *target = expr->ops->data;
291 void *info = nft_expr_priv(expr);
292 struct module *me = target->me;
293 struct xt_tgdtor_param par;
294
295 par.net = ctx->net;
296 par.target = target;
297 par.targinfo = info;
298 par.family = ctx->family;
299 if (par.target->destroy != NULL)
300 par.target->destroy(&par);
301
302 __nft_mt_tg_destroy(me, expr);
303}
304
305static int nft_extension_dump_info(struct sk_buff *skb, int attr,
306 const void *info,
307 unsigned int size, unsigned int user_size)
308{
309 unsigned int info_size, aligned_size = XT_ALIGN(size);
310 struct nlattr *nla;
311
312 nla = nla_reserve(skb, attr, aligned_size);
313 if (!nla)
314 return -1;
315
316 info_size = user_size ? : size;
317 memcpy(nla_data(nla), info, info_size);
318 memset(nla_data(nla) + info_size, 0, aligned_size - info_size);
319
320 return 0;
321}
322
323static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
324{
325 const struct xt_target *target = expr->ops->data;
326 void *info = nft_expr_priv(expr);
327
328 if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
329 nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
330 nft_extension_dump_info(skb, NFTA_TARGET_INFO, info,
331 target->targetsize, target->usersize))
332 goto nla_put_failure;
333
334 return 0;
335
336nla_put_failure:
337 return -1;
338}
339
340static int nft_target_validate(const struct nft_ctx *ctx,
341 const struct nft_expr *expr,
342 const struct nft_data **data)
343{
344 struct xt_target *target = expr->ops->data;
345 unsigned int hook_mask = 0;
346 int ret;
347
348 if (nft_is_base_chain(ctx->chain)) {
349 const struct nft_base_chain *basechain =
350 nft_base_chain(ctx->chain);
351 const struct nf_hook_ops *ops = &basechain->ops;
352
353 hook_mask = 1 << ops->hooknum;
354 if (target->hooks && !(hook_mask & target->hooks))
355 return -EINVAL;
356
357 ret = nft_compat_chain_validate_dependency(ctx, target->table);
358 if (ret < 0)
359 return ret;
360 }
361 return 0;
362}
363
364static void __nft_match_eval(const struct nft_expr *expr,
365 struct nft_regs *regs,
366 const struct nft_pktinfo *pkt,
367 void *info)
368{
369 struct xt_match *match = expr->ops->data;
370 struct sk_buff *skb = pkt->skb;
371 bool ret;
372
373 nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
374
375 ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
376
377 if (pkt->xt.hotdrop) {
378 regs->verdict.code = NF_DROP;
379 return;
380 }
381
382 switch (ret ? 1 : 0) {
383 case 1:
384 regs->verdict.code = NFT_CONTINUE;
385 break;
386 case 0:
387 regs->verdict.code = NFT_BREAK;
388 break;
389 }
390}
391
392static void nft_match_large_eval(const struct nft_expr *expr,
393 struct nft_regs *regs,
394 const struct nft_pktinfo *pkt)
395{
396 struct nft_xt_match_priv *priv = nft_expr_priv(expr);
397
398 __nft_match_eval(expr, regs, pkt, priv->info);
399}
400
401static void nft_match_eval(const struct nft_expr *expr,
402 struct nft_regs *regs,
403 const struct nft_pktinfo *pkt)
404{
405 __nft_match_eval(expr, regs, pkt, nft_expr_priv(expr));
406}
407
408static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
409 [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
410 [NFTA_MATCH_REV] = { .type = NLA_U32 },
411 [NFTA_MATCH_INFO] = { .type = NLA_BINARY },
412};
413
414
415static void
416nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
417 struct xt_match *match, void *info,
418 union nft_entry *entry, u16 proto, bool inv)
419{
420 par->net = ctx->net;
421 par->table = ctx->table->name;
422 switch (ctx->family) {
423 case AF_INET:
424 entry->e4.ip.proto = proto;
425 entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
426 break;
427 case AF_INET6:
428 if (proto)
429 entry->e6.ipv6.flags |= IP6T_F_PROTO;
430
431 entry->e6.ipv6.proto = proto;
432 entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
433 break;
434 case NFPROTO_BRIDGE:
435 entry->ebt.ethproto = (__force __be16)proto;
436 entry->ebt.invflags = inv ? EBT_IPROTO : 0;
437 break;
438 case NFPROTO_ARP:
439 break;
440 }
441 par->entryinfo = entry;
442 par->match = match;
443 par->matchinfo = info;
444 if (nft_is_base_chain(ctx->chain)) {
445 const struct nft_base_chain *basechain =
446 nft_base_chain(ctx->chain);
447 const struct nf_hook_ops *ops = &basechain->ops;
448
449 par->hook_mask = 1 << ops->hooknum;
450 } else {
451 par->hook_mask = 0;
452 }
453 par->family = ctx->family;
454 par->nft_compat = true;
455}
456
457static void match_compat_from_user(struct xt_match *m, void *in, void *out)
458{
459 int pad;
460
461 memcpy(out, in, m->matchsize);
462 pad = XT_ALIGN(m->matchsize) - m->matchsize;
463 if (pad > 0)
464 memset(out + m->matchsize, 0, pad);
465}
466
467static int
468__nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
469 const struct nlattr * const tb[],
470 void *info)
471{
472 struct xt_match *match = expr->ops->data;
473 struct xt_mtchk_param par;
474 size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
475 u16 proto = 0;
476 bool inv = false;
477 union nft_entry e = {};
478 int ret;
479
480 match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
481
482 if (ctx->nla[NFTA_RULE_COMPAT]) {
483 ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
484 if (ret < 0)
485 return ret;
486 }
487
488 nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
489
490 nft_compat_wait_for_destructors();
491
492 return xt_check_match(&par, size, proto, inv);
493}
494
495static int
496nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
497 const struct nlattr * const tb[])
498{
499 return __nft_match_init(ctx, expr, tb, nft_expr_priv(expr));
500}
501
502static int
503nft_match_large_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
504 const struct nlattr * const tb[])
505{
506 struct nft_xt_match_priv *priv = nft_expr_priv(expr);
507 struct xt_match *m = expr->ops->data;
508 int ret;
509
510 priv->info = kmalloc(XT_ALIGN(m->matchsize), GFP_KERNEL);
511 if (!priv->info)
512 return -ENOMEM;
513
514 ret = __nft_match_init(ctx, expr, tb, priv->info);
515 if (ret)
516 kfree(priv->info);
517 return ret;
518}
519
520static void
521__nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr,
522 void *info)
523{
524 struct xt_match *match = expr->ops->data;
525 struct module *me = match->me;
526 struct xt_mtdtor_param par;
527
528 par.net = ctx->net;
529 par.match = match;
530 par.matchinfo = info;
531 par.family = ctx->family;
532 if (par.match->destroy != NULL)
533 par.match->destroy(&par);
534
535 __nft_mt_tg_destroy(me, expr);
536}
537
538static void
539nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
540{
541 __nft_match_destroy(ctx, expr, nft_expr_priv(expr));
542}
543
544static void
545nft_match_large_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
546{
547 struct nft_xt_match_priv *priv = nft_expr_priv(expr);
548
549 __nft_match_destroy(ctx, expr, priv->info);
550 kfree(priv->info);
551}
552
553static int __nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr,
554 void *info)
555{
556 struct xt_match *match = expr->ops->data;
557
558 if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
559 nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
560 nft_extension_dump_info(skb, NFTA_MATCH_INFO, info,
561 match->matchsize, match->usersize))
562 goto nla_put_failure;
563
564 return 0;
565
566nla_put_failure:
567 return -1;
568}
569
570static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
571{
572 return __nft_match_dump(skb, expr, nft_expr_priv(expr));
573}
574
575static int nft_match_large_dump(struct sk_buff *skb, const struct nft_expr *e)
576{
577 struct nft_xt_match_priv *priv = nft_expr_priv(e);
578
579 return __nft_match_dump(skb, e, priv->info);
580}
581
582static int nft_match_validate(const struct nft_ctx *ctx,
583 const struct nft_expr *expr,
584 const struct nft_data **data)
585{
586 struct xt_match *match = expr->ops->data;
587 unsigned int hook_mask = 0;
588 int ret;
589
590 if (nft_is_base_chain(ctx->chain)) {
591 const struct nft_base_chain *basechain =
592 nft_base_chain(ctx->chain);
593 const struct nf_hook_ops *ops = &basechain->ops;
594
595 hook_mask = 1 << ops->hooknum;
596 if (match->hooks && !(hook_mask & match->hooks))
597 return -EINVAL;
598
599 ret = nft_compat_chain_validate_dependency(ctx, match->table);
600 if (ret < 0)
601 return ret;
602 }
603 return 0;
604}
605
606static int
607nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
608 int event, u16 family, const char *name,
609 int rev, int target)
610{
611 struct nlmsghdr *nlh;
612 struct nfgenmsg *nfmsg;
613 unsigned int flags = portid ? NLM_F_MULTI : 0;
614
615 event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event);
616 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
617 if (nlh == NULL)
618 goto nlmsg_failure;
619
620 nfmsg = nlmsg_data(nlh);
621 nfmsg->nfgen_family = family;
622 nfmsg->version = NFNETLINK_V0;
623 nfmsg->res_id = 0;
624
625 if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
626 nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
627 nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
628 goto nla_put_failure;
629
630 nlmsg_end(skb, nlh);
631 return skb->len;
632
633nlmsg_failure:
634nla_put_failure:
635 nlmsg_cancel(skb, nlh);
636 return -1;
637}
638
639static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
640 struct sk_buff *skb, const struct nlmsghdr *nlh,
641 const struct nlattr * const tb[],
642 struct netlink_ext_ack *extack)
643{
644 int ret = 0, target;
645 struct nfgenmsg *nfmsg;
646 const char *fmt;
647 const char *name;
648 u32 rev;
649 struct sk_buff *skb2;
650
651 if (tb[NFTA_COMPAT_NAME] == NULL ||
652 tb[NFTA_COMPAT_REV] == NULL ||
653 tb[NFTA_COMPAT_TYPE] == NULL)
654 return -EINVAL;
655
656 name = nla_data(tb[NFTA_COMPAT_NAME]);
657 rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
658 target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
659
660 nfmsg = nlmsg_data(nlh);
661
662 switch(nfmsg->nfgen_family) {
663 case AF_INET:
664 fmt = "ipt_%s";
665 break;
666 case AF_INET6:
667 fmt = "ip6t_%s";
668 break;
669 case NFPROTO_BRIDGE:
670 fmt = "ebt_%s";
671 break;
672 case NFPROTO_ARP:
673 fmt = "arpt_%s";
674 break;
675 default:
676 pr_err("nft_compat: unsupported protocol %d\n",
677 nfmsg->nfgen_family);
678 return -EINVAL;
679 }
680
681 if (!try_module_get(THIS_MODULE))
682 return -EINVAL;
683
684 rcu_read_unlock();
685 try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
686 rev, target, &ret),
687 fmt, name);
688 if (ret < 0)
689 goto out_put;
690
691 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
692 if (skb2 == NULL) {
693 ret = -ENOMEM;
694 goto out_put;
695 }
696
697
698 if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
699 nlh->nlmsg_seq,
700 NFNL_MSG_TYPE(nlh->nlmsg_type),
701 NFNL_MSG_COMPAT_GET,
702 nfmsg->nfgen_family,
703 name, ret, target) <= 0) {
704 kfree_skb(skb2);
705 goto out_put;
706 }
707
708 ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
709 MSG_DONTWAIT);
710 if (ret > 0)
711 ret = 0;
712out_put:
713 rcu_read_lock();
714 module_put(THIS_MODULE);
715 return ret == -EAGAIN ? -ENOBUFS : ret;
716}
717
718static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
719 [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING,
720 .len = NFT_COMPAT_NAME_MAX-1 },
721 [NFTA_COMPAT_REV] = { .type = NLA_U32 },
722 [NFTA_COMPAT_TYPE] = { .type = NLA_U32 },
723};
724
725static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
726 [NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu,
727 .attr_count = NFTA_COMPAT_MAX,
728 .policy = nfnl_compat_policy_get },
729};
730
731static const struct nfnetlink_subsystem nfnl_compat_subsys = {
732 .name = "nft-compat",
733 .subsys_id = NFNL_SUBSYS_NFT_COMPAT,
734 .cb_count = NFNL_MSG_COMPAT_MAX,
735 .cb = nfnl_nft_compat_cb,
736};
737
738static struct nft_expr_type nft_match_type;
739
740static const struct nft_expr_ops *
741nft_match_select_ops(const struct nft_ctx *ctx,
742 const struct nlattr * const tb[])
743{
744 struct nft_expr_ops *ops;
745 struct xt_match *match;
746 unsigned int matchsize;
747 char *mt_name;
748 u32 rev, family;
749 int err;
750
751 if (tb[NFTA_MATCH_NAME] == NULL ||
752 tb[NFTA_MATCH_REV] == NULL ||
753 tb[NFTA_MATCH_INFO] == NULL)
754 return ERR_PTR(-EINVAL);
755
756 mt_name = nla_data(tb[NFTA_MATCH_NAME]);
757 rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
758 family = ctx->family;
759
760 match = xt_request_find_match(family, mt_name, rev);
761 if (IS_ERR(match))
762 return ERR_PTR(-ENOENT);
763
764 if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) {
765 err = -EINVAL;
766 goto err;
767 }
768
769 ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL);
770 if (!ops) {
771 err = -ENOMEM;
772 goto err;
773 }
774
775 ops->type = &nft_match_type;
776 ops->eval = nft_match_eval;
777 ops->init = nft_match_init;
778 ops->destroy = nft_match_destroy;
779 ops->dump = nft_match_dump;
780 ops->validate = nft_match_validate;
781 ops->data = match;
782
783 matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
784 if (matchsize > NFT_MATCH_LARGE_THRESH) {
785 matchsize = NFT_EXPR_SIZE(sizeof(struct nft_xt_match_priv));
786
787 ops->eval = nft_match_large_eval;
788 ops->init = nft_match_large_init;
789 ops->destroy = nft_match_large_destroy;
790 ops->dump = nft_match_large_dump;
791 }
792
793 ops->size = matchsize;
794
795 return ops;
796err:
797 module_put(match->me);
798 return ERR_PTR(err);
799}
800
801static void nft_match_release_ops(const struct nft_expr_ops *ops)
802{
803 struct xt_match *match = ops->data;
804
805 module_put(match->me);
806 kfree(ops);
807}
808
809static struct nft_expr_type nft_match_type __read_mostly = {
810 .name = "match",
811 .select_ops = nft_match_select_ops,
812 .release_ops = nft_match_release_ops,
813 .policy = nft_match_policy,
814 .maxattr = NFTA_MATCH_MAX,
815 .owner = THIS_MODULE,
816};
817
818static struct nft_expr_type nft_target_type;
819
820static const struct nft_expr_ops *
821nft_target_select_ops(const struct nft_ctx *ctx,
822 const struct nlattr * const tb[])
823{
824 struct nft_expr_ops *ops;
825 struct xt_target *target;
826 char *tg_name;
827 u32 rev, family;
828 int err;
829
830 if (tb[NFTA_TARGET_NAME] == NULL ||
831 tb[NFTA_TARGET_REV] == NULL ||
832 tb[NFTA_TARGET_INFO] == NULL)
833 return ERR_PTR(-EINVAL);
834
835 tg_name = nla_data(tb[NFTA_TARGET_NAME]);
836 rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
837 family = ctx->family;
838
839 if (strcmp(tg_name, XT_ERROR_TARGET) == 0 ||
840 strcmp(tg_name, XT_STANDARD_TARGET) == 0 ||
841 strcmp(tg_name, "standard") == 0)
842 return ERR_PTR(-EINVAL);
843
844 target = xt_request_find_target(family, tg_name, rev);
845 if (IS_ERR(target))
846 return ERR_PTR(-ENOENT);
847
848 if (!target->target) {
849 err = -EINVAL;
850 goto err;
851 }
852
853 if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) {
854 err = -EINVAL;
855 goto err;
856 }
857
858 ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL);
859 if (!ops) {
860 err = -ENOMEM;
861 goto err;
862 }
863
864 ops->type = &nft_target_type;
865 ops->size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
866 ops->init = nft_target_init;
867 ops->destroy = nft_target_destroy;
868 ops->dump = nft_target_dump;
869 ops->validate = nft_target_validate;
870 ops->data = target;
871
872 if (family == NFPROTO_BRIDGE)
873 ops->eval = nft_target_eval_bridge;
874 else
875 ops->eval = nft_target_eval_xt;
876
877 return ops;
878err:
879 module_put(target->me);
880 return ERR_PTR(err);
881}
882
883static void nft_target_release_ops(const struct nft_expr_ops *ops)
884{
885 struct xt_target *target = ops->data;
886
887 module_put(target->me);
888 kfree(ops);
889}
890
891static struct nft_expr_type nft_target_type __read_mostly = {
892 .name = "target",
893 .select_ops = nft_target_select_ops,
894 .release_ops = nft_target_release_ops,
895 .policy = nft_target_policy,
896 .maxattr = NFTA_TARGET_MAX,
897 .owner = THIS_MODULE,
898};
899
900static int __init nft_compat_module_init(void)
901{
902 int ret;
903
904 ret = nft_register_expr(&nft_match_type);
905 if (ret < 0)
906 return ret;
907
908 ret = nft_register_expr(&nft_target_type);
909 if (ret < 0)
910 goto err_match;
911
912 ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
913 if (ret < 0) {
914 pr_err("nft_compat: cannot register with nfnetlink.\n");
915 goto err_target;
916 }
917
918 return ret;
919err_target:
920 nft_unregister_expr(&nft_target_type);
921err_match:
922 nft_unregister_expr(&nft_match_type);
923 return ret;
924}
925
926static void __exit nft_compat_module_exit(void)
927{
928 nfnetlink_subsys_unregister(&nfnl_compat_subsys);
929 nft_unregister_expr(&nft_target_type);
930 nft_unregister_expr(&nft_match_type);
931}
932
933MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
934
935module_init(nft_compat_module_init);
936module_exit(nft_compat_module_exit);
937
938MODULE_LICENSE("GPL");
939MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
940MODULE_ALIAS_NFT_EXPR("match");
941MODULE_ALIAS_NFT_EXPR("target");
942