From: Stephan Mueller Subject: [PATCH v5 5/8] crypto: AF_ALG: add user space interface for RNG Date: Sun, 07 Dec 2014 23:23:48 +0100 Message-ID: <3380968.kTQNpvjKFa@tachyon.chronox.de> References: <56740432.V2v4gLHrzS@tachyon.chronox.de> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit Cc: Daniel Borkmann , 'Quentin Gouchet' , 'LKML' , linux-crypto@vger.kernel.org, linux-api@vger.kernel.org To: Herbert Xu Return-path: In-Reply-To: <56740432.V2v4gLHrzS@tachyon.chronox.de> Sender: linux-kernel-owner@vger.kernel.org List-Id: linux-crypto.vger.kernel.org Allow user space to seed / reset the RNG via a setsockopt. This patch reuses alg_setkey to copy data into the kernel. The alg_setkey is now used for two mechanisms: setkey and seeding. The function is extended by the providing the function pointer to the function handling the copied data. As the alg_setkey is now usable for more than just setkey, it is renamed to alg_setop. Signed-off-by: Stephan Mueller --- crypto/af_alg.c | 29 +++++++++++++++++++---------- include/crypto/if_alg.h | 1 + include/uapi/linux/if_alg.h | 1 + 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 547c369..d1eb1e9 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -169,26 +169,27 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return 0; } -static int alg_setkey(struct sock *sk, char __user *ukey, - unsigned int keylen) +static int alg_setop(struct sock *sk, char __user *udata, + unsigned int datalen, + int (*handler)(void *private, const u8 *data, + unsigned int datalen)) { struct alg_sock *ask = alg_sk(sk); - const struct af_alg_type *type = ask->type; - u8 *key; + u8 *data; int err; - key = sock_kmalloc(sk, keylen, GFP_KERNEL); - if (!key) + data = sock_kmalloc(sk, datalen, GFP_KERNEL); + if (!data) return -ENOMEM; err = -EFAULT; - if (copy_from_user(key, ukey, keylen)) + if (copy_from_user(data, udata, datalen)) goto out; - err = type->setkey(ask->private, key, keylen); + err = handler(ask->private, data, datalen); out: - sock_kfree_s(sk, key, keylen); + sock_kfree_s(sk, data, datalen); return err; } @@ -214,7 +215,7 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, if (!type->setkey) goto unlock; - err = alg_setkey(sk, optval, optlen); + err = alg_setop(sk, optval, optlen, type->setkey); break; case ALG_SET_AEAD_AUTHSIZE: if (sock->state == SS_CONNECTED) @@ -222,6 +223,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, if (!type->setauthsize) goto unlock; err = type->setauthsize(ask->private, optlen); + break; + case ALG_SET_RNG_SEED: + if (sock->state == SS_CONNECTED) + goto unlock; + if (!type->setseed) + goto unlock; + + err = alg_setop(sk, optval, optlen, type->setseed); } unlock: diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 5c7b6c5..0808ed1 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -51,6 +51,7 @@ struct af_alg_type { int (*setkey)(void *private, const u8 *key, unsigned int keylen); int (*accept)(void *private, struct sock *sk); int (*setauthsize)(void *private, unsigned int authsize); + int (*setseed)(void *private, const u8 *seed, unsigned int seedlen); struct proto_ops *ops; struct module *owner; diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h index f2acd2f..973dcca 100644 --- a/include/uapi/linux/if_alg.h +++ b/include/uapi/linux/if_alg.h @@ -34,6 +34,7 @@ struct af_alg_iv { #define ALG_SET_OP 3 #define ALG_SET_AEAD_ASSOCLEN 4 #define ALG_SET_AEAD_AUTHSIZE 5 +#define ALG_SET_RNG_SEED 6 /* Operations */ #define ALG_OP_DECRYPT 0 -- 2.1.0