diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-09 15:22:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-09 15:22:49 -0400 |
commit | e8f2b548de7ae65e17ee911e54712a3f26f69c60 (patch) | |
tree | 0b332c254088effc61d832f9e95d65861251214e /fs | |
parent | 43ecdb0d31cf63d99d060af0585bf59be7fafcb2 (diff) | |
parent | e9c5d8a562f01b211926d70443378eb14b29a676 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"A nasty bug in fs/namespace.c caught by Andrey + a couple of less
serious unpleasantness - ecryptfs misc device playing hopeless games
with try_module_get() and palinfo procfs support being... not quite
correctly done, to be polite."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
mnt: release locks on error path in do_loopback
palinfo fixes
procfs: add proc_remove_subtree()
ecryptfs: close rmmod race
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ecryptfs/miscdev.c | 14 | ||||
-rw-r--r-- | fs/namespace.c | 2 | ||||
-rw-r--r-- | fs/proc/generic.c | 119 |
3 files changed, 92 insertions, 43 deletions
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 412e6eda25f8..e4141f257495 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c | |||
@@ -80,13 +80,6 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) | |||
80 | int rc; | 80 | int rc; |
81 | 81 | ||
82 | mutex_lock(&ecryptfs_daemon_hash_mux); | 82 | mutex_lock(&ecryptfs_daemon_hash_mux); |
83 | rc = try_module_get(THIS_MODULE); | ||
84 | if (rc == 0) { | ||
85 | rc = -EIO; | ||
86 | printk(KERN_ERR "%s: Error attempting to increment module use " | ||
87 | "count; rc = [%d]\n", __func__, rc); | ||
88 | goto out_unlock_daemon_list; | ||
89 | } | ||
90 | rc = ecryptfs_find_daemon_by_euid(&daemon); | 83 | rc = ecryptfs_find_daemon_by_euid(&daemon); |
91 | if (!rc) { | 84 | if (!rc) { |
92 | rc = -EINVAL; | 85 | rc = -EINVAL; |
@@ -96,7 +89,7 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) | |||
96 | if (rc) { | 89 | if (rc) { |
97 | printk(KERN_ERR "%s: Error attempting to spawn daemon; " | 90 | printk(KERN_ERR "%s: Error attempting to spawn daemon; " |
98 | "rc = [%d]\n", __func__, rc); | 91 | "rc = [%d]\n", __func__, rc); |
99 | goto out_module_put_unlock_daemon_list; | 92 | goto out_unlock_daemon_list; |
100 | } | 93 | } |
101 | mutex_lock(&daemon->mux); | 94 | mutex_lock(&daemon->mux); |
102 | if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) { | 95 | if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) { |
@@ -108,9 +101,6 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) | |||
108 | atomic_inc(&ecryptfs_num_miscdev_opens); | 101 | atomic_inc(&ecryptfs_num_miscdev_opens); |
109 | out_unlock_daemon: | 102 | out_unlock_daemon: |
110 | mutex_unlock(&daemon->mux); | 103 | mutex_unlock(&daemon->mux); |
111 | out_module_put_unlock_daemon_list: | ||
112 | if (rc) | ||
113 | module_put(THIS_MODULE); | ||
114 | out_unlock_daemon_list: | 104 | out_unlock_daemon_list: |
115 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 105 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
116 | return rc; | 106 | return rc; |
@@ -147,7 +137,6 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) | |||
147 | "bug.\n", __func__, rc); | 137 | "bug.\n", __func__, rc); |
148 | BUG(); | 138 | BUG(); |
149 | } | 139 | } |
150 | module_put(THIS_MODULE); | ||
151 | return rc; | 140 | return rc; |
152 | } | 141 | } |
153 | 142 | ||
@@ -471,6 +460,7 @@ out_free: | |||
471 | 460 | ||
472 | 461 | ||
473 | static const struct file_operations ecryptfs_miscdev_fops = { | 462 | static const struct file_operations ecryptfs_miscdev_fops = { |
463 | .owner = THIS_MODULE, | ||
474 | .open = ecryptfs_miscdev_open, | 464 | .open = ecryptfs_miscdev_open, |
475 | .poll = ecryptfs_miscdev_poll, | 465 | .poll = ecryptfs_miscdev_poll, |
476 | .read = ecryptfs_miscdev_read, | 466 | .read = ecryptfs_miscdev_read, |
diff --git a/fs/namespace.c b/fs/namespace.c index d581e45c0a9f..341d3f564082 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1690,7 +1690,7 @@ static int do_loopback(struct path *path, const char *old_name, | |||
1690 | 1690 | ||
1691 | if (IS_ERR(mnt)) { | 1691 | if (IS_ERR(mnt)) { |
1692 | err = PTR_ERR(mnt); | 1692 | err = PTR_ERR(mnt); |
1693 | goto out; | 1693 | goto out2; |
1694 | } | 1694 | } |
1695 | 1695 | ||
1696 | err = graft_tree(mnt, path); | 1696 | err = graft_tree(mnt, path); |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 4b3b3ffb52f1..21e1a8f1659d 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -755,37 +755,8 @@ void pde_put(struct proc_dir_entry *pde) | |||
755 | free_proc_entry(pde); | 755 | free_proc_entry(pde); |
756 | } | 756 | } |
757 | 757 | ||
758 | /* | 758 | static void entry_rundown(struct proc_dir_entry *de) |
759 | * Remove a /proc entry and free it if it's not currently in use. | ||
760 | */ | ||
761 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | ||
762 | { | 759 | { |
763 | struct proc_dir_entry **p; | ||
764 | struct proc_dir_entry *de = NULL; | ||
765 | const char *fn = name; | ||
766 | unsigned int len; | ||
767 | |||
768 | spin_lock(&proc_subdir_lock); | ||
769 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
770 | spin_unlock(&proc_subdir_lock); | ||
771 | return; | ||
772 | } | ||
773 | len = strlen(fn); | ||
774 | |||
775 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
776 | if (proc_match(len, fn, *p)) { | ||
777 | de = *p; | ||
778 | *p = de->next; | ||
779 | de->next = NULL; | ||
780 | break; | ||
781 | } | ||
782 | } | ||
783 | spin_unlock(&proc_subdir_lock); | ||
784 | if (!de) { | ||
785 | WARN(1, "name '%s'\n", name); | ||
786 | return; | ||
787 | } | ||
788 | |||
789 | spin_lock(&de->pde_unload_lock); | 760 | spin_lock(&de->pde_unload_lock); |
790 | /* | 761 | /* |
791 | * Stop accepting new callers into module. If you're | 762 | * Stop accepting new callers into module. If you're |
@@ -817,6 +788,40 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
817 | spin_lock(&de->pde_unload_lock); | 788 | spin_lock(&de->pde_unload_lock); |
818 | } | 789 | } |
819 | spin_unlock(&de->pde_unload_lock); | 790 | spin_unlock(&de->pde_unload_lock); |
791 | } | ||
792 | |||
793 | /* | ||
794 | * Remove a /proc entry and free it if it's not currently in use. | ||
795 | */ | ||
796 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | ||
797 | { | ||
798 | struct proc_dir_entry **p; | ||
799 | struct proc_dir_entry *de = NULL; | ||
800 | const char *fn = name; | ||
801 | unsigned int len; | ||
802 | |||
803 | spin_lock(&proc_subdir_lock); | ||
804 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
805 | spin_unlock(&proc_subdir_lock); | ||
806 | return; | ||
807 | } | ||
808 | len = strlen(fn); | ||
809 | |||
810 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
811 | if (proc_match(len, fn, *p)) { | ||
812 | de = *p; | ||
813 | *p = de->next; | ||
814 | de->next = NULL; | ||
815 | break; | ||
816 | } | ||
817 | } | ||
818 | spin_unlock(&proc_subdir_lock); | ||
819 | if (!de) { | ||
820 | WARN(1, "name '%s'\n", name); | ||
821 | return; | ||
822 | } | ||
823 | |||
824 | entry_rundown(de); | ||
820 | 825 | ||
821 | if (S_ISDIR(de->mode)) | 826 | if (S_ISDIR(de->mode)) |
822 | parent->nlink--; | 827 | parent->nlink--; |
@@ -827,3 +832,57 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
827 | pde_put(de); | 832 | pde_put(de); |
828 | } | 833 | } |
829 | EXPORT_SYMBOL(remove_proc_entry); | 834 | EXPORT_SYMBOL(remove_proc_entry); |
835 | |||
836 | int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) | ||
837 | { | ||
838 | struct proc_dir_entry **p; | ||
839 | struct proc_dir_entry *root = NULL, *de, *next; | ||
840 | const char *fn = name; | ||
841 | unsigned int len; | ||
842 | |||
843 | spin_lock(&proc_subdir_lock); | ||
844 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
845 | spin_unlock(&proc_subdir_lock); | ||
846 | return -ENOENT; | ||
847 | } | ||
848 | len = strlen(fn); | ||
849 | |||
850 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
851 | if (proc_match(len, fn, *p)) { | ||
852 | root = *p; | ||
853 | *p = root->next; | ||
854 | root->next = NULL; | ||
855 | break; | ||
856 | } | ||
857 | } | ||
858 | if (!root) { | ||
859 | spin_unlock(&proc_subdir_lock); | ||
860 | return -ENOENT; | ||
861 | } | ||
862 | de = root; | ||
863 | while (1) { | ||
864 | next = de->subdir; | ||
865 | if (next) { | ||
866 | de->subdir = next->next; | ||
867 | next->next = NULL; | ||
868 | de = next; | ||
869 | continue; | ||
870 | } | ||
871 | spin_unlock(&proc_subdir_lock); | ||
872 | |||
873 | entry_rundown(de); | ||
874 | next = de->parent; | ||
875 | if (S_ISDIR(de->mode)) | ||
876 | next->nlink--; | ||
877 | de->nlink = 0; | ||
878 | if (de == root) | ||
879 | break; | ||
880 | pde_put(de); | ||
881 | |||
882 | spin_lock(&proc_subdir_lock); | ||
883 | de = next; | ||
884 | } | ||
885 | pde_put(root); | ||
886 | return 0; | ||
887 | } | ||
888 | EXPORT_SYMBOL(remove_proc_subtree); | ||