diff options
author | Liping Zhang <liping.zhang@spreadtrum.com> | 2016-07-23 04:00:31 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-07-23 06:22:07 -0400 |
commit | 2bf4fade54de995f84d319ae02003609dca450f3 (patch) | |
tree | 024cb3652c7f57ae1dc8ef1df2333a2d4a2c581d | |
parent | 96d1327ac2e3dc3ac4204fe3656dad0043fc0efd (diff) |
netfilter: nft_compat: put back match/target module if init fail
If the user specify the invalid NFTA_MATCH_INFO/NFTA_TARGET_INFO attr
or memory alloc fail, we should call module_put to the related match
or target. Otherwise, we cannot remove the module even nobody use it.
Signed-off-by: Liping Zhang <liping.zhang@spreadtrum.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/nft_compat.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 6228c422c766..2e07cec50ffd 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -634,6 +634,7 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
634 | struct xt_match *match; | 634 | struct xt_match *match; |
635 | char *mt_name; | 635 | char *mt_name; |
636 | u32 rev, family; | 636 | u32 rev, family; |
637 | int err; | ||
637 | 638 | ||
638 | if (tb[NFTA_MATCH_NAME] == NULL || | 639 | if (tb[NFTA_MATCH_NAME] == NULL || |
639 | tb[NFTA_MATCH_REV] == NULL || | 640 | tb[NFTA_MATCH_REV] == NULL || |
@@ -660,13 +661,17 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
660 | if (IS_ERR(match)) | 661 | if (IS_ERR(match)) |
661 | return ERR_PTR(-ENOENT); | 662 | return ERR_PTR(-ENOENT); |
662 | 663 | ||
663 | if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) | 664 | if (match->matchsize > nla_len(tb[NFTA_MATCH_INFO])) { |
664 | return ERR_PTR(-EINVAL); | 665 | err = -EINVAL; |
666 | goto err; | ||
667 | } | ||
665 | 668 | ||
666 | /* This is the first time we use this match, allocate operations */ | 669 | /* This is the first time we use this match, allocate operations */ |
667 | nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); | 670 | nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); |
668 | if (nft_match == NULL) | 671 | if (nft_match == NULL) { |
669 | return ERR_PTR(-ENOMEM); | 672 | err = -ENOMEM; |
673 | goto err; | ||
674 | } | ||
670 | 675 | ||
671 | nft_match->ops.type = &nft_match_type; | 676 | nft_match->ops.type = &nft_match_type; |
672 | nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); | 677 | nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize)); |
@@ -680,6 +685,9 @@ nft_match_select_ops(const struct nft_ctx *ctx, | |||
680 | list_add(&nft_match->head, &nft_match_list); | 685 | list_add(&nft_match->head, &nft_match_list); |
681 | 686 | ||
682 | return &nft_match->ops; | 687 | return &nft_match->ops; |
688 | err: | ||
689 | module_put(match->me); | ||
690 | return ERR_PTR(err); | ||
683 | } | 691 | } |
684 | 692 | ||
685 | static void nft_match_release(void) | 693 | static void nft_match_release(void) |
@@ -717,6 +725,7 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
717 | struct xt_target *target; | 725 | struct xt_target *target; |
718 | char *tg_name; | 726 | char *tg_name; |
719 | u32 rev, family; | 727 | u32 rev, family; |
728 | int err; | ||
720 | 729 | ||
721 | if (tb[NFTA_TARGET_NAME] == NULL || | 730 | if (tb[NFTA_TARGET_NAME] == NULL || |
722 | tb[NFTA_TARGET_REV] == NULL || | 731 | tb[NFTA_TARGET_REV] == NULL || |
@@ -743,13 +752,17 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
743 | if (IS_ERR(target)) | 752 | if (IS_ERR(target)) |
744 | return ERR_PTR(-ENOENT); | 753 | return ERR_PTR(-ENOENT); |
745 | 754 | ||
746 | if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) | 755 | if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) { |
747 | return ERR_PTR(-EINVAL); | 756 | err = -EINVAL; |
757 | goto err; | ||
758 | } | ||
748 | 759 | ||
749 | /* This is the first time we use this target, allocate operations */ | 760 | /* This is the first time we use this target, allocate operations */ |
750 | nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); | 761 | nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); |
751 | if (nft_target == NULL) | 762 | if (nft_target == NULL) { |
752 | return ERR_PTR(-ENOMEM); | 763 | err = -ENOMEM; |
764 | goto err; | ||
765 | } | ||
753 | 766 | ||
754 | nft_target->ops.type = &nft_target_type; | 767 | nft_target->ops.type = &nft_target_type; |
755 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); | 768 | nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); |
@@ -767,6 +780,9 @@ nft_target_select_ops(const struct nft_ctx *ctx, | |||
767 | list_add(&nft_target->head, &nft_target_list); | 780 | list_add(&nft_target->head, &nft_target_list); |
768 | 781 | ||
769 | return &nft_target->ops; | 782 | return &nft_target->ops; |
783 | err: | ||
784 | module_put(target->me); | ||
785 | return ERR_PTR(err); | ||
770 | } | 786 | } |
771 | 787 | ||
772 | static void nft_target_release(void) | 788 | static void nft_target_release(void) |