diff options
author | Stephan Mueller <smueller@chronox.de> | 2017-04-24 05:15:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-20 08:28:37 -0400 |
commit | bcc70358396abb905f448a5c43f54dda457a0959 (patch) | |
tree | 7b4de5ed5450bfc774fbb80925f4e82ed1ec6789 | |
parent | 9b2fb8ad5ba1b528e2f2927898403b0df40fd09b (diff) |
crypto: algif_aead - Require setkey before accept(2)
commit 2a2a251f110576b1d89efbd0662677d7e7db21a8 upstream.
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")
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 fde8d885f7b6..6c11537ca404 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; |
@@ -732,24 +737,146 @@ static struct proto_ops algif_aead_ops = { | |||
732 | .poll = aead_poll, | 737 | .poll = aead_poll, |
733 | }; | 738 | }; |
734 | 739 | ||
740 | static int aead_check_key(struct socket *sock) | ||
741 | { | ||
742 | int err = 0; | ||
743 | struct sock *psk; | ||
744 | struct alg_sock *pask; | ||
745 | struct aead_tfm *tfm; | ||
746 | struct sock *sk = sock->sk; | ||
747 | struct alg_sock *ask = alg_sk(sk); | ||
748 | |||
749 | lock_sock(sk); | ||
750 | if (ask->refcnt) | ||
751 | goto unlock_child; | ||
752 | |||
753 | psk = ask->parent; | ||
754 | pask = alg_sk(ask->parent); | ||
755 | tfm = pask->private; | ||
756 | |||
757 | err = -ENOKEY; | ||
758 | lock_sock_nested(psk, SINGLE_DEPTH_NESTING); | ||
759 | if (!tfm->has_key) | ||
760 | goto unlock; | ||
761 | |||
762 | if (!pask->refcnt++) | ||
763 | sock_hold(psk); | ||
764 | |||
765 | ask->refcnt = 1; | ||
766 | sock_put(psk); | ||
767 | |||
768 | err = 0; | ||
769 | |||
770 | unlock: | ||
771 | release_sock(psk); | ||
772 | unlock_child: | ||
773 | release_sock(sk); | ||
774 | |||
775 | return err; | ||
776 | } | ||
777 | |||
778 | static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
779 | size_t size) | ||
780 | { | ||
781 | int err; | ||
782 | |||
783 | err = aead_check_key(sock); | ||
784 | if (err) | ||
785 | return err; | ||
786 | |||
787 | return aead_sendmsg(sock, msg, size); | ||
788 | } | ||
789 | |||
790 | static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page, | ||
791 | int offset, size_t size, int flags) | ||
792 | { | ||
793 | int err; | ||
794 | |||
795 | err = aead_check_key(sock); | ||
796 | if (err) | ||
797 | return err; | ||
798 | |||
799 | return aead_sendpage(sock, page, offset, size, flags); | ||
800 | } | ||
801 | |||
802 | static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
803 | size_t ignored, int flags) | ||
804 | { | ||
805 | int err; | ||
806 | |||
807 | err = aead_check_key(sock); | ||
808 | if (err) | ||
809 | return err; | ||
810 | |||
811 | return aead_recvmsg(sock, msg, ignored, flags); | ||
812 | } | ||
813 | |||
814 | static struct proto_ops algif_aead_ops_nokey = { | ||
815 | .family = PF_ALG, | ||
816 | |||
817 | .connect = sock_no_connect, | ||
818 | .socketpair = sock_no_socketpair, | ||
819 | .getname = sock_no_getname, | ||
820 | .ioctl = sock_no_ioctl, | ||
821 | .listen = sock_no_listen, | ||
822 | .shutdown = sock_no_shutdown, | ||
823 | .getsockopt = sock_no_getsockopt, | ||
824 | .mmap = sock_no_mmap, | ||
825 | .bind = sock_no_bind, | ||
826 | .accept = sock_no_accept, | ||
827 | .setsockopt = sock_no_setsockopt, | ||
828 | |||
829 | .release = af_alg_release, | ||
830 | .sendmsg = aead_sendmsg_nokey, | ||
831 | .sendpage = aead_sendpage_nokey, | ||
832 | .recvmsg = aead_recvmsg_nokey, | ||
833 | .poll = aead_poll, | ||
834 | }; | ||
835 | |||
735 | static void *aead_bind(const char *name, u32 type, u32 mask) | 836 | static void *aead_bind(const char *name, u32 type, u32 mask) |
736 | { | 837 | { |
737 | return crypto_alloc_aead(name, type, mask); | 838 | struct aead_tfm *tfm; |
839 | struct crypto_aead *aead; | ||
840 | |||
841 | tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); | ||
842 | if (!tfm) | ||
843 | return ERR_PTR(-ENOMEM); | ||
844 | |||
845 | aead = crypto_alloc_aead(name, type, mask); | ||
846 | if (IS_ERR(aead)) { | ||
847 | kfree(tfm); | ||
848 | return ERR_CAST(aead); | ||
849 | } | ||
850 | |||
851 | tfm->aead = aead; | ||
852 | |||
853 | return tfm; | ||
738 | } | 854 | } |
739 | 855 | ||
740 | static void aead_release(void *private) | 856 | static void aead_release(void *private) |
741 | { | 857 | { |
742 | crypto_free_aead(private); | 858 | struct aead_tfm *tfm = private; |
859 | |||
860 | crypto_free_aead(tfm->aead); | ||
861 | kfree(tfm); | ||
743 | } | 862 | } |
744 | 863 | ||
745 | static int aead_setauthsize(void *private, unsigned int authsize) | 864 | static int aead_setauthsize(void *private, unsigned int authsize) |
746 | { | 865 | { |
747 | return crypto_aead_setauthsize(private, authsize); | 866 | struct aead_tfm *tfm = private; |
867 | |||
868 | return crypto_aead_setauthsize(tfm->aead, authsize); | ||
748 | } | 869 | } |
749 | 870 | ||
750 | static int aead_setkey(void *private, const u8 *key, unsigned int keylen) | 871 | static int aead_setkey(void *private, const u8 *key, unsigned int keylen) |
751 | { | 872 | { |
752 | return crypto_aead_setkey(private, key, keylen); | 873 | struct aead_tfm *tfm = private; |
874 | int err; | ||
875 | |||
876 | err = crypto_aead_setkey(tfm->aead, key, keylen); | ||
877 | tfm->has_key = !err; | ||
878 | |||
879 | return err; | ||
753 | } | 880 | } |
754 | 881 | ||
755 | static void aead_sock_destruct(struct sock *sk) | 882 | static void aead_sock_destruct(struct sock *sk) |
@@ -766,12 +893,14 @@ static void aead_sock_destruct(struct sock *sk) | |||
766 | af_alg_release_parent(sk); | 893 | af_alg_release_parent(sk); |
767 | } | 894 | } |
768 | 895 | ||
769 | static int aead_accept_parent(void *private, struct sock *sk) | 896 | static int aead_accept_parent_nokey(void *private, struct sock *sk) |
770 | { | 897 | { |
771 | struct aead_ctx *ctx; | 898 | struct aead_ctx *ctx; |
772 | struct alg_sock *ask = alg_sk(sk); | 899 | struct alg_sock *ask = alg_sk(sk); |
773 | unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private); | 900 | struct aead_tfm *tfm = private; |
774 | unsigned int ivlen = crypto_aead_ivsize(private); | 901 | struct crypto_aead *aead = tfm->aead; |
902 | unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead); | ||
903 | unsigned int ivlen = crypto_aead_ivsize(aead); | ||
775 | 904 | ||
776 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); | 905 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); |
777 | if (!ctx) | 906 | if (!ctx) |
@@ -798,7 +927,7 @@ static int aead_accept_parent(void *private, struct sock *sk) | |||
798 | 927 | ||
799 | ask->private = ctx; | 928 | ask->private = ctx; |
800 | 929 | ||
801 | aead_request_set_tfm(&ctx->aead_req, private); | 930 | aead_request_set_tfm(&ctx->aead_req, aead); |
802 | aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 931 | aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
803 | af_alg_complete, &ctx->completion); | 932 | af_alg_complete, &ctx->completion); |
804 | 933 | ||
@@ -807,13 +936,25 @@ static int aead_accept_parent(void *private, struct sock *sk) | |||
807 | return 0; | 936 | return 0; |
808 | } | 937 | } |
809 | 938 | ||
939 | static int aead_accept_parent(void *private, struct sock *sk) | ||
940 | { | ||
941 | struct aead_tfm *tfm = private; | ||
942 | |||
943 | if (!tfm->has_key) | ||
944 | return -ENOKEY; | ||
945 | |||
946 | return aead_accept_parent_nokey(private, sk); | ||
947 | } | ||
948 | |||
810 | static const struct af_alg_type algif_type_aead = { | 949 | static const struct af_alg_type algif_type_aead = { |
811 | .bind = aead_bind, | 950 | .bind = aead_bind, |
812 | .release = aead_release, | 951 | .release = aead_release, |
813 | .setkey = aead_setkey, | 952 | .setkey = aead_setkey, |
814 | .setauthsize = aead_setauthsize, | 953 | .setauthsize = aead_setauthsize, |
815 | .accept = aead_accept_parent, | 954 | .accept = aead_accept_parent, |
955 | .accept_nokey = aead_accept_parent_nokey, | ||
816 | .ops = &algif_aead_ops, | 956 | .ops = &algif_aead_ops, |
957 | .ops_nokey = &algif_aead_ops_nokey, | ||
817 | .name = "aead", | 958 | .name = "aead", |
818 | .owner = THIS_MODULE | 959 | .owner = THIS_MODULE |
819 | }; | 960 | }; |