1 /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-C 1 2 /* 3 * Test interface for Jitter RNG. 4 * 5 * Copyright (C) 2023, Stephan Mueller <smuell 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_ 16 17 struct jent_testing { 18 u32 jent_testing_rb[JENT_TEST_RINGBUFF 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 26 static struct dentry *jent_raw_debugfs_root = 27 28 /*************************** Generic Data Hand 29 30 /* 31 * boot variable: 32 * 0 ==> No boot test, gathering of runtime da 33 * 1 ==> Boot test enabled and ready for colle 34 * data is disabled 35 * 2 ==> Boot test completed and disabled, gat 36 * disabled 37 */ 38 39 static void jent_testing_reset(struct jent_tes 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, fl 47 } 48 49 static void jent_testing_data_init(struct jent 50 { 51 /* 52 * The boot time testing implies we ha 53 * caller wants to clear it, he has to 54 * at runtime via sysfs to enable regu 55 */ 56 if (boot) 57 return; 58 59 jent_testing_reset(data); 60 atomic_set(&data->jent_testing_enabled 61 pr_warn("Enabling data collection\n"); 62 } 63 64 static void jent_testing_fini(struct jent_test 65 { 66 /* If we have boot data, we do not res 67 if (boot) 68 return; 69 70 atomic_set(&data->jent_testing_enabled 71 jent_testing_reset(data); 72 pr_warn("Disabling data collection\n") 73 } 74 75 static bool jent_testing_store(struct jent_tes 76 u32 *boot) 77 { 78 unsigned long flags; 79 80 if (!atomic_read(&data->jent_testing_e 81 return false; 82 83 spin_lock_irqsave(&data->lock, flags); 84 85 /* 86 * Disable entropy testing for boot ti 87 * is filled. 88 */ 89 if (*boot) { 90 if (((u32)atomic_read(&data->r 91 JENT_TEST_RINGBUFFER_SIZE 92 *boot = 2; 93 pr_warn_once("One time 94 spin_unlock_irqrestore 95 return false; 96 } 97 98 if (atomic_read(&data->rb_writ 99 pr_warn("One time data 100 } 101 102 data->jent_testing_rb[((u32)atomic_rea 103 JENT_TEST_RINGBU 104 atomic_inc(&data->rb_writer); 105 106 spin_unlock_irqrestore(&data->lock, fl 107 108 if (wq_has_sleeper(&data->read_wait)) 109 wake_up_interruptible(&data->r 110 111 return true; 112 } 113 114 static bool jent_testing_have_data(struct jent 115 { 116 return ((((u32)atomic_read(&data->rb_w 117 JENT_TEST_RINGBUFFER_MASK) != 118 (data->rb_reader & JENT_TEST_ 119 } 120 121 static int jent_testing_reader(struct jent_tes 122 u8 *outbuf, u32 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( 131 132 spin_lock_irqsave(&data->lock, 133 134 /* We have no data or reached 135 if (!writer || (writer == data 136 137 spin_unlock_irqrestore 138 139 /* 140 * Now we gathered all 141 * collection. 142 */ 143 if (*boot) { 144 *boot = 0; 145 goto out; 146 } 147 148 wait_event_interruptib 149 150 if (signal_pending(cur 151 collected_data 152 goto out; 153 } 154 155 continue; 156 } 157 158 /* We copy out word-wise */ 159 if (outbuflen < sizeof(u32)) { 160 spin_unlock_irqrestore 161 goto out; 162 } 163 164 memcpy(outbuf, &data->jent_tes 165 sizeof(u32)); 166 data->rb_reader++; 167 168 spin_unlock_irqrestore(&data-> 169 170 outbuf += sizeof(u32); 171 outbuflen -= sizeof(u32); 172 collected_data += sizeof(u32); 173 } 174 175 out: 176 jent_testing_fini(data, *boot); 177 return collected_data; 178 } 179 180 static int jent_testing_extract_user(struct fi 181 size_t nb 182 int (*rea 183 { 184 u8 *tmp, *tmp_aligned; 185 int ret = 0, large_request = (nbytes > 186 187 if (!nbytes) 188 return 0; 189 190 /* 191 * The intention of this interface is 192 * 1000 samples due to the SP800-90B r 193 * effort in avoiding allocating more 194 * by the user. Hence, we allocate suf 195 * that amount of data. 196 */ 197 tmp = kmalloc(JENT_TEST_RINGBUFFER_SIZ 198 if (!tmp) 199 return -ENOMEM; 200 201 tmp_aligned = PTR_ALIGN(tmp, sizeof(u3 202 203 while (nbytes) { 204 int i; 205 206 if (large_request && need_resc 207 if (signal_pending(cur 208 if (ret == 0) 209 ret = 210 break; 211 } 212 schedule(); 213 } 214 215 i = min_t(int, nbytes, JENT_TE 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_alig 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 Entr 241 242 static u32 boot_raw_hires_test = 0; 243 module_param(boot_raw_hires_test, uint, 0644); 244 MODULE_PARM_DESC(boot_raw_hires_test, 245 "Enable gathering boot time h 246 247 static struct jent_testing jent_raw_hires = { 248 .rb_reader = 0, 249 .rb_writer = ATOMIC_INIT(0), 250 .lock = __SPIN_LOCK_UNLOCKED(jent 251 .read_wait = __WAIT_QUEUE_HEAD_INITIAL 252 }; 253 254 int jent_raw_hires_entropy_store(__u32 value) 255 { 256 return jent_testing_store(&jent_raw_hi 257 } 258 EXPORT_SYMBOL(jent_raw_hires_entropy_store); 259 260 static int jent_raw_hires_entropy_reader(u8 *o 261 { 262 return jent_testing_reader(&jent_raw_h 263 outbuf, out 264 } 265 266 static ssize_t jent_raw_hires_read(struct file 267 size_t coun 268 { 269 return jent_testing_extract_user(file, 270 jent_ 271 } 272 273 static const struct file_operations jent_raw_h 274 .owner = THIS_MODULE, 275 .read = jent_raw_hires_read, 276 }; 277 278 /******************************* Initializatio 279 280 void jent_testing_init(void) 281 { 282 jent_raw_debugfs_root = debugfs_create 283 284 debugfs_create_file_unsafe("jent_raw_h 285 jent_raw_de 286 &jent_raw_h 287 } 288 EXPORT_SYMBOL(jent_testing_init); 289 290 void jent_testing_exit(void) 291 { 292 debugfs_remove_recursive(jent_raw_debu 293 } 294 EXPORT_SYMBOL(jent_testing_exit); 295
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.