| 1 | |
| 2 | * hw_random/core.c: HWRNG core API
|
| 3 | *
|
| 4 | * Copyright 2006 Michael Buesch <[email protected]>
|
| 5 | * Copyright 2005 (c) MontaVista Software, Inc.
|
| 6 | *
|
| 7 | * Please read Documentation/admin-guide/hw_random.rst for details on use.
|
| 8 | *
|
| 9 | * This software may be used and distributed according to the terms
|
| 10 | * of the GNU General Public License, incorporated herein by reference.
|
| 11 |
|
| 12 |
|
| 13 | #include <linux/delay.h>
|
| 14 | #include <linux/device.h>
|
| 15 | #include <linux/err.h>
|
| 16 | #include <linux/fs.h>
|
| 17 | #include <linux/hw_random.h>
|
| 18 | #include <linux/kernel.h>
|
| 19 | #include <linux/kthread.h>
|
| 20 | #include <linux/lockdep.h>
|
| 21 | #include <linux/miscdevice.h>
|
| 22 | #include <linux/module.h>
|
| 23 | #include <linux/notifier.h>
|
| 24 | #include <linux/random.h>
|
| 25 | #include <linux/rcupdate.h>
|
| 26 | #include <linux/sched.h>
|
| 27 | #include <linux/sched/signal.h>
|
| 28 | #include <linux/slab.h>
|
| 29 | #include <linux/string.h>
|
| 30 | #include <linux/suspend.h>
|
| 31 | #include <linux/sysfs.h>
|
| 32 | #include <linux/uaccess.h>
|
| 33 | #include <linux/workqueue.h>
|
| 34 |
|
| 35 | #define RNG_MODULE_NAME "hw_random"
|
| 36 |
|
| 37 | #define RNG_BUFFER_SIZE MAX(32, SMP_CACHE_BYTES)
|
| 38 |
|
| 39 | static struct hwrng __rcu *current_rng;
|
| 40 |
|
| 41 | static int cur_rng_set_by_user;
|
| 42 | static struct task_struct *hwrng_fill;
|
| 43 |
|
| 44 | static LIST_HEAD(rng_list);
|
| 45 |
|
| 46 | static DEFINE_MUTEX(rng_mutex);
|
| 47 |
|
| 48 | static DEFINE_MUTEX(reading_mutex);
|
| 49 | static int data_avail;
|
| 50 | static u8 *rng_buffer, *rng_fillbuf;
|
| 51 |
|
| 52 | static bool hwrng_fillfn_stopped;
|
| 53 | static unsigned short current_quality;
|
| 54 | static unsigned short default_quality = 1024;
|
| 55 |
|
| 56 | module_param(current_quality, ushort, 0644);
|
| 57 | MODULE_PARM_DESC(current_quality,
|
| 58 | "current hwrng entropy estimation per 1024 bits of input -- obsolete, use rng_quality instead");
|
| 59 | module_param(default_quality, ushort, 0644);
|
| 60 | MODULE_PARM_DESC(default_quality,
|
| 61 | "default maximum entropy content of hwrng per 1024 bits of input");
|
| 62 |
|
| 63 | static int hwrng_init(struct hwrng *rng);
|
| 64 | static int hwrng_fillfn(void *unused);
|
| 65 | static void hwrng_start_hwrng_fillfn(void);
|
| 66 | static void hwrng_stop_hwrng_fillfn(void);
|
| 67 |
|
| 68 | static size_t rng_buffer_size(void)
|
| 69 | {
|
| 70 | return RNG_BUFFER_SIZE;
|
| 71 | }
|
| 72 |
|
| 73 | static void cleanup_rng_work(struct work_struct *work)
|
| 74 | {
|
| 75 | struct hwrng *rng = container_of(work, struct hwrng, cleanup_work);
|
| 76 |
|
| 77 | |
| 78 | * Hold rng_mutex here so we serialize in case they set_current_rng
|
| 79 | * on rng again immediately.
|
| 80 |
|
| 81 | mutex_lock(&rng_mutex);
|
| 82 |
|
| 83 |
|
| 84 | if (kref_read(&rng->ref)) {
|
| 85 | mutex_unlock(&rng_mutex);
|
| 86 | return;
|
| 87 | }
|
| 88 |
|
| 89 | if (rng->cleanup)
|
| 90 | rng->cleanup(rng);
|
| 91 |
|
| 92 | complete(&rng->cleanup_done);
|
| 93 | mutex_unlock(&rng_mutex);
|
| 94 | }
|
| 95 |
|
| 96 | static inline void cleanup_rng(struct kref *kref)
|
| 97 | {
|
| 98 | struct hwrng *rng = container_of(kref, struct hwrng, ref);
|
| 99 |
|
| 100 | schedule_work(&rng->cleanup_work);
|
| 101 | }
|
| 102 |
|
| 103 | static int set_current_rng(struct hwrng *rng)
|
| 104 | {
|
| 105 | struct hwrng *old_rng;
|
| 106 | int err;
|
| 107 |
|
| 108 | BUG_ON(!mutex_is_locked(&rng_mutex));
|
| 109 |
|
| 110 | err = hwrng_init(rng);
|
| 111 | if (err)
|
| 112 | return err;
|
| 113 |
|
| 114 | old_rng = rcu_dereference_protected(current_rng,
|
| 115 | lockdep_is_held(&rng_mutex));
|
| 116 | rcu_assign_pointer(current_rng, rng);
|
| 117 |
|
| 118 | if (old_rng) {
|
| 119 | synchronize_rcu();
|
| 120 | kref_put(&old_rng->ref, cleanup_rng);
|
| 121 | }
|
| 122 |
|
| 123 |
|
| 124 | hwrng_start_hwrng_fillfn();
|
| 125 |
|
| 126 | return 0;
|
| 127 | }
|
| 128 |
|
| 129 | static void drop_current_rng(void)
|
| 130 | {
|
| 131 | struct hwrng *rng;
|
| 132 |
|
| 133 | rng = rcu_dereference_protected(current_rng,
|
| 134 | lockdep_is_held(&rng_mutex));
|
| 135 | if (!rng)
|
| 136 | return;
|
| 137 |
|
| 138 | RCU_INIT_POINTER(current_rng, NULL);
|
| 139 | synchronize_rcu();
|
| 140 |
|
| 141 | hwrng_stop_hwrng_fillfn();
|
| 142 |
|
| 143 |
|
| 144 | kref_put(&rng->ref, cleanup_rng);
|
| 145 | }
|
| 146 |
|
| 147 |
|
| 148 | static struct hwrng *get_current_rng_nolock(void)
|
| 149 | {
|
| 150 | struct hwrng *rng;
|
| 151 |
|
| 152 | rng = rcu_dereference_protected(current_rng,
|
| 153 | lockdep_is_held(&rng_mutex));
|
| 154 | if (rng)
|
| 155 | kref_get(&rng->ref);
|
| 156 |
|
| 157 | return rng;
|
| 158 | }
|
| 159 |
|
| 160 | static struct hwrng *get_current_rng(void)
|
| 161 | {
|
| 162 | struct hwrng *rng;
|
| 163 |
|
| 164 | rcu_read_lock();
|
| 165 | rng = rcu_dereference(current_rng);
|
| 166 | if (rng)
|
| 167 | kref_get(&rng->ref);
|
| 168 |
|
| 169 | rcu_read_unlock();
|
| 170 |
|
| 171 | return rng;
|
| 172 | }
|
| 173 |
|
| 174 | static void put_rng(struct hwrng *rng)
|
| 175 | {
|
| 176 | if (rng)
|
| 177 | kref_put(&rng->ref, cleanup_rng);
|
| 178 | }
|
| 179 |
|
| 180 | static int hwrng_init(struct hwrng *rng)
|
| 181 | {
|
| 182 | if (kref_get_unless_zero(&rng->ref))
|
| 183 | goto skip_init;
|
| 184 |
|
| 185 | if (rng->init) {
|
| 186 | int ret;
|
| 187 |
|
| 188 | ret = rng->init(rng);
|
| 189 | if (ret)
|
| 190 | return ret;
|
| 191 | }
|
| 192 |
|
| 193 | kref_init(&rng->ref);
|
| 194 | reinit_completion(&rng->cleanup_done);
|
| 195 |
|
| 196 | skip_init:
|
| 197 | current_quality = rng->quality;
|
| 198 |
|
| 199 | return 0;
|
| 200 | }
|
| 201 |
|
| 202 | static int rng_dev_open(struct inode *inode, struct file *filp)
|
| 203 | {
|
| 204 |
|
| 205 | if ((filp->f_mode & FMODE_READ) == 0)
|
| 206 | return -EINVAL;
|
| 207 | if (filp->f_mode & FMODE_WRITE)
|
| 208 | return -EINVAL;
|
| 209 | return 0;
|
| 210 | }
|
| 211 |
|
| 212 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, bool wait)
|
| 213 | {
|
| 214 | int present;
|
| 215 |
|
| 216 | BUG_ON(!mutex_is_locked(&reading_mutex));
|
| 217 | if (rng->read) {
|
| 218 | int err;
|
| 219 |
|
| 220 | err = rng->read(rng, buffer, size, wait);
|
| 221 | if (WARN_ON_ONCE(err > 0 && err > size))
|
| 222 | err = size;
|
| 223 |
|
| 224 | return err;
|
| 225 | }
|
| 226 |
|
| 227 | if (rng->data_present)
|
| 228 | present = rng->data_present(rng, wait);
|
| 229 | else
|
| 230 | present = 1;
|
| 231 |
|
| 232 | if (present)
|
| 233 | return rng->data_read(rng, (u32 *)buffer);
|
| 234 |
|
| 235 | return 0;
|
| 236 | }
|
| 237 |
|
| 238 | static ssize_t rng_dev_read(struct file *filp, char __user *buf,
|
| 239 | size_t size, loff_t *offp)
|
| 240 | {
|
| 241 | u8 buffer[RNG_BUFFER_SIZE];
|
| 242 | ssize_t ret = 0;
|
| 243 | int err = 0;
|
| 244 | int bytes_read, len;
|
| 245 | struct hwrng *rng;
|
| 246 |
|
| 247 | while (size) {
|
| 248 | rng = get_current_rng();
|
| 249 | if (!rng) {
|
| 250 | err = -ENODEV;
|
| 251 | goto out;
|
| 252 | }
|
| 253 |
|
| 254 | if (mutex_lock_interruptible(&reading_mutex)) {
|
| 255 | err = -ERESTARTSYS;
|
| 256 | goto out_put;
|
| 257 | }
|
| 258 | if (!data_avail) {
|
| 259 | bytes_read = rng_get_data(rng, rng_buffer,
|
| 260 | rng_buffer_size(),
|
| 261 | !(filp->f_flags & O_NONBLOCK));
|
| 262 | if (bytes_read < 0) {
|
| 263 | err = bytes_read;
|
| 264 | goto out_unlock_reading;
|
| 265 | } else if (bytes_read == 0 &&
|
| 266 | (filp->f_flags & O_NONBLOCK)) {
|
| 267 | err = -EAGAIN;
|
| 268 | goto out_unlock_reading;
|
| 269 | }
|
| 270 |
|
| 271 | data_avail = bytes_read;
|
| 272 | }
|
| 273 |
|
| 274 | len = data_avail;
|
| 275 | if (len) {
|
| 276 | if (len > size)
|
| 277 | len = size;
|
| 278 |
|
| 279 | data_avail -= len;
|
| 280 |
|
| 281 | memcpy(buffer, rng_buffer + data_avail, len);
|
| 282 | }
|
| 283 | mutex_unlock(&reading_mutex);
|
| 284 | put_rng(rng);
|
| 285 |
|
| 286 | if (len) {
|
| 287 | if (copy_to_user(buf + ret, buffer, len)) {
|
| 288 | err = -EFAULT;
|
| 289 | goto out;
|
| 290 | }
|
| 291 |
|
| 292 | size -= len;
|
| 293 | ret += len;
|
| 294 | }
|
| 295 |
|
| 296 |
|
| 297 | if (need_resched())
|
| 298 | schedule_timeout_interruptible(1);
|
| 299 |
|
| 300 | if (signal_pending(current)) {
|
| 301 | err = -ERESTARTSYS;
|
| 302 | goto out;
|
| 303 | }
|
| 304 | }
|
| 305 | out:
|
| 306 | memzero_explicit(buffer, sizeof(buffer));
|
| 307 | return ret ? : err;
|
| 308 |
|
| 309 | out_unlock_reading:
|
| 310 | mutex_unlock(&reading_mutex);
|
| 311 | out_put:
|
| 312 | put_rng(rng);
|
| 313 | goto out;
|
| 314 | }
|
| 315 |
|
| 316 | static const struct file_operations rng_chrdev_ops = {
|
| 317 | .owner = THIS_MODULE,
|
| 318 | .open = rng_dev_open,
|
| 319 | .read = rng_dev_read,
|
| 320 | .llseek = noop_llseek,
|
| 321 | };
|
| 322 |
|
| 323 | static const struct attribute_group *rng_dev_groups[];
|
| 324 |
|
| 325 | static struct miscdevice rng_miscdev = {
|
| 326 | .minor = HWRNG_MINOR,
|
| 327 | .name = RNG_MODULE_NAME,
|
| 328 | .nodename = "hwrng",
|
| 329 | .fops = &rng_chrdev_ops,
|
| 330 | .groups = rng_dev_groups,
|
| 331 | };
|
| 332 |
|
| 333 | static int enable_best_rng(void)
|
| 334 | {
|
| 335 | struct hwrng *rng, *cur_rng, *new_rng = NULL;
|
| 336 | int ret = -ENODEV;
|
| 337 |
|
| 338 | BUG_ON(!mutex_is_locked(&rng_mutex));
|
| 339 |
|
| 340 |
|
| 341 | if (list_empty(&rng_list)) {
|
| 342 | drop_current_rng();
|
| 343 | cur_rng_set_by_user = 0;
|
| 344 | return 0;
|
| 345 | }
|
| 346 |
|
| 347 |
|
| 348 | list_for_each_entry(rng, &rng_list, list) {
|
| 349 | if (!new_rng || rng->quality > new_rng->quality)
|
| 350 | new_rng = rng;
|
| 351 | }
|
| 352 |
|
| 353 | cur_rng = rcu_dereference_protected(current_rng,
|
| 354 | lockdep_is_held(&rng_mutex));
|
| 355 | ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng));
|
| 356 | if (!ret)
|
| 357 | cur_rng_set_by_user = 0;
|
| 358 |
|
| 359 | return ret;
|
| 360 | }
|
| 361 |
|
| 362 | static ssize_t rng_current_store(struct device *dev,
|
| 363 | struct device_attribute *attr,
|
| 364 | const char *buf, size_t len)
|
| 365 | {
|
| 366 | int err;
|
| 367 | struct hwrng *rng, *new_rng;
|
| 368 |
|
| 369 | err = mutex_lock_interruptible(&rng_mutex);
|
| 370 | if (err)
|
| 371 | return -ERESTARTSYS;
|
| 372 |
|
| 373 | if (sysfs_streq(buf, "")) {
|
| 374 | err = enable_best_rng();
|
| 375 | } else if (sysfs_streq(buf, "none")) {
|
| 376 | cur_rng_set_by_user = 1;
|
| 377 | drop_current_rng();
|
| 378 | } else {
|
| 379 | list_for_each_entry(rng, &rng_list, list) {
|
| 380 | if (sysfs_streq(rng->name, buf)) {
|
| 381 | err = set_current_rng(rng);
|
| 382 | if (!err)
|
| 383 | cur_rng_set_by_user = 1;
|
| 384 | break;
|
| 385 | }
|
| 386 | }
|
| 387 | }
|
| 388 | new_rng = get_current_rng_nolock();
|
| 389 | mutex_unlock(&rng_mutex);
|
| 390 |
|
| 391 | if (new_rng)
|
| 392 | put_rng(new_rng);
|
| 393 |
|
| 394 | return err ? : len;
|
| 395 | }
|
| 396 |
|
| 397 | static ssize_t rng_current_show(struct device *dev,
|
| 398 | struct device_attribute *attr,
|
| 399 | char *buf)
|
| 400 | {
|
| 401 | ssize_t ret;
|
| 402 | struct hwrng *rng;
|
| 403 |
|
| 404 | rng = get_current_rng();
|
| 405 |
|
| 406 | ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none");
|
| 407 | put_rng(rng);
|
| 408 |
|
| 409 | return ret;
|
| 410 | }
|
| 411 |
|
| 412 | static ssize_t rng_available_show(struct device *dev,
|
| 413 | struct device_attribute *attr,
|
| 414 | char *buf)
|
| 415 | {
|
| 416 | struct hwrng *rng;
|
| 417 | int len = 0;
|
| 418 |
|
| 419 | if (mutex_lock_interruptible(&rng_mutex))
|
| 420 | return -ERESTARTSYS;
|
| 421 | list_for_each_entry(rng, &rng_list, list)
|
| 422 | len += sysfs_emit_at(buf, len, "%s ", rng->name);
|
| 423 | len += sysfs_emit_at(buf, len, "none\n");
|
| 424 | mutex_unlock(&rng_mutex);
|
| 425 |
|
| 426 | return len;
|
| 427 | }
|
| 428 |
|
| 429 | static ssize_t rng_selected_show(struct device *dev,
|
| 430 | struct device_attribute *attr,
|
| 431 | char *buf)
|
| 432 | {
|
| 433 | return sysfs_emit(buf, "%d\n", cur_rng_set_by_user);
|
| 434 | }
|
| 435 |
|
| 436 | static ssize_t rng_quality_show(struct device *dev,
|
| 437 | struct device_attribute *attr,
|
| 438 | char *buf)
|
| 439 | {
|
| 440 | ssize_t ret;
|
| 441 | struct hwrng *rng;
|
| 442 |
|
| 443 | rng = get_current_rng();
|
| 444 |
|
| 445 | if (!rng)
|
| 446 | return -ENODEV;
|
| 447 |
|
| 448 | ret = sysfs_emit(buf, "%hu\n", rng->quality);
|
| 449 | put_rng(rng);
|
| 450 |
|
| 451 | return ret;
|
| 452 | }
|
| 453 |
|
| 454 | static ssize_t rng_quality_store(struct device *dev,
|
| 455 | struct device_attribute *attr,
|
| 456 | const char *buf, size_t len)
|
| 457 | {
|
| 458 | struct hwrng *rng;
|
| 459 | u16 quality;
|
| 460 | int ret = -EINVAL;
|
| 461 |
|
| 462 | if (len < 2)
|
| 463 | return -EINVAL;
|
| 464 |
|
| 465 | ret = mutex_lock_interruptible(&rng_mutex);
|
| 466 | if (ret)
|
| 467 | return -ERESTARTSYS;
|
| 468 |
|
| 469 | ret = kstrtou16(buf, 0, &quality);
|
| 470 | if (ret || quality > 1024) {
|
| 471 | ret = -EINVAL;
|
| 472 | goto out;
|
| 473 | }
|
| 474 |
|
| 475 | rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex));
|
| 476 | if (!rng) {
|
| 477 | ret = -ENODEV;
|
| 478 | goto out;
|
| 479 | }
|
| 480 |
|
| 481 | rng->quality = quality;
|
| 482 | current_quality = quality;
|
| 483 |
|
| 484 |
|
| 485 | ret = enable_best_rng();
|
| 486 |
|
| 487 | out:
|
| 488 | mutex_unlock(&rng_mutex);
|
| 489 | return ret ? ret : len;
|
| 490 | }
|
| 491 |
|
| 492 | static DEVICE_ATTR_RW(rng_current);
|
| 493 | static DEVICE_ATTR_RO(rng_available);
|
| 494 | static DEVICE_ATTR_RO(rng_selected);
|
| 495 | static DEVICE_ATTR_RW(rng_quality);
|
| 496 |
|
| 497 | static struct attribute *rng_dev_attrs[] = {
|
| 498 | &dev_attr_rng_current.attr,
|
| 499 | &dev_attr_rng_available.attr,
|
| 500 | &dev_attr_rng_selected.attr,
|
| 501 | &dev_attr_rng_quality.attr,
|
| 502 | NULL
|
| 503 | };
|
| 504 |
|
| 505 | ATTRIBUTE_GROUPS(rng_dev);
|
| 506 |
|
| 507 | static void hwrng_start_hwrng_fillfn(void)
|
| 508 | {
|
| 509 | lockdep_assert_held(&rng_mutex);
|
| 510 |
|
| 511 | |
| 512 | * PM notifier stopped the hwrng_fillfn kthread, prevent userspace to
|
| 513 | * restart it until kernel freezes threads.
|
| 514 |
|
| 515 | if (hwrng_fillfn_stopped)
|
| 516 | return;
|
| 517 |
|
| 518 | if (!hwrng_fill) {
|
| 519 | hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
|
| 520 | if (IS_ERR(hwrng_fill)) {
|
| 521 | pr_err("hwrng_fill thread creation failed\n");
|
| 522 | hwrng_fill = NULL;
|
| 523 | }
|
| 524 | }
|
| 525 | }
|
| 526 |
|
| 527 | static void hwrng_stop_hwrng_fillfn(void)
|
| 528 | {
|
| 529 | lockdep_assert_held(&rng_mutex);
|
| 530 |
|
| 531 | if (hwrng_fill) {
|
| 532 | kthread_stop(hwrng_fill);
|
| 533 | hwrng_fill = NULL;
|
| 534 | }
|
| 535 | }
|
| 536 |
|
| 537 | static int hwrng_fillfn(void *unused)
|
| 538 | {
|
| 539 | size_t entropy, entropy_credit = 0;
|
| 540 | long rc;
|
| 541 |
|
| 542 | while (!kthread_should_stop()) {
|
| 543 | unsigned short quality;
|
| 544 | struct hwrng *rng;
|
| 545 |
|
| 546 | rng = get_current_rng();
|
| 547 | if (!rng) {
|
| 548 | |
| 549 | * Keep the task_struct alive until kthread_stop()
|
| 550 | * is called to avoid UAF in drop_current_rng().
|
| 551 |
|
| 552 | while (!kthread_should_stop()) {
|
| 553 | set_current_state(TASK_INTERRUPTIBLE);
|
| 554 | if (!kthread_should_stop())
|
| 555 | schedule();
|
| 556 | }
|
| 557 | set_current_state(TASK_RUNNING);
|
| 558 | break;
|
| 559 | }
|
| 560 |
|
| 561 | mutex_lock(&reading_mutex);
|
| 562 | rc = rng_get_data(rng, rng_fillbuf, rng_buffer_size(), true);
|
| 563 | if (current_quality != rng->quality)
|
| 564 | rng->quality = current_quality;
|
| 565 | quality = rng->quality;
|
| 566 | mutex_unlock(&reading_mutex);
|
| 567 |
|
| 568 | if (rc <= 0)
|
| 569 | hwrng_msleep(rng, 10000);
|
| 570 |
|
| 571 | put_rng(rng);
|
| 572 |
|
| 573 | if (rc <= 0)
|
| 574 | continue;
|
| 575 |
|
| 576 | |
| 577 | * keep track of the remainder for the next iteration
|
| 578 |
|
| 579 | entropy = rc * quality * 8 + entropy_credit;
|
| 580 | if ((entropy >> 10) == 0)
|
| 581 | entropy_credit = entropy;
|
| 582 |
|
| 583 |
|
| 584 | add_hwgenerator_randomness((void *)rng_fillbuf, rc,
|
| 585 | entropy >> 10, true);
|
| 586 | }
|
| 587 | return 0;
|
| 588 | }
|
| 589 |
|
| 590 | static int hwrng_pm_notifier(struct notifier_block *nb, unsigned long action,
|
| 591 | void *data)
|
| 592 | {
|
| 593 | switch (action) {
|
| 594 | case PM_SUSPEND_PREPARE:
|
| 595 | case PM_HIBERNATION_PREPARE:
|
| 596 | case PM_RESTORE_PREPARE:
|
| 597 | mutex_lock(&rng_mutex);
|
| 598 | hwrng_stop_hwrng_fillfn();
|
| 599 | hwrng_fillfn_stopped = true;
|
| 600 | mutex_unlock(&rng_mutex);
|
| 601 | break;
|
| 602 |
|
| 603 | case PM_POST_SUSPEND:
|
| 604 | case PM_POST_HIBERNATION:
|
| 605 | case PM_POST_RESTORE:
|
| 606 | mutex_lock(&rng_mutex);
|
| 607 | hwrng_fillfn_stopped = false;
|
| 608 | if (rcu_access_pointer(current_rng))
|
| 609 | hwrng_start_hwrng_fillfn();
|
| 610 | mutex_unlock(&rng_mutex);
|
| 611 | break;
|
| 612 | }
|
| 613 |
|
| 614 | return NOTIFY_DONE;
|
| 615 | }
|
| 616 |
|
| 617 | static struct notifier_block hwrng_pm_nb = {
|
| 618 | .notifier_call = hwrng_pm_notifier,
|
| 619 | };
|
| 620 |
|
| 621 | int hwrng_register(struct hwrng *rng)
|
| 622 | {
|
| 623 | int err = -EINVAL;
|
| 624 | struct hwrng *cur_rng, *tmp;
|
| 625 |
|
| 626 | if (!rng->name || (!rng->data_read && !rng->read))
|
| 627 | goto out;
|
| 628 |
|
| 629 | mutex_lock(&rng_mutex);
|
| 630 |
|
| 631 |
|
| 632 | err = -EEXIST;
|
| 633 | list_for_each_entry(tmp, &rng_list, list) {
|
| 634 | if (strcmp(tmp->name, rng->name) == 0)
|
| 635 | goto out_unlock;
|
| 636 | }
|
| 637 | list_add_tail(&rng->list, &rng_list);
|
| 638 |
|
| 639 | INIT_WORK(&rng->cleanup_work, cleanup_rng_work);
|
| 640 | init_completion(&rng->cleanup_done);
|
| 641 | complete(&rng->cleanup_done);
|
| 642 | init_completion(&rng->dying);
|
| 643 |
|
| 644 |
|
| 645 | rng->quality = min3(default_quality, 1024, rng->quality ?: 1024);
|
| 646 |
|
| 647 | if (!cur_rng_set_by_user) {
|
| 648 | cur_rng = rcu_dereference_protected(current_rng,
|
| 649 | lockdep_is_held(&rng_mutex));
|
| 650 | if (!cur_rng || rng->quality > cur_rng->quality) {
|
| 651 | |
| 652 | * Set new rng as current as the new rng source
|
| 653 | * provides better entropy quality and was not
|
| 654 | * chosen by userspace.
|
| 655 |
|
| 656 | err = set_current_rng(rng);
|
| 657 | if (err)
|
| 658 | goto out_list_del;
|
| 659 | }
|
| 660 | }
|
| 661 | mutex_unlock(&rng_mutex);
|
| 662 | return 0;
|
| 663 | out_list_del:
|
| 664 | list_del_init(&rng->list);
|
| 665 | out_unlock:
|
| 666 | mutex_unlock(&rng_mutex);
|
| 667 | out:
|
| 668 | return err;
|
| 669 | }
|
| 670 | EXPORT_SYMBOL_GPL(hwrng_register);
|
| 671 |
|
| 672 | void hwrng_unregister(struct hwrng *rng)
|
| 673 | {
|
| 674 | struct hwrng *cur_rng;
|
| 675 | int err;
|
| 676 |
|
| 677 | mutex_lock(&rng_mutex);
|
| 678 |
|
| 679 | list_del(&rng->list);
|
| 680 | complete_all(&rng->dying);
|
| 681 |
|
| 682 | cur_rng = rcu_dereference_protected(current_rng,
|
| 683 | lockdep_is_held(&rng_mutex));
|
| 684 | if (cur_rng == rng) {
|
| 685 | err = enable_best_rng();
|
| 686 | if (err) {
|
| 687 | drop_current_rng();
|
| 688 | cur_rng_set_by_user = 0;
|
| 689 | }
|
| 690 | }
|
| 691 |
|
| 692 | mutex_unlock(&rng_mutex);
|
| 693 | wait_for_completion(&rng->cleanup_done);
|
| 694 | }
|
| 695 | EXPORT_SYMBOL_GPL(hwrng_unregister);
|
| 696 |
|
| 697 | static void devm_hwrng_release(struct device *dev, void *res)
|
| 698 | {
|
| 699 | hwrng_unregister(*(struct hwrng **)res);
|
| 700 | }
|
| 701 |
|
| 702 | static int devm_hwrng_match(struct device *dev, void *res, void *data)
|
| 703 | {
|
| 704 | struct hwrng **r = res;
|
| 705 |
|
| 706 | if (WARN_ON(!r || !*r))
|
| 707 | return 0;
|
| 708 |
|
| 709 | return *r == data;
|
| 710 | }
|
| 711 |
|
| 712 | int devm_hwrng_register(struct device *dev, struct hwrng *rng)
|
| 713 | {
|
| 714 | struct hwrng **ptr;
|
| 715 | int error;
|
| 716 |
|
| 717 | ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL);
|
| 718 | if (!ptr)
|
| 719 | return -ENOMEM;
|
| 720 |
|
| 721 | error = hwrng_register(rng);
|
| 722 | if (error) {
|
| 723 | devres_free(ptr);
|
| 724 | return error;
|
| 725 | }
|
| 726 |
|
| 727 | *ptr = rng;
|
| 728 | devres_add(dev, ptr);
|
| 729 | return 0;
|
| 730 | }
|
| 731 | EXPORT_SYMBOL_GPL(devm_hwrng_register);
|
| 732 |
|
| 733 | void devm_hwrng_unregister(struct device *dev, struct hwrng *rng)
|
| 734 | {
|
| 735 | devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng);
|
| 736 | }
|
| 737 | EXPORT_SYMBOL_GPL(devm_hwrng_unregister);
|
| 738 |
|
| 739 | long hwrng_msleep(struct hwrng *rng, unsigned int msecs)
|
| 740 | {
|
| 741 | unsigned long timeout = msecs_to_jiffies(msecs) + 1;
|
| 742 |
|
| 743 | return wait_for_completion_interruptible_timeout(&rng->dying, timeout);
|
| 744 | }
|
| 745 | EXPORT_SYMBOL_GPL(hwrng_msleep);
|
| 746 |
|
| 747 | long hwrng_yield(struct hwrng *rng)
|
| 748 | {
|
| 749 | return wait_for_completion_interruptible_timeout(&rng->dying, 1);
|
| 750 | }
|
| 751 | EXPORT_SYMBOL_GPL(hwrng_yield);
|
| 752 |
|
| 753 | static int __init hwrng_modinit(void)
|
| 754 | {
|
| 755 | int ret;
|
| 756 |
|
| 757 |
|
| 758 | rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
|
| 759 | if (!rng_buffer)
|
| 760 | return -ENOMEM;
|
| 761 |
|
| 762 | rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
|
| 763 | if (!rng_fillbuf) {
|
| 764 | kfree(rng_buffer);
|
| 765 | return -ENOMEM;
|
| 766 | }
|
| 767 |
|
| 768 | ret = misc_register(&rng_miscdev);
|
| 769 | if (ret)
|
| 770 | goto misc_err;
|
| 771 |
|
| 772 | ret = register_pm_notifier(&hwrng_pm_nb);
|
| 773 | if (ret)
|
| 774 | goto pm_err;
|
| 775 |
|
| 776 | return 0;
|
| 777 |
|
| 778 | pm_err:
|
| 779 | misc_deregister(&rng_miscdev);
|
| 780 | misc_err:
|
| 781 | kfree(rng_fillbuf);
|
| 782 | kfree(rng_buffer);
|
| 783 |
|
| 784 | return ret;
|
| 785 | }
|
| 786 |
|
| 787 | static void __exit hwrng_modexit(void)
|
| 788 | {
|
| 789 | mutex_lock(&rng_mutex);
|
| 790 | WARN_ON(rcu_access_pointer(current_rng));
|
| 791 | kfree(rng_buffer);
|
| 792 | kfree(rng_fillbuf);
|
| 793 | mutex_unlock(&rng_mutex);
|
| 794 |
|
| 795 | unregister_pm_notifier(&hwrng_pm_nb);
|
| 796 |
|
| 797 | misc_deregister(&rng_miscdev);
|
| 798 | }
|
| 799 |
|
| 800 | fs_initcall(hwrng_modinit);
|
| 801 | module_exit(hwrng_modexit);
|
| 802 |
|
| 803 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
|
| 804 | MODULE_LICENSE("GPL");
|