Commit 7ea600b5314529f9d1b9d6d3c41cb26fce6a7a4a
1 parent
06ae43f34b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Nest rename_lock inside vfsmount_lock
... lest we get livelocks between path_is_under() and d_path() and friends. The thing is, wrt fairness lglocks are more similar to rwsems than to rwlocks; it is possible to have thread B spin on attempt to take lock shared while thread A is already holding it shared, if B is on lower-numbered CPU than A and there's a thread C spinning on attempt to take the same lock exclusive. As the result, we need consistent ordering between vfsmount_lock (lglock) and rename_lock (seq_lock), even though everything that takes both is going to take vfsmount_lock only shared. Spotted-by: Brad Spengler <spender@grsecurity.net> Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 11 additions and 5 deletions Side-by-side Diff
fs/dcache.c
... | ... | @@ -2542,7 +2542,6 @@ |
2542 | 2542 | bool slash = false; |
2543 | 2543 | int error = 0; |
2544 | 2544 | |
2545 | - br_read_lock(&vfsmount_lock); | |
2546 | 2545 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
2547 | 2546 | struct dentry * parent; |
2548 | 2547 | |
... | ... | @@ -2572,8 +2571,6 @@ |
2572 | 2571 | if (!error && !slash) |
2573 | 2572 | error = prepend(buffer, buflen, "/", 1); |
2574 | 2573 | |
2575 | -out: | |
2576 | - br_read_unlock(&vfsmount_lock); | |
2577 | 2574 | return error; |
2578 | 2575 | |
2579 | 2576 | global_root: |
... | ... | @@ -2590,7 +2587,7 @@ |
2590 | 2587 | error = prepend(buffer, buflen, "/", 1); |
2591 | 2588 | if (!error) |
2592 | 2589 | error = is_mounted(vfsmnt) ? 1 : 2; |
2593 | - goto out; | |
2590 | + return error; | |
2594 | 2591 | } |
2595 | 2592 | |
2596 | 2593 | /** |
2597 | 2594 | |
... | ... | @@ -2617,9 +2614,11 @@ |
2617 | 2614 | int error; |
2618 | 2615 | |
2619 | 2616 | prepend(&res, &buflen, "\0", 1); |
2617 | + br_read_lock(&vfsmount_lock); | |
2620 | 2618 | write_seqlock(&rename_lock); |
2621 | 2619 | error = prepend_path(path, root, &res, &buflen); |
2622 | 2620 | write_sequnlock(&rename_lock); |
2621 | + br_read_unlock(&vfsmount_lock); | |
2623 | 2622 | |
2624 | 2623 | if (error < 0) |
2625 | 2624 | return ERR_PTR(error); |
2626 | 2625 | |
... | ... | @@ -2636,9 +2635,11 @@ |
2636 | 2635 | int error; |
2637 | 2636 | |
2638 | 2637 | prepend(&res, &buflen, "\0", 1); |
2638 | + br_read_lock(&vfsmount_lock); | |
2639 | 2639 | write_seqlock(&rename_lock); |
2640 | 2640 | error = prepend_path(path, &root, &res, &buflen); |
2641 | 2641 | write_sequnlock(&rename_lock); |
2642 | + br_read_unlock(&vfsmount_lock); | |
2642 | 2643 | |
2643 | 2644 | if (error > 1) |
2644 | 2645 | error = -EINVAL; |
2645 | 2646 | |
2646 | 2647 | |
... | ... | @@ -2702,11 +2703,13 @@ |
2702 | 2703 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
2703 | 2704 | |
2704 | 2705 | get_fs_root(current->fs, &root); |
2706 | + br_read_lock(&vfsmount_lock); | |
2705 | 2707 | write_seqlock(&rename_lock); |
2706 | 2708 | error = path_with_deleted(path, &root, &res, &buflen); |
2709 | + write_sequnlock(&rename_lock); | |
2710 | + br_read_unlock(&vfsmount_lock); | |
2707 | 2711 | if (error < 0) |
2708 | 2712 | res = ERR_PTR(error); |
2709 | - write_sequnlock(&rename_lock); | |
2710 | 2713 | path_put(&root); |
2711 | 2714 | return res; |
2712 | 2715 | } |
... | ... | @@ -2830,6 +2833,7 @@ |
2830 | 2833 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
2831 | 2834 | |
2832 | 2835 | error = -ENOENT; |
2836 | + br_read_lock(&vfsmount_lock); | |
2833 | 2837 | write_seqlock(&rename_lock); |
2834 | 2838 | if (!d_unlinked(pwd.dentry)) { |
2835 | 2839 | unsigned long len; |
... | ... | @@ -2839,6 +2843,7 @@ |
2839 | 2843 | prepend(&cwd, &buflen, "\0", 1); |
2840 | 2844 | error = prepend_path(&pwd, &root, &cwd, &buflen); |
2841 | 2845 | write_sequnlock(&rename_lock); |
2846 | + br_read_unlock(&vfsmount_lock); | |
2842 | 2847 | |
2843 | 2848 | if (error < 0) |
2844 | 2849 | goto out; |
... | ... | @@ -2859,6 +2864,7 @@ |
2859 | 2864 | } |
2860 | 2865 | } else { |
2861 | 2866 | write_sequnlock(&rename_lock); |
2867 | + br_read_unlock(&vfsmount_lock); | |
2862 | 2868 | } |
2863 | 2869 | |
2864 | 2870 | out: |