Commit 33e54450683c5e970ac007489d7921ba792d093c
Committed by
Herbert Xu
1 parent
ee83655512
Exists in
master
and in
7 other branches
padata: Handle empty padata cpumasks
This patch fixes a bug when the padata cpumask does not intersect with the active cpumask. In this case we get a division by zero in padata_alloc_pd and we end up with a useless padata instance. Padata can end up with an empty cpumask for two reasons: 1. A user removed the last cpu that belongs to the padata cpumask and the active cpumask. 2. The last cpu that belongs to the padata cpumask and the active cpumask goes offline. We introduce a function padata_validate_cpumask to check if the padata cpumask does intersect with the active cpumask. If the cpumasks do not intersect we mark the instance as invalid, so it can't be used. We do not allocate the cpumask dependend recources in this case. This fixes the division by zero and keeps the padate instance in a consistent state. It's not possible to trigger this bug by now because the only padata user, pcrypt uses always the possible cpumask. Reported-by: Dan Kruchinin <dkruchinin@acm.org> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Showing 1 changed file with 50 additions and 11 deletions Side-by-side Diff
kernel/padata.c
... | ... | @@ -516,12 +516,27 @@ |
516 | 516 | |
517 | 517 | synchronize_rcu(); |
518 | 518 | |
519 | - padata_flush_queues(pd_old); | |
520 | - padata_free_pd(pd_old); | |
519 | + if (pd_old) { | |
520 | + padata_flush_queues(pd_old); | |
521 | + padata_free_pd(pd_old); | |
522 | + } | |
521 | 523 | |
522 | 524 | pinst->flags &= ~PADATA_RESET; |
523 | 525 | } |
524 | 526 | |
527 | +/* If cpumask contains no active cpu, we mark the instance as invalid. */ | |
528 | +static bool padata_validate_cpumask(struct padata_instance *pinst, | |
529 | + const struct cpumask *cpumask) | |
530 | +{ | |
531 | + if (!cpumask_intersects(cpumask, cpu_active_mask)) { | |
532 | + pinst->flags |= PADATA_INVALID; | |
533 | + return false; | |
534 | + } | |
535 | + | |
536 | + pinst->flags &= ~PADATA_INVALID; | |
537 | + return true; | |
538 | +} | |
539 | + | |
525 | 540 | /** |
526 | 541 | * padata_set_cpumask - set the cpumask that padata should use |
527 | 542 | * |
528 | 543 | |
529 | 544 | |
... | ... | @@ -531,11 +546,18 @@ |
531 | 546 | int padata_set_cpumask(struct padata_instance *pinst, |
532 | 547 | cpumask_var_t cpumask) |
533 | 548 | { |
534 | - struct parallel_data *pd; | |
549 | + int valid; | |
535 | 550 | int err = 0; |
551 | + struct parallel_data *pd = NULL; | |
536 | 552 | |
537 | 553 | mutex_lock(&pinst->lock); |
538 | 554 | |
555 | + valid = padata_validate_cpumask(pinst, cpumask); | |
556 | + if (!valid) { | |
557 | + __padata_stop(pinst); | |
558 | + goto out_replace; | |
559 | + } | |
560 | + | |
539 | 561 | get_online_cpus(); |
540 | 562 | |
541 | 563 | pd = padata_alloc_pd(pinst, cpumask); |
542 | 564 | |
... | ... | @@ -544,10 +566,14 @@ |
544 | 566 | goto out; |
545 | 567 | } |
546 | 568 | |
569 | +out_replace: | |
547 | 570 | cpumask_copy(pinst->cpumask, cpumask); |
548 | 571 | |
549 | 572 | padata_replace(pinst, pd); |
550 | 573 | |
574 | + if (valid) | |
575 | + __padata_start(pinst); | |
576 | + | |
551 | 577 | out: |
552 | 578 | put_online_cpus(); |
553 | 579 | |
... | ... | @@ -567,6 +593,9 @@ |
567 | 593 | return -ENOMEM; |
568 | 594 | |
569 | 595 | padata_replace(pinst, pd); |
596 | + | |
597 | + if (padata_validate_cpumask(pinst, pinst->cpumask)) | |
598 | + __padata_start(pinst); | |
570 | 599 | } |
571 | 600 | |
572 | 601 | return 0; |
573 | 602 | |
... | ... | @@ -597,9 +626,16 @@ |
597 | 626 | |
598 | 627 | static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) |
599 | 628 | { |
600 | - struct parallel_data *pd; | |
629 | + struct parallel_data *pd = NULL; | |
601 | 630 | |
602 | 631 | if (cpumask_test_cpu(cpu, cpu_online_mask)) { |
632 | + | |
633 | + if (!padata_validate_cpumask(pinst, pinst->cpumask)) { | |
634 | + __padata_stop(pinst); | |
635 | + padata_replace(pinst, pd); | |
636 | + goto out; | |
637 | + } | |
638 | + | |
603 | 639 | pd = padata_alloc_pd(pinst, pinst->cpumask); |
604 | 640 | if (!pd) |
605 | 641 | return -ENOMEM; |
... | ... | @@ -607,6 +643,7 @@ |
607 | 643 | padata_replace(pinst, pd); |
608 | 644 | } |
609 | 645 | |
646 | +out: | |
610 | 647 | return 0; |
611 | 648 | } |
612 | 649 | |
... | ... | @@ -732,7 +769,7 @@ |
732 | 769 | struct workqueue_struct *wq) |
733 | 770 | { |
734 | 771 | struct padata_instance *pinst; |
735 | - struct parallel_data *pd; | |
772 | + struct parallel_data *pd = NULL; | |
736 | 773 | |
737 | 774 | pinst = kzalloc(sizeof(struct padata_instance), GFP_KERNEL); |
738 | 775 | if (!pinst) |
739 | 776 | |
... | ... | @@ -740,12 +777,14 @@ |
740 | 777 | |
741 | 778 | get_online_cpus(); |
742 | 779 | |
743 | - pd = padata_alloc_pd(pinst, cpumask); | |
744 | - if (!pd) | |
780 | + if (!alloc_cpumask_var(&pinst->cpumask, GFP_KERNEL)) | |
745 | 781 | goto err_free_inst; |
746 | 782 | |
747 | - if (!alloc_cpumask_var(&pinst->cpumask, GFP_KERNEL)) | |
748 | - goto err_free_pd; | |
783 | + if (padata_validate_cpumask(pinst, cpumask)) { | |
784 | + pd = padata_alloc_pd(pinst, cpumask); | |
785 | + if (!pd) | |
786 | + goto err_free_mask; | |
787 | + } | |
749 | 788 | |
750 | 789 | rcu_assign_pointer(pinst->pd, pd); |
751 | 790 | |
... | ... | @@ -767,8 +806,8 @@ |
767 | 806 | |
768 | 807 | return pinst; |
769 | 808 | |
770 | -err_free_pd: | |
771 | - padata_free_pd(pd); | |
809 | +err_free_mask: | |
810 | + free_cpumask_var(pinst->cpumask); | |
772 | 811 | err_free_inst: |
773 | 812 | kfree(pinst); |
774 | 813 | put_online_cpus(); |