cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

algif_rng.c (8617B)


      1/*
      2 * algif_rng: User-space interface for random number generators
      3 *
      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 without
      9 * modification, are permitted provided that the following conditions
     10 * are met:
     11 * 1. Redistributions of source code must retain the above copyright
     12 *    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 copyright
     15 *    notice, this list of conditions and the following disclaimer in the
     16 *    documentation and/or other materials provided with the distribution.
     17 * 3. The name of the author may not be used to endorse or promote
     18 *    products derived from this software without specific prior
     19 *    written permission.
     20 *
     21 * ALTERNATIVELY, this product may be distributed under the terms of
     22 * the GNU General Public License, in which case the provisions of the GPL2
     23 * are required INSTEAD OF the above restrictions.  (This clause is
     24 * necessary due to a potential bad interaction between the GPL and
     25 * the restrictions contained in a BSD-style copyright.)
     26 *
     27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
     30 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
     31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     33 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     34 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     35 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     37 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
     38 * 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 128
     55	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 coding
     87	 * errors
     88	 */
     89	memset(result, 0, len);
     90
     91	/*
     92	 * The enforcement of a proper seeding of an RNG is done within an
     93	 * RNG implementation. Some RNGs (DRBG, krng) do not need specific
     94	 * seeding as they automatically seed. The X9.31 DRNG will return
     95	 * 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	.sendpage	=	sock_no_sendpage,
    178
    179	.release	=	af_alg_release,
    180	.recvmsg	=	rng_recvmsg,
    181};
    182
    183static struct proto_ops __maybe_unused algif_rng_test_ops = {
    184	.family		=	PF_ALG,
    185
    186	.connect	=	sock_no_connect,
    187	.socketpair	=	sock_no_socketpair,
    188	.getname	=	sock_no_getname,
    189	.ioctl		=	sock_no_ioctl,
    190	.listen		=	sock_no_listen,
    191	.shutdown	=	sock_no_shutdown,
    192	.mmap		=	sock_no_mmap,
    193	.bind		=	sock_no_bind,
    194	.accept		=	sock_no_accept,
    195	.sendpage	=	sock_no_sendpage,
    196
    197	.release	=	af_alg_release,
    198	.recvmsg	=	rng_test_recvmsg,
    199	.sendmsg	=	rng_test_sendmsg,
    200};
    201
    202static void *rng_bind(const char *name, u32 type, u32 mask)
    203{
    204	struct rng_parent_ctx *pctx;
    205	struct crypto_rng *rng;
    206
    207	pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
    208	if (!pctx)
    209		return ERR_PTR(-ENOMEM);
    210
    211	rng = crypto_alloc_rng(name, type, mask);
    212	if (IS_ERR(rng)) {
    213		kfree(pctx);
    214		return ERR_CAST(rng);
    215	}
    216
    217	pctx->drng = rng;
    218	return pctx;
    219}
    220
    221static void rng_release(void *private)
    222{
    223	struct rng_parent_ctx *pctx = private;
    224
    225	if (unlikely(!pctx))
    226		return;
    227	crypto_free_rng(pctx->drng);
    228	kfree_sensitive(pctx->entropy);
    229	kfree_sensitive(pctx);
    230}
    231
    232static void rng_sock_destruct(struct sock *sk)
    233{
    234	struct alg_sock *ask = alg_sk(sk);
    235	struct rng_ctx *ctx = ask->private;
    236
    237	rng_reset_addtl(ctx);
    238	sock_kfree_s(sk, ctx, ctx->len);
    239	af_alg_release_parent(sk);
    240}
    241
    242static int rng_accept_parent(void *private, struct sock *sk)
    243{
    244	struct rng_ctx *ctx;
    245	struct rng_parent_ctx *pctx = private;
    246	struct alg_sock *ask = alg_sk(sk);
    247	unsigned int len = sizeof(*ctx);
    248
    249	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
    250	if (!ctx)
    251		return -ENOMEM;
    252
    253	ctx->len = len;
    254	ctx->addtl = NULL;
    255	ctx->addtl_len = 0;
    256
    257	/*
    258	 * No seeding done at that point -- if multiple accepts are
    259	 * done on one RNG instance, each resulting FD points to the same
    260	 * state of the RNG.
    261	 */
    262
    263	ctx->drng = pctx->drng;
    264	ask->private = ctx;
    265	sk->sk_destruct = rng_sock_destruct;
    266
    267	/*
    268	 * Non NULL pctx->entropy means that CAVP test has been initiated on
    269	 * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.
    270	 */
    271	if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)
    272		sk->sk_socket->ops = &algif_rng_test_ops;
    273
    274	return 0;
    275}
    276
    277static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
    278{
    279	struct rng_parent_ctx *pctx = private;
    280	/*
    281	 * Check whether seedlen is of sufficient size is done in RNG
    282	 * implementations.
    283	 */
    284	return crypto_rng_reset(pctx->drng, seed, seedlen);
    285}
    286
    287static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy,
    288					 unsigned int len)
    289{
    290	struct rng_parent_ctx *pctx = private;
    291	u8 *kentropy = NULL;
    292
    293	if (!capable(CAP_SYS_ADMIN))
    294		return -EACCES;
    295
    296	if (pctx->entropy)
    297		return -EINVAL;
    298
    299	if (len > MAXSIZE)
    300		return -EMSGSIZE;
    301
    302	if (len) {
    303		kentropy = memdup_sockptr(entropy, len);
    304		if (IS_ERR(kentropy))
    305			return PTR_ERR(kentropy);
    306	}
    307
    308	crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
    309	/*
    310	 * Since rng doesn't perform any memory management for the entropy
    311	 * buffer, save kentropy pointer to pctx now to free it after use.
    312	 */
    313	pctx->entropy = kentropy;
    314	return 0;
    315}
    316
    317static const struct af_alg_type algif_type_rng = {
    318	.bind		=	rng_bind,
    319	.release	=	rng_release,
    320	.accept		=	rng_accept_parent,
    321	.setkey		=	rng_setkey,
    322#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
    323	.setentropy	=	rng_setentropy,
    324#endif
    325	.ops		=	&algif_rng_ops,
    326	.name		=	"rng",
    327	.owner		=	THIS_MODULE
    328};
    329
    330static int __init rng_init(void)
    331{
    332	return af_alg_register_type(&algif_type_rng);
    333}
    334
    335static void __exit rng_exit(void)
    336{
    337	int err = af_alg_unregister_type(&algif_type_rng);
    338	BUG_ON(err);
    339}
    340
    341module_init(rng_init);
    342module_exit(rng_exit);