diff options
author | Stephan Mueller <smueller@chronox.de> | 2017-04-24 05:15:23 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2017-04-24 06:11:08 -0400 |
commit | 2a2a251f110576b1d89efbd0662677d7e7db21a8 (patch) | |
tree | 4d4237387e1a5a3160858286da5e2665d06cf955 /crypto/algif_aead.c | |
parent | a368f43d6e3a001e684e9191a27df384fbff12f5 (diff) |
crypto: algif_aead - Require setkey before accept(2)
Some cipher implementations will crash if you try to use them
without calling setkey first. This patch adds a check so that
the accept(2) call will fail with -ENOKEY if setkey hasn't been
done on the socket yet.
Fixes: 400c40cf78da ("crypto: algif - add AEAD support")
Cc: <stable@vger.kernel.org>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/algif_aead.c')
-rw-r--r-- | crypto/algif_aead.c | 157 |
1 files changed, 149 insertions, 8 deletions
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 5a8053758657..e0d55ea2f0eb 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c | |||
@@ -44,6 +44,11 @@ struct aead_async_req { | |||
44 | char iv[]; | 44 | char iv[]; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct aead_tfm { | ||
48 | struct crypto_aead *aead; | ||
49 | bool has_key; | ||
50 | }; | ||
51 | |||
47 | struct aead_ctx { | 52 | struct aead_ctx { |
48 | struct aead_sg_list tsgl; | 53 | struct aead_sg_list tsgl; |
49 | struct aead_async_rsgl first_rsgl; | 54 | struct aead_async_rsgl first_rsgl; |
@@ -723,24 +728,146 @@ static struct proto_ops algif_aead_ops = { | |||
723 | .poll = aead_poll, | 728 | .poll = aead_poll, |
724 | }; | 729 | }; |
725 | 730 | ||
731 | static int aead_check_key(struct socket *sock) | ||
732 | { | ||
733 | int err = 0; | ||
734 | struct sock *psk; | ||
735 | struct alg_sock *pask; | ||
736 | struct aead_tfm *tfm; | ||
737 | struct sock *sk = sock->sk; | ||
738 | struct alg_sock *ask = alg_sk(sk); | ||
739 | |||
740 | lock_sock(sk); | ||
741 | if (ask->refcnt) | ||
742 | goto unlock_child; | ||
743 | |||
744 | psk = ask->parent; | ||
745 | pask = alg_sk(ask->parent); | ||
746 | tfm = pask->private; | ||
747 | |||
748 | err = -ENOKEY; | ||
749 | lock_sock_nested(psk, SINGLE_DEPTH_NESTING); | ||
750 | if (!tfm->has_key) | ||
751 | goto unlock; | ||
752 | |||
753 | if (!pask->refcnt++) | ||
754 | sock_hold(psk); | ||
755 | |||
756 | ask->refcnt = 1; | ||
757 | sock_put(psk); | ||
758 | |||
759 | err = 0; | ||
760 | |||
761 | unlock: | ||
762 | release_sock(psk); | ||
763 | unlock_child: | ||
764 | release_sock(sk); | ||
765 | |||
766 | return err; | ||
767 | } | ||
768 | |||
769 | static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
770 | size_t size) | ||
771 | { | ||
772 | int err; | ||
773 | |||
774 | err = aead_check_key(sock); | ||
775 | if (err) | ||
776 | return err; | ||
777 | |||
778 | return aead_sendmsg(sock, msg, size); | ||
779 | } | ||
780 | |||
781 | static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page, | ||
782 | int offset, size_t size, int flags) | ||
783 | { | ||
784 | int err; | ||
785 | |||
786 | err = aead_check_key(sock); | ||
787 | if (err) | ||
788 | return err; | ||
789 | |||
790 | return aead_sendpage(sock, page, offset, size, flags); | ||
791 | } | ||
792 | |||
793 | static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
794 | size_t ignored, int flags) | ||
795 | { | ||
796 | int err; | ||
797 | |||
798 | err = aead_check_key(sock); | ||
799 | if (err) | ||
800 | return err; | ||
801 | |||
802 | return aead_recvmsg(sock, msg, ignored, flags); | ||
803 | } | ||
804 | |||
805 | static struct proto_ops algif_aead_ops_nokey = { | ||
806 | .family = PF_ALG, | ||
807 | |||
808 | .connect = sock_no_connect, | ||
809 | .socketpair = sock_no_socketpair, | ||
810 | .getname = sock_no_getname, | ||
811 | .ioctl = sock_no_ioctl, | ||
812 | .listen = sock_no_listen, | ||
813 | .shutdown = sock_no_shutdown, | ||
814 | .getsockopt = sock_no_getsockopt, | ||
815 | .mmap = sock_no_mmap, | ||
816 | .bind = sock_no_bind, | ||
817 | .accept = sock_no_accept, | ||
818 | .setsockopt = sock_no_setsockopt, | ||
819 | |||
820 | .release = af_alg_release, | ||
821 | .sendmsg = aead_sendmsg_nokey, | ||
822 | .sendpage = aead_sendpage_nokey, | ||
823 | .recvmsg = aead_recvmsg_nokey, | ||
824 | .poll = aead_poll, | ||
825 | }; | ||
826 | |||
726 | static void *aead_bind(const char *name, u32 type, u32 mask) | 827 | static void *aead_bind(const char *name, u32 type, u32 mask) |
727 | { | 828 | { |
728 | return crypto_alloc_aead(name, type, mask); | 829 | struct aead_tfm *tfm; |
830 | struct crypto_aead *aead; | ||
831 | |||
832 | tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); | ||
833 | if (!tfm) | ||
834 | return ERR_PTR(-ENOMEM); | ||
835 | |||
836 | aead = crypto_alloc_aead(name, type, mask); | ||
837 | if (IS_ERR(aead)) { | ||
838 | kfree(tfm); | ||
839 | return ERR_CAST(aead); | ||
840 | } | ||
841 | |||
842 | tfm->aead = aead; | ||
843 | |||
844 | return tfm; | ||
729 | } | 845 | } |
730 | 846 | ||
731 | static void aead_release(void *private) | 847 | static void aead_release(void *private) |
732 | { | 848 | { |
733 | crypto_free_aead(private); | 849 | struct aead_tfm *tfm = private; |
850 | |||
851 | crypto_free_aead(tfm->aead); | ||
852 | kfree(tfm); | ||
734 | } | 853 | } |
735 | 854 | ||
736 | static int aead_setauthsize(void *private, unsigned int authsize) | 855 | static int aead_setauthsize(void *private, unsigned int authsize) |
737 | { | 856 | { |
738 | return crypto_aead_setauthsize(private, authsize); | 857 | struct aead_tfm *tfm = private; |
858 | |||
859 | return crypto_aead_setauthsize(tfm->aead, authsize); | ||
739 | } | 860 | } |
740 | 861 | ||
741 | static int aead_setkey(void *private, const u8 *key, unsigned int keylen) | 862 | static int aead_setkey(void *private, const u8 *key, unsigned int keylen) |
742 | { | 863 | { |
743 | return crypto_aead_setkey(private, key, keylen); | 864 | struct aead_tfm *tfm = private; |
865 | int err; | ||
866 | |||
867 | err = crypto_aead_setkey(tfm->aead, key, keylen); | ||
868 | tfm->has_key = !err; | ||
869 | |||
870 | return err; | ||
744 | } | 871 | } |
745 | 872 | ||
746 | static void aead_sock_destruct(struct sock *sk) | 873 | static void aead_sock_destruct(struct sock *sk) |
@@ -757,12 +884,14 @@ static void aead_sock_destruct(struct sock *sk) | |||
757 | af_alg_release_parent(sk); | 884 | af_alg_release_parent(sk); |
758 | } | 885 | } |
759 | 886 | ||
760 | static int aead_accept_parent(void *private, struct sock *sk) | 887 | static int aead_accept_parent_nokey(void *private, struct sock *sk) |
761 | { | 888 | { |
762 | struct aead_ctx *ctx; | 889 | struct aead_ctx *ctx; |
763 | struct alg_sock *ask = alg_sk(sk); | 890 | struct alg_sock *ask = alg_sk(sk); |
764 | unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private); | 891 | struct aead_tfm *tfm = private; |
765 | unsigned int ivlen = crypto_aead_ivsize(private); | 892 | struct crypto_aead *aead = tfm->aead; |
893 | unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead); | ||
894 | unsigned int ivlen = crypto_aead_ivsize(aead); | ||
766 | 895 | ||
767 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); | 896 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); |
768 | if (!ctx) | 897 | if (!ctx) |
@@ -789,7 +918,7 @@ static int aead_accept_parent(void *private, struct sock *sk) | |||
789 | 918 | ||
790 | ask->private = ctx; | 919 | ask->private = ctx; |
791 | 920 | ||
792 | aead_request_set_tfm(&ctx->aead_req, private); | 921 | aead_request_set_tfm(&ctx->aead_req, aead); |
793 | aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 922 | aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
794 | af_alg_complete, &ctx->completion); | 923 | af_alg_complete, &ctx->completion); |
795 | 924 | ||
@@ -798,13 +927,25 @@ static int aead_accept_parent(void *private, struct sock *sk) | |||
798 | return 0; | 927 | return 0; |
799 | } | 928 | } |
800 | 929 | ||
930 | static int aead_accept_parent(void *private, struct sock *sk) | ||
931 | { | ||
932 | struct aead_tfm *tfm = private; | ||
933 | |||
934 | if (!tfm->has_key) | ||
935 | return -ENOKEY; | ||
936 | |||
937 | return aead_accept_parent_nokey(private, sk); | ||
938 | } | ||
939 | |||
801 | static const struct af_alg_type algif_type_aead = { | 940 | static const struct af_alg_type algif_type_aead = { |
802 | .bind = aead_bind, | 941 | .bind = aead_bind, |
803 | .release = aead_release, | 942 | .release = aead_release, |
804 | .setkey = aead_setkey, | 943 | .setkey = aead_setkey, |
805 | .setauthsize = aead_setauthsize, | 944 | .setauthsize = aead_setauthsize, |
806 | .accept = aead_accept_parent, | 945 | .accept = aead_accept_parent, |
946 | .accept_nokey = aead_accept_parent_nokey, | ||
807 | .ops = &algif_aead_ops, | 947 | .ops = &algif_aead_ops, |
948 | .ops_nokey = &algif_aead_ops_nokey, | ||
808 | .name = "aead", | 949 | .name = "aead", |
809 | .owner = THIS_MODULE | 950 | .owner = THIS_MODULE |
810 | }; | 951 | }; |