Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hwrng: core - use RCU and work_struct to fix race condition

Currently, hwrng_fill is not cleared until the hwrng_fillfn() thread
exits. Since hwrng_unregister() reads hwrng_fill outside the rng_mutex
lock, a concurrent hwrng_unregister() may call kthread_stop() again on
the same task.

Additionally, if hwrng_unregister() is called immediately after
hwrng_register(), the stopped thread may have never been executed. Thus,
hwrng_fill remains dirty even after hwrng_unregister() returns. In this
case, subsequent calls to hwrng_register() will fail to start new
threads, and hwrng_unregister() will call kthread_stop() on the same
freed task. In both cases, a use-after-free occurs:

refcount_t: addition on 0; use-after-free.
WARNING: ... at lib/refcount.c:25 refcount_warn_saturate+0xec/0x1c0
Call Trace:
kthread_stop+0x181/0x360
hwrng_unregister+0x288/0x380
virtrng_remove+0xe3/0x200

This patch fixes the race by protecting the global hwrng_fill pointer
inside the rng_mutex lock, so that hwrng_fillfn() thread is stopped only
once, and calls to kthread_run() and kthread_stop() are serialized
with the lock held.

To avoid deadlock in hwrng_fillfn() while being stopped with the lock
held, we convert current_rng to RCU, so that get_current_rng() can read
current_rng without holding the lock. To remove the lock from put_rng(),
we also delay the actual cleanup into a work_struct.

Since get_current_rng() no longer returns ERR_PTR values, the IS_ERR()
checks are removed from its callers.

With hwrng_fill protected by the rng_mutex lock, hwrng_fillfn() can no
longer clear hwrng_fill itself. Therefore, if hwrng_fillfn() returns
directly after current_rng is dropped, kthread_stop() would be called on
a freed task_struct later. To fix this, hwrng_fillfn() calls schedule()
now to keep the task alive until being stopped. The kthread_stop() call
is also moved from hwrng_unregister() to drop_current_rng(), ensuring
kthread_stop() is called on all possible paths where current_rng becomes
NULL, so that the thread would not wait forever.

Fixes: be4000bc4644 ("hwrng: create filler thread")
Suggested-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Lianjie Wang <karin0.zst@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Lianjie Wang and committed by
Herbert Xu
cc2f39d6 ccb679fd

+107 -63
+105 -63
drivers/char/hw_random/core.c
··· 20 20 #include <linux/miscdevice.h> 21 21 #include <linux/module.h> 22 22 #include <linux/random.h> 23 + #include <linux/rcupdate.h> 23 24 #include <linux/sched.h> 24 25 #include <linux/sched/signal.h> 25 26 #include <linux/slab.h> 26 27 #include <linux/string.h> 27 28 #include <linux/uaccess.h> 29 + #include <linux/workqueue.h> 28 30 29 31 #define RNG_MODULE_NAME "hw_random" 30 32 31 33 #define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) 32 34 33 - static struct hwrng *current_rng; 35 + static struct hwrng __rcu *current_rng; 34 36 /* the current rng has been explicitly chosen by user via sysfs */ 35 37 static int cur_rng_set_by_user; 36 38 static struct task_struct *hwrng_fill; 37 39 /* list of registered rngs */ 38 40 static LIST_HEAD(rng_list); 39 - /* Protects rng_list and current_rng */ 41 + /* Protects rng_list, hwrng_fill and updating on current_rng */ 40 42 static DEFINE_MUTEX(rng_mutex); 41 43 /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ 42 44 static DEFINE_MUTEX(reading_mutex); ··· 66 64 return RNG_BUFFER_SIZE; 67 65 } 68 66 69 - static inline void cleanup_rng(struct kref *kref) 67 + static void cleanup_rng_work(struct work_struct *work) 70 68 { 71 - struct hwrng *rng = container_of(kref, struct hwrng, ref); 69 + struct hwrng *rng = container_of(work, struct hwrng, cleanup_work); 70 + 71 + /* 72 + * Hold rng_mutex here so we serialize in case they set_current_rng 73 + * on rng again immediately. 74 + */ 75 + mutex_lock(&rng_mutex); 76 + 77 + /* Skip if rng has been reinitialized. */ 78 + if (kref_read(&rng->ref)) { 79 + mutex_unlock(&rng_mutex); 80 + return; 81 + } 72 82 73 83 if (rng->cleanup) 74 84 rng->cleanup(rng); 75 85 76 86 complete(&rng->cleanup_done); 87 + mutex_unlock(&rng_mutex); 88 + } 89 + 90 + static inline void cleanup_rng(struct kref *kref) 91 + { 92 + struct hwrng *rng = container_of(kref, struct hwrng, ref); 93 + 94 + schedule_work(&rng->cleanup_work); 77 95 } 78 96 79 97 static int set_current_rng(struct hwrng *rng) 80 98 { 99 + struct hwrng *old_rng; 81 100 int err; 82 101 83 102 BUG_ON(!mutex_is_locked(&rng_mutex)); ··· 107 84 if (err) 108 85 return err; 109 86 110 - drop_current_rng(); 111 - current_rng = rng; 87 + old_rng = rcu_dereference_protected(current_rng, 88 + lockdep_is_held(&rng_mutex)); 89 + rcu_assign_pointer(current_rng, rng); 90 + 91 + if (old_rng) { 92 + synchronize_rcu(); 93 + kref_put(&old_rng->ref, cleanup_rng); 94 + } 112 95 113 96 /* if necessary, start hwrng thread */ 114 97 if (!hwrng_fill) { ··· 130 101 131 102 static void drop_current_rng(void) 132 103 { 133 - BUG_ON(!mutex_is_locked(&rng_mutex)); 134 - if (!current_rng) 104 + struct hwrng *rng; 105 + 106 + rng = rcu_dereference_protected(current_rng, 107 + lockdep_is_held(&rng_mutex)); 108 + if (!rng) 135 109 return; 136 110 111 + RCU_INIT_POINTER(current_rng, NULL); 112 + synchronize_rcu(); 113 + 114 + if (hwrng_fill) { 115 + kthread_stop(hwrng_fill); 116 + hwrng_fill = NULL; 117 + } 118 + 137 119 /* decrease last reference for triggering the cleanup */ 138 - kref_put(&current_rng->ref, cleanup_rng); 139 - current_rng = NULL; 120 + kref_put(&rng->ref, cleanup_rng); 140 121 } 141 122 142 - /* Returns ERR_PTR(), NULL or refcounted hwrng */ 123 + /* Returns NULL or refcounted hwrng */ 143 124 static struct hwrng *get_current_rng_nolock(void) 144 125 { 145 - if (current_rng) 146 - kref_get(&current_rng->ref); 126 + struct hwrng *rng; 147 127 148 - return current_rng; 128 + rng = rcu_dereference_protected(current_rng, 129 + lockdep_is_held(&rng_mutex)); 130 + if (rng) 131 + kref_get(&rng->ref); 132 + 133 + return rng; 149 134 } 150 135 151 136 static struct hwrng *get_current_rng(void) 152 137 { 153 138 struct hwrng *rng; 154 139 155 - if (mutex_lock_interruptible(&rng_mutex)) 156 - return ERR_PTR(-ERESTARTSYS); 140 + rcu_read_lock(); 141 + rng = rcu_dereference(current_rng); 142 + if (rng) 143 + kref_get(&rng->ref); 157 144 158 - rng = get_current_rng_nolock(); 145 + rcu_read_unlock(); 159 146 160 - mutex_unlock(&rng_mutex); 161 147 return rng; 162 148 } 163 149 164 150 static void put_rng(struct hwrng *rng) 165 151 { 166 - /* 167 - * Hold rng_mutex here so we serialize in case they set_current_rng 168 - * on rng again immediately. 169 - */ 170 - mutex_lock(&rng_mutex); 171 152 if (rng) 172 153 kref_put(&rng->ref, cleanup_rng); 173 - mutex_unlock(&rng_mutex); 174 154 } 175 155 176 156 static int hwrng_init(struct hwrng *rng) ··· 251 213 252 214 while (size) { 253 215 rng = get_current_rng(); 254 - if (IS_ERR(rng)) { 255 - err = PTR_ERR(rng); 256 - goto out; 257 - } 258 216 if (!rng) { 259 217 err = -ENODEV; 260 218 goto out; ··· 337 303 338 304 static int enable_best_rng(void) 339 305 { 340 - struct hwrng *rng, *new_rng = NULL; 306 + struct hwrng *rng, *cur_rng, *new_rng = NULL; 341 307 int ret = -ENODEV; 342 308 343 309 BUG_ON(!mutex_is_locked(&rng_mutex)); ··· 355 321 new_rng = rng; 356 322 } 357 323 358 - ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); 324 + cur_rng = rcu_dereference_protected(current_rng, 325 + lockdep_is_held(&rng_mutex)); 326 + ret = ((new_rng == cur_rng) ? 0 : set_current_rng(new_rng)); 359 327 if (!ret) 360 328 cur_rng_set_by_user = 0; 361 329 ··· 407 371 struct hwrng *rng; 408 372 409 373 rng = get_current_rng(); 410 - if (IS_ERR(rng)) 411 - return PTR_ERR(rng); 412 374 413 375 ret = sysfs_emit(buf, "%s\n", rng ? rng->name : "none"); 414 376 put_rng(rng); ··· 450 416 struct hwrng *rng; 451 417 452 418 rng = get_current_rng(); 453 - if (IS_ERR(rng)) 454 - return PTR_ERR(rng); 455 419 456 420 if (!rng) /* no need to put_rng */ 457 421 return -ENODEV; ··· 464 432 struct device_attribute *attr, 465 433 const char *buf, size_t len) 466 434 { 435 + struct hwrng *rng; 467 436 u16 quality; 468 437 int ret = -EINVAL; 469 438 ··· 481 448 goto out; 482 449 } 483 450 484 - if (!current_rng) { 451 + rng = rcu_dereference_protected(current_rng, lockdep_is_held(&rng_mutex)); 452 + if (!rng) { 485 453 ret = -ENODEV; 486 454 goto out; 487 455 } 488 456 489 - current_rng->quality = quality; 457 + rng->quality = quality; 490 458 current_quality = quality; /* obsolete */ 491 459 492 460 /* the best available RNG may have changed */ ··· 523 489 struct hwrng *rng; 524 490 525 491 rng = get_current_rng(); 526 - if (IS_ERR(rng) || !rng) 492 + if (!rng) { 493 + /* 494 + * Keep the task_struct alive until kthread_stop() 495 + * is called to avoid UAF in drop_current_rng(). 496 + */ 497 + while (!kthread_should_stop()) { 498 + set_current_state(TASK_INTERRUPTIBLE); 499 + if (!kthread_should_stop()) 500 + schedule(); 501 + } 502 + set_current_state(TASK_RUNNING); 527 503 break; 504 + } 505 + 528 506 mutex_lock(&reading_mutex); 529 507 rc = rng_get_data(rng, rng_fillbuf, 530 508 rng_buffer_size(), 1); ··· 564 518 add_hwgenerator_randomness((void *)rng_fillbuf, rc, 565 519 entropy >> 10, true); 566 520 } 567 - hwrng_fill = NULL; 568 521 return 0; 569 522 } 570 523 571 524 int hwrng_register(struct hwrng *rng) 572 525 { 573 526 int err = -EINVAL; 574 - struct hwrng *tmp; 527 + struct hwrng *cur_rng, *tmp; 575 528 576 529 if (!rng->name || (!rng->data_read && !rng->read)) 577 530 goto out; ··· 585 540 } 586 541 list_add_tail(&rng->list, &rng_list); 587 542 543 + INIT_WORK(&rng->cleanup_work, cleanup_rng_work); 588 544 init_completion(&rng->cleanup_done); 589 545 complete(&rng->cleanup_done); 590 546 init_completion(&rng->dying); ··· 593 547 /* Adjust quality field to always have a proper value */ 594 548 rng->quality = min3(default_quality, 1024, rng->quality ?: 1024); 595 549 596 - if (!cur_rng_set_by_user && 597 - (!current_rng || rng->quality > current_rng->quality)) { 598 - /* 599 - * Set new rng as current as the new rng source 600 - * provides better entropy quality and was not 601 - * chosen by userspace. 602 - */ 603 - err = set_current_rng(rng); 604 - if (err) 605 - goto out_unlock; 550 + if (!cur_rng_set_by_user) { 551 + cur_rng = rcu_dereference_protected(current_rng, 552 + lockdep_is_held(&rng_mutex)); 553 + if (!cur_rng || rng->quality > cur_rng->quality) { 554 + /* 555 + * Set new rng as current as the new rng source 556 + * provides better entropy quality and was not 557 + * chosen by userspace. 558 + */ 559 + err = set_current_rng(rng); 560 + if (err) 561 + goto out_unlock; 562 + } 606 563 } 607 564 mutex_unlock(&rng_mutex); 608 565 return 0; ··· 618 569 619 570 void hwrng_unregister(struct hwrng *rng) 620 571 { 621 - struct hwrng *new_rng; 572 + struct hwrng *cur_rng; 622 573 int err; 623 574 624 575 mutex_lock(&rng_mutex); 625 576 626 577 list_del(&rng->list); 627 578 complete_all(&rng->dying); 628 - if (current_rng == rng) { 579 + 580 + cur_rng = rcu_dereference_protected(current_rng, 581 + lockdep_is_held(&rng_mutex)); 582 + if (cur_rng == rng) { 629 583 err = enable_best_rng(); 630 584 if (err) { 631 585 drop_current_rng(); ··· 636 584 } 637 585 } 638 586 639 - new_rng = get_current_rng_nolock(); 640 - if (list_empty(&rng_list)) { 641 - mutex_unlock(&rng_mutex); 642 - if (hwrng_fill) 643 - kthread_stop(hwrng_fill); 644 - } else 645 - mutex_unlock(&rng_mutex); 646 - 647 - if (new_rng) 648 - put_rng(new_rng); 649 - 587 + mutex_unlock(&rng_mutex); 650 588 wait_for_completion(&rng->cleanup_done); 651 589 } 652 590 EXPORT_SYMBOL_GPL(hwrng_unregister); ··· 724 682 static void __exit hwrng_modexit(void) 725 683 { 726 684 mutex_lock(&rng_mutex); 727 - BUG_ON(current_rng); 685 + WARN_ON(rcu_access_pointer(current_rng)); 728 686 kfree(rng_buffer); 729 687 kfree(rng_fillbuf); 730 688 mutex_unlock(&rng_mutex);
+2
include/linux/hw_random.h
··· 15 15 #include <linux/completion.h> 16 16 #include <linux/kref.h> 17 17 #include <linux/types.h> 18 + #include <linux/workqueue_types.h> 18 19 19 20 /** 20 21 * struct hwrng - Hardware Random Number Generator driver ··· 49 48 /* internal. */ 50 49 struct list_head list; 51 50 struct kref ref; 51 + struct work_struct cleanup_work; 52 52 struct completion cleanup_done; 53 53 struct completion dying; 54 54 };