diff options
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 11 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 26 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 26 |
3 files changed, 50 insertions, 13 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7d7ab94a7a2e..2fdf75da7a70 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -480,6 +480,11 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
480 | } | 480 | } |
481 | t->u.kernel.target = target; | 481 | t->u.kernel.target = target; |
482 | 482 | ||
483 | ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t), | ||
484 | name, e->comefrom, 0, 0); | ||
485 | if (ret) | ||
486 | goto err; | ||
487 | |||
483 | if (t->u.kernel.target == &arpt_standard_target) { | 488 | if (t->u.kernel.target == &arpt_standard_target) { |
484 | if (!standard_check(t, size)) { | 489 | if (!standard_check(t, size)) { |
485 | ret = -EINVAL; | 490 | ret = -EINVAL; |
@@ -490,16 +495,16 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
490 | t->u.target_size | 495 | t->u.target_size |
491 | - sizeof(*t), | 496 | - sizeof(*t), |
492 | e->comefrom)) { | 497 | e->comefrom)) { |
493 | module_put(t->u.kernel.target->me); | ||
494 | duprintf("arp_tables: check failed for `%s'.\n", | 498 | duprintf("arp_tables: check failed for `%s'.\n", |
495 | t->u.kernel.target->name); | 499 | t->u.kernel.target->name); |
496 | ret = -EINVAL; | 500 | ret = -EINVAL; |
497 | goto out; | 501 | goto err; |
498 | } | 502 | } |
499 | 503 | ||
500 | (*i)++; | 504 | (*i)++; |
501 | return 0; | 505 | return 0; |
502 | 506 | err: | |
507 | module_put(t->u.kernel.target->me); | ||
503 | out: | 508 | out: |
504 | return ret; | 509 | return ret; |
505 | } | 510 | } |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 16f47c675fef..f884ca223295 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -508,6 +508,7 @@ check_match(struct ipt_entry_match *m, | |||
508 | unsigned int *i) | 508 | unsigned int *i) |
509 | { | 509 | { |
510 | struct ipt_match *match; | 510 | struct ipt_match *match; |
511 | int ret; | ||
511 | 512 | ||
512 | match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, | 513 | match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, |
513 | m->u.user.revision), | 514 | m->u.user.revision), |
@@ -518,18 +519,27 @@ check_match(struct ipt_entry_match *m, | |||
518 | } | 519 | } |
519 | m->u.kernel.match = match; | 520 | m->u.kernel.match = match; |
520 | 521 | ||
522 | ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m), | ||
523 | name, hookmask, ip->proto, | ||
524 | ip->invflags & IPT_INV_PROTO); | ||
525 | if (ret) | ||
526 | goto err; | ||
527 | |||
521 | if (m->u.kernel.match->checkentry | 528 | if (m->u.kernel.match->checkentry |
522 | && !m->u.kernel.match->checkentry(name, ip, m->data, | 529 | && !m->u.kernel.match->checkentry(name, ip, m->data, |
523 | m->u.match_size - sizeof(*m), | 530 | m->u.match_size - sizeof(*m), |
524 | hookmask)) { | 531 | hookmask)) { |
525 | module_put(m->u.kernel.match->me); | ||
526 | duprintf("ip_tables: check failed for `%s'.\n", | 532 | duprintf("ip_tables: check failed for `%s'.\n", |
527 | m->u.kernel.match->name); | 533 | m->u.kernel.match->name); |
528 | return -EINVAL; | 534 | ret = -EINVAL; |
535 | goto err; | ||
529 | } | 536 | } |
530 | 537 | ||
531 | (*i)++; | 538 | (*i)++; |
532 | return 0; | 539 | return 0; |
540 | err: | ||
541 | module_put(m->u.kernel.match->me); | ||
542 | return ret; | ||
533 | } | 543 | } |
534 | 544 | ||
535 | static struct ipt_target ipt_standard_target; | 545 | static struct ipt_target ipt_standard_target; |
@@ -565,6 +575,12 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
565 | } | 575 | } |
566 | t->u.kernel.target = target; | 576 | t->u.kernel.target = target; |
567 | 577 | ||
578 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), | ||
579 | name, e->comefrom, e->ip.proto, | ||
580 | e->ip.invflags & IPT_INV_PROTO); | ||
581 | if (ret) | ||
582 | goto err; | ||
583 | |||
568 | if (t->u.kernel.target == &ipt_standard_target) { | 584 | if (t->u.kernel.target == &ipt_standard_target) { |
569 | if (!standard_check(t, size)) { | 585 | if (!standard_check(t, size)) { |
570 | ret = -EINVAL; | 586 | ret = -EINVAL; |
@@ -575,16 +591,16 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
575 | t->u.target_size | 591 | t->u.target_size |
576 | - sizeof(*t), | 592 | - sizeof(*t), |
577 | e->comefrom)) { | 593 | e->comefrom)) { |
578 | module_put(t->u.kernel.target->me); | ||
579 | duprintf("ip_tables: check failed for `%s'.\n", | 594 | duprintf("ip_tables: check failed for `%s'.\n", |
580 | t->u.kernel.target->name); | 595 | t->u.kernel.target->name); |
581 | ret = -EINVAL; | 596 | ret = -EINVAL; |
582 | goto cleanup_matches; | 597 | goto err; |
583 | } | 598 | } |
584 | 599 | ||
585 | (*i)++; | 600 | (*i)++; |
586 | return 0; | 601 | return 0; |
587 | 602 | err: | |
603 | module_put(t->u.kernel.target->me); | ||
588 | cleanup_matches: | 604 | cleanup_matches: |
589 | IPT_MATCH_ITERATE(e, cleanup_match, &j); | 605 | IPT_MATCH_ITERATE(e, cleanup_match, &j); |
590 | return ret; | 606 | return ret; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74ff56c322f4..1cd70683f2e2 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -575,6 +575,7 @@ check_match(struct ip6t_entry_match *m, | |||
575 | unsigned int *i) | 575 | unsigned int *i) |
576 | { | 576 | { |
577 | struct ip6t_match *match; | 577 | struct ip6t_match *match; |
578 | int ret; | ||
578 | 579 | ||
579 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, | 580 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, |
580 | m->u.user.revision), | 581 | m->u.user.revision), |
@@ -585,18 +586,27 @@ check_match(struct ip6t_entry_match *m, | |||
585 | } | 586 | } |
586 | m->u.kernel.match = match; | 587 | m->u.kernel.match = match; |
587 | 588 | ||
589 | ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), | ||
590 | name, hookmask, ipv6->proto, | ||
591 | ipv6->invflags & IP6T_INV_PROTO); | ||
592 | if (ret) | ||
593 | goto err; | ||
594 | |||
588 | if (m->u.kernel.match->checkentry | 595 | if (m->u.kernel.match->checkentry |
589 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, | 596 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, |
590 | m->u.match_size - sizeof(*m), | 597 | m->u.match_size - sizeof(*m), |
591 | hookmask)) { | 598 | hookmask)) { |
592 | module_put(m->u.kernel.match->me); | ||
593 | duprintf("ip_tables: check failed for `%s'.\n", | 599 | duprintf("ip_tables: check failed for `%s'.\n", |
594 | m->u.kernel.match->name); | 600 | m->u.kernel.match->name); |
595 | return -EINVAL; | 601 | ret = -EINVAL; |
602 | goto err; | ||
596 | } | 603 | } |
597 | 604 | ||
598 | (*i)++; | 605 | (*i)++; |
599 | return 0; | 606 | return 0; |
607 | err: | ||
608 | module_put(m->u.kernel.match->me); | ||
609 | return ret; | ||
600 | } | 610 | } |
601 | 611 | ||
602 | static struct ip6t_target ip6t_standard_target; | 612 | static struct ip6t_target ip6t_standard_target; |
@@ -632,6 +642,12 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
632 | } | 642 | } |
633 | t->u.kernel.target = target; | 643 | t->u.kernel.target = target; |
634 | 644 | ||
645 | ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), | ||
646 | name, e->comefrom, e->ipv6.proto, | ||
647 | e->ipv6.invflags & IP6T_INV_PROTO); | ||
648 | if (ret) | ||
649 | goto err; | ||
650 | |||
635 | if (t->u.kernel.target == &ip6t_standard_target) { | 651 | if (t->u.kernel.target == &ip6t_standard_target) { |
636 | if (!standard_check(t, size)) { | 652 | if (!standard_check(t, size)) { |
637 | ret = -EINVAL; | 653 | ret = -EINVAL; |
@@ -642,16 +658,16 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
642 | t->u.target_size | 658 | t->u.target_size |
643 | - sizeof(*t), | 659 | - sizeof(*t), |
644 | e->comefrom)) { | 660 | e->comefrom)) { |
645 | module_put(t->u.kernel.target->me); | ||
646 | duprintf("ip_tables: check failed for `%s'.\n", | 661 | duprintf("ip_tables: check failed for `%s'.\n", |
647 | t->u.kernel.target->name); | 662 | t->u.kernel.target->name); |
648 | ret = -EINVAL; | 663 | ret = -EINVAL; |
649 | goto cleanup_matches; | 664 | goto err; |
650 | } | 665 | } |
651 | 666 | ||
652 | (*i)++; | 667 | (*i)++; |
653 | return 0; | 668 | return 0; |
654 | 669 | err: | |
670 | module_put(t->u.kernel.target->me); | ||
655 | cleanup_matches: | 671 | cleanup_matches: |
656 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 672 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); |
657 | return ret; | 673 | return ret; |