brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 10c41ad Raw
341 lines · c
1/*2 * algif_rng: User-space interface for random number generators3 *4 * This file provides the user-space API for random number generators.5 *6 * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>7 *8 * Redistribution and use in source and binary forms, with or without9 * modification, are permitted provided that the following conditions10 * are met:11 * 1. Redistributions of source code must retain the above copyright12 *    notice, and the entire permission notice in its entirety,13 *    including the disclaimer of warranties.14 * 2. Redistributions in binary form must reproduce the above copyright15 *    notice, this list of conditions and the following disclaimer in the16 *    documentation and/or other materials provided with the distribution.17 * 3. The name of the author may not be used to endorse or promote18 *    products derived from this software without specific prior19 *    written permission.20 *21 * ALTERNATIVELY, this product may be distributed under the terms of22 * the GNU General Public License, in which case the provisions of the GPL223 * are required INSTEAD OF the above restrictions.  (This clause is24 * necessary due to a potential bad interaction between the GPL and25 * the restrictions contained in a BSD-style copyright.)26 *27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF30 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT33 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR34 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE37 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH38 * DAMAGE.39 */40 41#include <linux/capability.h>42#include <linux/module.h>43#include <crypto/rng.h>44#include <linux/random.h>45#include <crypto/if_alg.h>46#include <linux/net.h>47#include <net/sock.h>48 49MODULE_LICENSE("GPL");50MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");51MODULE_DESCRIPTION("User-space interface for random number generators");52 53struct rng_ctx {54#define MAXSIZE 12855	unsigned int len;56	struct crypto_rng *drng;57	u8 *addtl;58	size_t addtl_len;59};60 61struct rng_parent_ctx {62	struct crypto_rng *drng;63	u8 *entropy;64};65 66static void rng_reset_addtl(struct rng_ctx *ctx)67{68	kfree_sensitive(ctx->addtl);69	ctx->addtl = NULL;70	ctx->addtl_len = 0;71}72 73static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len,74			u8 *addtl, size_t addtl_len)75{76	int err = 0;77	int genlen = 0;78	u8 result[MAXSIZE];79 80	if (len == 0)81		return 0;82	if (len > MAXSIZE)83		len = MAXSIZE;84 85	/*86	 * although not strictly needed, this is a precaution against coding87	 * errors88	 */89	memset(result, 0, len);90 91	/*92	 * The enforcement of a proper seeding of an RNG is done within an93	 * RNG implementation. Some RNGs (DRBG, krng) do not need specific94	 * seeding as they automatically seed. The X9.31 DRNG will return95	 * an error if it was not seeded properly.96	 */97	genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len);98	if (genlen < 0)99		return genlen;100 101	err = memcpy_to_msg(msg, result, len);102	memzero_explicit(result, len);103 104	return err ? err : len;105}106 107static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,108		       int flags)109{110	struct sock *sk = sock->sk;111	struct alg_sock *ask = alg_sk(sk);112	struct rng_ctx *ctx = ask->private;113 114	return _rng_recvmsg(ctx->drng, msg, len, NULL, 0);115}116 117static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,118			    int flags)119{120	struct sock *sk = sock->sk;121	struct alg_sock *ask = alg_sk(sk);122	struct rng_ctx *ctx = ask->private;123	int ret;124 125	lock_sock(sock->sk);126	ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len);127	rng_reset_addtl(ctx);128	release_sock(sock->sk);129 130	return ret;131}132 133static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)134{135	int err;136	struct alg_sock *ask = alg_sk(sock->sk);137	struct rng_ctx *ctx = ask->private;138 139	lock_sock(sock->sk);140	if (len > MAXSIZE) {141		err = -EMSGSIZE;142		goto unlock;143	}144 145	rng_reset_addtl(ctx);146	ctx->addtl = kmalloc(len, GFP_KERNEL);147	if (!ctx->addtl) {148		err = -ENOMEM;149		goto unlock;150	}151 152	err = memcpy_from_msg(ctx->addtl, msg, len);153	if (err) {154		rng_reset_addtl(ctx);155		goto unlock;156	}157	ctx->addtl_len = len;158 159unlock:160	release_sock(sock->sk);161	return err ? err : len;162}163 164static struct proto_ops algif_rng_ops = {165	.family		=	PF_ALG,166 167	.connect	=	sock_no_connect,168	.socketpair	=	sock_no_socketpair,169	.getname	=	sock_no_getname,170	.ioctl		=	sock_no_ioctl,171	.listen		=	sock_no_listen,172	.shutdown	=	sock_no_shutdown,173	.mmap		=	sock_no_mmap,174	.bind		=	sock_no_bind,175	.accept		=	sock_no_accept,176	.sendmsg	=	sock_no_sendmsg,177 178	.release	=	af_alg_release,179	.recvmsg	=	rng_recvmsg,180};181 182static struct proto_ops __maybe_unused algif_rng_test_ops = {183	.family		=	PF_ALG,184 185	.connect	=	sock_no_connect,186	.socketpair	=	sock_no_socketpair,187	.getname	=	sock_no_getname,188	.ioctl		=	sock_no_ioctl,189	.listen		=	sock_no_listen,190	.shutdown	=	sock_no_shutdown,191	.mmap		=	sock_no_mmap,192	.bind		=	sock_no_bind,193	.accept		=	sock_no_accept,194 195	.release	=	af_alg_release,196	.recvmsg	=	rng_test_recvmsg,197	.sendmsg	=	rng_test_sendmsg,198};199 200static void *rng_bind(const char *name, u32 type, u32 mask)201{202	struct rng_parent_ctx *pctx;203	struct crypto_rng *rng;204 205	pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);206	if (!pctx)207		return ERR_PTR(-ENOMEM);208 209	rng = crypto_alloc_rng(name, type, mask);210	if (IS_ERR(rng)) {211		kfree(pctx);212		return ERR_CAST(rng);213	}214 215	pctx->drng = rng;216	return pctx;217}218 219static void rng_release(void *private)220{221	struct rng_parent_ctx *pctx = private;222 223	if (unlikely(!pctx))224		return;225	crypto_free_rng(pctx->drng);226	kfree_sensitive(pctx->entropy);227	kfree_sensitive(pctx);228}229 230static void rng_sock_destruct(struct sock *sk)231{232	struct alg_sock *ask = alg_sk(sk);233	struct rng_ctx *ctx = ask->private;234 235	rng_reset_addtl(ctx);236	sock_kfree_s(sk, ctx, ctx->len);237	af_alg_release_parent(sk);238}239 240static int rng_accept_parent(void *private, struct sock *sk)241{242	struct rng_ctx *ctx;243	struct rng_parent_ctx *pctx = private;244	struct alg_sock *ask = alg_sk(sk);245	unsigned int len = sizeof(*ctx);246 247	ctx = sock_kmalloc(sk, len, GFP_KERNEL);248	if (!ctx)249		return -ENOMEM;250 251	ctx->len = len;252	ctx->addtl = NULL;253	ctx->addtl_len = 0;254 255	/*256	 * No seeding done at that point -- if multiple accepts are257	 * done on one RNG instance, each resulting FD points to the same258	 * state of the RNG.259	 */260 261	ctx->drng = pctx->drng;262	ask->private = ctx;263	sk->sk_destruct = rng_sock_destruct;264 265	/*266	 * Non NULL pctx->entropy means that CAVP test has been initiated on267	 * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.268	 */269	if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)270		sk->sk_socket->ops = &algif_rng_test_ops;271 272	return 0;273}274 275static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)276{277	struct rng_parent_ctx *pctx = private;278	/*279	 * Check whether seedlen is of sufficient size is done in RNG280	 * implementations.281	 */282	return crypto_rng_reset(pctx->drng, seed, seedlen);283}284 285static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,286					 unsigned int len)287{288	struct rng_parent_ctx *pctx = private;289	u8 *kentropy = NULL;290 291	if (!capable(CAP_SYS_ADMIN))292		return -EACCES;293 294	if (pctx->entropy)295		return -EINVAL;296 297	if (len > MAXSIZE)298		return -EMSGSIZE;299 300	if (len) {301		kentropy = memdup_sockptr(entropy, len);302		if (IS_ERR(kentropy))303			return PTR_ERR(kentropy);304	}305 306	crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);307	/*308	 * Since rng doesn't perform any memory management for the entropy309	 * buffer, save kentropy pointer to pctx now to free it after use.310	 */311	pctx->entropy = kentropy;312	return 0;313}314 315static const struct af_alg_type algif_type_rng = {316	.bind		=	rng_bind,317	.release	=	rng_release,318	.accept		=	rng_accept_parent,319	.setkey		=	rng_setkey,320#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP321	.setentropy	=	rng_setentropy,322#endif323	.ops		=	&algif_rng_ops,324	.name		=	"rng",325	.owner		=	THIS_MODULE326};327 328static int __init rng_init(void)329{330	return af_alg_register_type(&algif_type_rng);331}332 333static void __exit rng_exit(void)334{335	int err = af_alg_unregister_type(&algif_type_rng);336	BUG_ON(err);337}338 339module_init(rng_init);340module_exit(rng_exit);341