diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index a8e7aa3..82a7dcd 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -125,6 +125,23 @@ int af_alg_release(struct socket *sock)
 }
 EXPORT_SYMBOL_GPL(af_alg_release);

+void af_alg_release_parent(struct sock *sk)
+{
+        struct alg_sock *ask = alg_sk(sk);
+        bool last;
+
+        sk = ask->parent;
+        ask = alg_sk(sk);
+
+        lock_sock(sk);
+        last = !--ask->refcnt;
+        release_sock(sk);
+
+        if (last)
+                sock_put(sk);
+}
+EXPORT_SYMBOL_GPL(af_alg_release_parent);
+
 static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
         const u32 forbidden = CRYPTO_ALG_INTERNAL;
@@ -133,6 +150,7 @@ static int alg_bind(struct socket *sock, struct
sockaddr *uaddr, int addr_len)
         struct sockaddr_alg *sa = (void *)uaddr;
         const struct af_alg_type *type;
         void *private;
+        int err;

         if (sock->state == SS_CONNECTED)
                 return -EINVAL;
@@ -160,16 +178,22 @@ static int alg_bind(struct socket *sock, struct
sockaddr *uaddr, int addr_len)
                 return PTR_ERR(private);
         }

+        err = -EBUSY;
         lock_sock(sk);
+        if (ask->refcnt)
+                goto unlock;

         swap(ask->type, type);
         swap(ask->private, private);

+        err = 0;
+
+unlock:
         release_sock(sk);

         alg_do_release(type, private);

-        return 0;
+        return err;
 }

 static int alg_setkey(struct sock *sk, char __user *ukey,
@@ -196,6 +220,16 @@ out:
         return err;
 }

+static int alg_setauthsize(struct sock *sk, unsigned int size)
+{
+        int err;
+        struct alg_sock *ask = alg_sk(sk);
+        const struct af_alg_type *type = ask->type;
+
+        err = type->setauthsize(ask->private, size);
+        return err;
+}
+
 static int alg_setsockopt(struct socket *sock, int level, int optname,
                           char __user *optval, unsigned int optlen)
 {
@@ -210,6 +244,11 @@ static int alg_setsockopt(struct socket *sock,
int level, int optname,
         if (level != SOL_ALG || !type)
                 goto unlock;

+        if (ask->refcnt) {
+                err = -EBUSY;
+                goto unlock;
+        }
+
         switch (optname) {
         case ALG_SET_KEY:
                 if (sock->state == SS_CONNECTED)
@@ -224,7 +263,7 @@ static int alg_setsockopt(struct socket *sock, int
level, int optname,
                         goto unlock;
                 if (!type->setauthsize)
                         goto unlock;
-                err = type->setauthsize(ask->private, optlen);
+                err = alg_setauthsize(sk, optlen);
         }

 unlock:
@@ -264,7 +303,8 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)

         sk2->sk_family = PF_ALG;

-        sock_hold(sk);
+        if (!ask->refcnt++)
+                sock_hold(sk);
         alg_sk(sk2)->parent = sk;
         alg_sk(sk2)->type = type;

diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 634b4d1..df483f9 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -31,6 +31,11 @@ struct skcipher_sg_list {
         struct scatterlist sg[0];
 };

+struct skcipher_tfm {
+        struct crypto_skcipher *skcipher;
+        bool has_key;
+};
+
 struct skcipher_ctx {
         struct list_head tsgl;
         struct af_alg_sgl rsgl;
@@ -750,17 +755,41 @@ static struct proto_ops algif_skcipher_ops = {

 static void *skcipher_bind(const char *name, u32 type, u32 mask)
 {
-        return crypto_alloc_skcipher(name, type, mask);
+        struct skcipher_tfm *tfm;
+        struct crypto_skcipher *skcipher;
+
+        tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+        if (!tfm)
+                return ERR_PTR(-ENOMEM);
+
+        skcipher = crypto_alloc_skcipher(name, type, mask);
+        if (IS_ERR(skcipher)) {
+                kfree(tfm);
+                return ERR_CAST(skcipher);
+        }
+
+        tfm->skcipher = skcipher;
+
+        return tfm;
 }

 static void skcipher_release(void *private)
 {
-        crypto_free_skcipher(private);
+        struct skcipher_tfm *tfm = private;
+
+        crypto_free_skcipher(tfm->skcipher);
+        kfree(tfm);
 }

 static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-        return crypto_skcipher_setkey(private, key, keylen);
+        struct skcipher_tfm *tfm = private;
+        int err;
+
+        err = crypto_skcipher_setkey(tfm->skcipher, key, keylen);
+        tfm->has_key = !err;
+
+        return err;
 }

 static void skcipher_wait(struct sock *sk)
@@ -792,20 +821,25 @@ static int skcipher_accept_parent(void *private,
struct sock *sk)
 {
         struct skcipher_ctx *ctx;
         struct alg_sock *ask = alg_sk(sk);
-        unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
+        struct skcipher_tfm *tfm = private;
+        struct crypto_skcipher *skcipher = tfm->skcipher;
+        unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher);
+
+        if (!tfm->has_key)
+                return -ENOKEY;

         ctx = sock_kmalloc(sk, len, GFP_KERNEL);
         if (!ctx)
                 return -ENOMEM;

-        ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
+        ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher),
                                GFP_KERNEL);
         if (!ctx->iv) {
                 sock_kfree_s(sk, ctx, len);
                 return -ENOMEM;
         }

-        memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
+        memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher));

         INIT_LIST_HEAD(&ctx->tsgl);
