Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50d7bf3d authored by Herbert Xu's avatar Herbert Xu Committed by Sasha Levin
Browse files

crypto: algif_skcipher - Add nokey compatibility path



    commit a0fa2d037129a9849918a92d91b79ed6c7bd2818 upstream.

    This patch adds a compatibility path to support old applications
    that do acept(2) before setkey.

    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
    [backported to 3.18 by Milan Broz <gmazyland@gmail.com>]

Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent 1f45c389
Loading
Loading
Loading
Loading
+144 −5
Original line number Diff line number Diff line
@@ -549,6 +549,99 @@ static struct proto_ops algif_skcipher_ops = {
	.poll		=	skcipher_poll,
};

static int skcipher_check_key(struct socket *sock)
{
	int err;
	struct sock *psk;
	struct alg_sock *pask;
	struct skcipher_tfm *tfm;
	struct sock *sk = sock->sk;
	struct alg_sock *ask = alg_sk(sk);

	if (ask->refcnt)
		return 0;

	psk = ask->parent;
	pask = alg_sk(ask->parent);
	tfm = pask->private;

	err = -ENOKEY;
	lock_sock(psk);
	if (!tfm->has_key)
		goto unlock;

	if (!pask->refcnt++)
		sock_hold(psk);

	ask->refcnt = 1;
	sock_put(psk);

	err = 0;

unlock:
	release_sock(psk);

	return err;
}

static int skcipher_sendmsg_nokey(struct kiocb *unused, struct socket *sock,
				  struct msghdr *msg, size_t size)
{
	int err;

	err = skcipher_check_key(sock);
	if (err)
		return err;

	return skcipher_sendmsg(NULL, sock, msg, size);
}

static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page,
				       int offset, size_t size, int flags)
{
	int err;

	err = skcipher_check_key(sock);
	if (err)
		return err;

	return skcipher_sendpage(sock, page, offset, size, flags);
}

static int skcipher_recvmsg_nokey(struct kiocb *unused, struct socket *sock,
				  struct msghdr *msg, size_t ignored, int flags)
{
	int err;

	err = skcipher_check_key(sock);
	if (err)
		return err;

	return skcipher_recvmsg(NULL, sock, msg, ignored, flags);
}

static struct proto_ops algif_skcipher_ops_nokey = {
	.family		=	PF_ALG,

	.connect	=	sock_no_connect,
	.socketpair	=	sock_no_socketpair,
	.getname	=	sock_no_getname,
	.ioctl		=	sock_no_ioctl,
	.listen		=	sock_no_listen,
	.shutdown	=	sock_no_shutdown,
	.getsockopt	=	sock_no_getsockopt,
	.mmap		=	sock_no_mmap,
	.bind		=	sock_no_bind,
	.accept		=	sock_no_accept,
	.setsockopt	=	sock_no_setsockopt,

	.release	=	af_alg_release,
	.sendmsg	=	skcipher_sendmsg_nokey,
	.sendpage	=	skcipher_sendpage_nokey,
	.recvmsg	=	skcipher_recvmsg_nokey,
	.poll		=	skcipher_poll,
};

static void *skcipher_bind(const char *name, u32 type, u32 mask)
{
	struct skcipher_tfm *tfm;
@@ -588,7 +681,7 @@ static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
	return err;
}

static void skcipher_sock_destruct(struct sock *sk)
static void skcipher_sock_destruct_common(struct sock *sk)
{
	struct alg_sock *ask = alg_sk(sk);
	struct skcipher_ctx *ctx = ask->private;
@@ -597,10 +690,33 @@ static void skcipher_sock_destruct(struct sock *sk)
	skcipher_free_sgl(sk);
	sock_kfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm));
	sock_kfree_s(sk, ctx, ctx->len);
}

static void skcipher_sock_destruct(struct sock *sk)
{
	skcipher_sock_destruct_common(sk);
	af_alg_release_parent(sk);
}

static int skcipher_accept_parent(void *private, struct sock *sk)
static void skcipher_release_parent_nokey(struct sock *sk)
{
	struct alg_sock *ask = alg_sk(sk);

	if (!ask->refcnt) {
		sock_put(ask->parent);
		return;
	}

	af_alg_release_parent(sk);
}

static void skcipher_sock_destruct_nokey(struct sock *sk)
{
	skcipher_sock_destruct_common(sk);
	skcipher_release_parent_nokey(sk);
}

static int skcipher_accept_parent_common(void *private, struct sock *sk)
{
	struct skcipher_ctx *ctx;
	struct alg_sock *ask = alg_sk(sk);
@@ -608,9 +724,6 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
	struct crypto_ablkcipher *skcipher = tfm->skcipher;
	unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(skcipher);

	if (!tfm->has_key)
		return -ENOKEY;

	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;
@@ -644,12 +757,38 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
	return 0;
}

static int skcipher_accept_parent(void *private, struct sock *sk)
{
	struct skcipher_tfm *tfm = private;

	if (!tfm->has_key)
		return -ENOKEY;

	return skcipher_accept_parent_common(private, sk);
}

static int skcipher_accept_parent_nokey(void *private, struct sock *sk)
{
	int err;

	err = skcipher_accept_parent_common(private, sk);
	if (err)
		goto out;

	sk->sk_destruct = skcipher_sock_destruct_nokey;

out:
	return err;
}

static const struct af_alg_type algif_type_skcipher = {
	.bind		=	skcipher_bind,
	.release	=	skcipher_release,
	.setkey		=	skcipher_setkey,
	.accept		=	skcipher_accept_parent,
	.accept_nokey	=	skcipher_accept_parent_nokey,
	.ops		=	&algif_skcipher_ops,
	.ops_nokey	=	&algif_skcipher_ops_nokey,
	.name		=	"skcipher",
	.owner		=	THIS_MODULE
};