brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 5cb6a77 Raw
295 lines · c
1/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */2/*3 * Test interface for Jitter RNG.4 *5 * Copyright (C) 2023, Stephan Mueller <smueller@chronox.de>6 */7 8#include <linux/debugfs.h>9#include <linux/module.h>10#include <linux/uaccess.h>11 12#include "jitterentropy.h"13 14#define JENT_TEST_RINGBUFFER_SIZE	(1<<10)15#define JENT_TEST_RINGBUFFER_MASK	(JENT_TEST_RINGBUFFER_SIZE - 1)16 17struct jent_testing {18	u32 jent_testing_rb[JENT_TEST_RINGBUFFER_SIZE];19	u32 rb_reader;20	atomic_t rb_writer;21	atomic_t jent_testing_enabled;22	spinlock_t lock;23	wait_queue_head_t read_wait;24};25 26static struct dentry *jent_raw_debugfs_root = NULL;27 28/*************************** Generic Data Handling ****************************/29 30/*31 * boot variable:32 * 0 ==> No boot test, gathering of runtime data allowed33 * 1 ==> Boot test enabled and ready for collecting data, gathering runtime34 *	 data is disabled35 * 2 ==> Boot test completed and disabled, gathering of runtime data is36 *	 disabled37 */38 39static void jent_testing_reset(struct jent_testing *data)40{41	unsigned long flags;42 43	spin_lock_irqsave(&data->lock, flags);44	data->rb_reader = 0;45	atomic_set(&data->rb_writer, 0);46	spin_unlock_irqrestore(&data->lock, flags);47}48 49static void jent_testing_data_init(struct jent_testing *data, u32 boot)50{51	/*52	 * The boot time testing implies we have a running test. If the53	 * caller wants to clear it, he has to unset the boot_test flag54	 * at runtime via sysfs to enable regular runtime testing55	 */56	if (boot)57		return;58 59	jent_testing_reset(data);60	atomic_set(&data->jent_testing_enabled, 1);61	pr_warn("Enabling data collection\n");62}63 64static void jent_testing_fini(struct jent_testing *data, u32 boot)65{66	/* If we have boot data, we do not reset yet to allow data to be read */67	if (boot)68		return;69 70	atomic_set(&data->jent_testing_enabled, 0);71	jent_testing_reset(data);72	pr_warn("Disabling data collection\n");73}74 75static bool jent_testing_store(struct jent_testing *data, u32 value,76			       u32 *boot)77{78	unsigned long flags;79 80	if (!atomic_read(&data->jent_testing_enabled) && (*boot != 1))81		return false;82 83	spin_lock_irqsave(&data->lock, flags);84 85	/*86	 * Disable entropy testing for boot time testing after ring buffer87	 * is filled.88	 */89	if (*boot) {90		if (((u32)atomic_read(&data->rb_writer)) >91		     JENT_TEST_RINGBUFFER_SIZE) {92			*boot = 2;93			pr_warn_once("One time data collection test disabled\n");94			spin_unlock_irqrestore(&data->lock, flags);95			return false;96		}97 98		if (atomic_read(&data->rb_writer) == 1)99			pr_warn("One time data collection test enabled\n");100	}101 102	data->jent_testing_rb[((u32)atomic_read(&data->rb_writer)) &103			      JENT_TEST_RINGBUFFER_MASK] = value;104	atomic_inc(&data->rb_writer);105 106	spin_unlock_irqrestore(&data->lock, flags);107 108	if (wq_has_sleeper(&data->read_wait))109		wake_up_interruptible(&data->read_wait);110 111	return true;112}113 114static bool jent_testing_have_data(struct jent_testing *data)115{116	return ((((u32)atomic_read(&data->rb_writer)) &117		 JENT_TEST_RINGBUFFER_MASK) !=118		 (data->rb_reader & JENT_TEST_RINGBUFFER_MASK));119}120 121static int jent_testing_reader(struct jent_testing *data, u32 *boot,122			       u8 *outbuf, u32 outbuflen)123{124	unsigned long flags;125	int collected_data = 0;126 127	jent_testing_data_init(data, *boot);128 129	while (outbuflen) {130		u32 writer = (u32)atomic_read(&data->rb_writer);131 132		spin_lock_irqsave(&data->lock, flags);133 134		/* We have no data or reached the writer. */135		if (!writer || (writer == data->rb_reader)) {136 137			spin_unlock_irqrestore(&data->lock, flags);138 139			/*140			 * Now we gathered all boot data, enable regular data141			 * collection.142			 */143			if (*boot) {144				*boot = 0;145				goto out;146			}147 148			wait_event_interruptible(data->read_wait,149						 jent_testing_have_data(data));150			if (signal_pending(current)) {151				collected_data = -ERESTARTSYS;152				goto out;153			}154 155			continue;156		}157 158		/* We copy out word-wise */159		if (outbuflen < sizeof(u32)) {160			spin_unlock_irqrestore(&data->lock, flags);161			goto out;162		}163 164		memcpy(outbuf, &data->jent_testing_rb[data->rb_reader],165		       sizeof(u32));166		data->rb_reader++;167 168		spin_unlock_irqrestore(&data->lock, flags);169 170		outbuf += sizeof(u32);171		outbuflen -= sizeof(u32);172		collected_data += sizeof(u32);173	}174 175out:176	jent_testing_fini(data, *boot);177	return collected_data;178}179 180static int jent_testing_extract_user(struct file *file, char __user *buf,181				     size_t nbytes, loff_t *ppos,182				     int (*reader)(u8 *outbuf, u32 outbuflen))183{184	u8 *tmp, *tmp_aligned;185	int ret = 0, large_request = (nbytes > 256);186 187	if (!nbytes)188		return 0;189 190	/*191	 * The intention of this interface is for collecting at least192	 * 1000 samples due to the SP800-90B requirements. So, we make no193	 * effort in avoiding allocating more memory that actually needed194	 * by the user. Hence, we allocate sufficient memory to always hold195	 * that amount of data.196	 */197	tmp = kmalloc(JENT_TEST_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL);198	if (!tmp)199		return -ENOMEM;200 201	tmp_aligned = PTR_ALIGN(tmp, sizeof(u32));202 203	while (nbytes) {204		int i;205 206		if (large_request && need_resched()) {207			if (signal_pending(current)) {208				if (ret == 0)209					ret = -ERESTARTSYS;210				break;211			}212			schedule();213		}214 215		i = min_t(int, nbytes, JENT_TEST_RINGBUFFER_SIZE);216		i = reader(tmp_aligned, i);217		if (i <= 0) {218			if (i < 0)219				ret = i;220			break;221		}222		if (copy_to_user(buf, tmp_aligned, i)) {223			ret = -EFAULT;224			break;225		}226 227		nbytes -= i;228		buf += i;229		ret += i;230	}231 232	kfree_sensitive(tmp);233 234	if (ret > 0)235		*ppos += ret;236 237	return ret;238}239 240/************** Raw High-Resolution Timer Entropy Data Handling **************/241 242static u32 boot_raw_hires_test = 0;243module_param(boot_raw_hires_test, uint, 0644);244MODULE_PARM_DESC(boot_raw_hires_test,245		 "Enable gathering boot time high resolution timer entropy of the first Jitter RNG entropy events");246 247static struct jent_testing jent_raw_hires = {248	.rb_reader = 0,249	.rb_writer = ATOMIC_INIT(0),250	.lock      = __SPIN_LOCK_UNLOCKED(jent_raw_hires.lock),251	.read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(jent_raw_hires.read_wait)252};253 254int jent_raw_hires_entropy_store(__u32 value)255{256	return jent_testing_store(&jent_raw_hires, value, &boot_raw_hires_test);257}258EXPORT_SYMBOL(jent_raw_hires_entropy_store);259 260static int jent_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen)261{262	return jent_testing_reader(&jent_raw_hires, &boot_raw_hires_test,263				   outbuf, outbuflen);264}265 266static ssize_t jent_raw_hires_read(struct file *file, char __user *to,267				   size_t count, loff_t *ppos)268{269	return jent_testing_extract_user(file, to, count, ppos,270					 jent_raw_hires_entropy_reader);271}272 273static const struct file_operations jent_raw_hires_fops = {274	.owner = THIS_MODULE,275	.read = jent_raw_hires_read,276};277 278/******************************* Initialization *******************************/279 280void jent_testing_init(void)281{282	jent_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);283 284	debugfs_create_file_unsafe("jent_raw_hires", 0400,285				   jent_raw_debugfs_root, NULL,286				   &jent_raw_hires_fops);287}288EXPORT_SYMBOL(jent_testing_init);289 290void jent_testing_exit(void)291{292	debugfs_remove_recursive(jent_raw_debugfs_root);293}294EXPORT_SYMBOL(jent_testing_exit);295