aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2009-03-28 19:21:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-28 20:30:00 -0400
commit7c2c7d993044cddc5010f6f429b100c63bc7dffb (patch)
treeb92a6daf7c11f9a53de6fed07512fe02cd5b4a68 /fs/proc/base.c
parente426b64c412aaa3e9eb3e4b261dc5be0d5a83e78 (diff)
fix setuid sometimes wouldn't
check_unsafe_exec() also notes whether the fs_struct is being shared by more threads than will get killed by the exec, and if so sets LSM_UNSAFE_SHARE to make bprm_set_creds() careful about euid. But /proc/<pid>/cwd and /proc/<pid>/root lookups make transient use of get_fs_struct(), which also raises that sharing count. This might occasionally cause a setuid program not to change euid, in the same way as happened with files->count (check_unsafe_exec also looks at sighand->count, but /proc doesn't raise that one). We'd prefer exec not to unshare fs_struct: so fix this in procfs, replacing get_fs_struct() by get_fs_path(), which does path_get while still holding task_lock, instead of raising fs->count. Signed-off-by: Hugh Dickins <hugh@veritas.com> Cc: stable@kernel.org ___ fs/proc/base.c | 50 +++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c50
1 files changed, 16 insertions, 34 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index aef6d55b7de6..e0afd326b688 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -146,15 +146,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
146 return count; 146 return count;
147} 147}
148 148
149static struct fs_struct *get_fs_struct(struct task_struct *task) 149static int get_fs_path(struct task_struct *task, struct path *path, bool root)
150{ 150{
151 struct fs_struct *fs; 151 struct fs_struct *fs;
152 int result = -ENOENT;
153
152 task_lock(task); 154 task_lock(task);
153 fs = task->fs; 155 fs = task->fs;
154 if(fs) 156 if (fs) {
155 atomic_inc(&fs->count); 157 read_lock(&fs->lock);
158 *path = root ? fs->root : fs->pwd;
159 path_get(path);
160 read_unlock(&fs->lock);
161 result = 0;
162 }
156 task_unlock(task); 163 task_unlock(task);
157 return fs; 164 return result;
158} 165}
159 166
160static int get_nr_threads(struct task_struct *tsk) 167static int get_nr_threads(struct task_struct *tsk)
@@ -172,42 +179,24 @@ static int get_nr_threads(struct task_struct *tsk)
172static int proc_cwd_link(struct inode *inode, struct path *path) 179static int proc_cwd_link(struct inode *inode, struct path *path)
173{ 180{
174 struct task_struct *task = get_proc_task(inode); 181 struct task_struct *task = get_proc_task(inode);
175 struct fs_struct *fs = NULL;
176 int result = -ENOENT; 182 int result = -ENOENT;
177 183
178 if (task) { 184 if (task) {
179 fs = get_fs_struct(task); 185 result = get_fs_path(task, path, 0);
180 put_task_struct(task); 186 put_task_struct(task);
181 } 187 }
182 if (fs) {
183 read_lock(&fs->lock);
184 *path = fs->pwd;
185 path_get(&fs->pwd);
186 read_unlock(&fs->lock);
187 result = 0;
188 put_fs_struct(fs);
189 }
190 return result; 188 return result;
191} 189}
192 190
193static int proc_root_link(struct inode *inode, struct path *path) 191static int proc_root_link(struct inode *inode, struct path *path)
194{ 192{
195 struct task_struct *task = get_proc_task(inode); 193 struct task_struct *task = get_proc_task(inode);
196 struct fs_struct *fs = NULL;
197 int result = -ENOENT; 194 int result = -ENOENT;
198 195
199 if (task) { 196 if (task) {
200 fs = get_fs_struct(task); 197 result = get_fs_path(task, path, 1);
201 put_task_struct(task); 198 put_task_struct(task);
202 } 199 }
203 if (fs) {
204 read_lock(&fs->lock);
205 *path = fs->root;
206 path_get(&fs->root);
207 read_unlock(&fs->lock);
208 result = 0;
209 put_fs_struct(fs);
210 }
211 return result; 200 return result;
212} 201}
213 202
@@ -596,7 +585,6 @@ static int mounts_open_common(struct inode *inode, struct file *file,
596 struct task_struct *task = get_proc_task(inode); 585 struct task_struct *task = get_proc_task(inode);
597 struct nsproxy *nsp; 586 struct nsproxy *nsp;
598 struct mnt_namespace *ns = NULL; 587 struct mnt_namespace *ns = NULL;
599 struct fs_struct *fs = NULL;
600 struct path root; 588 struct path root;
601 struct proc_mounts *p; 589 struct proc_mounts *p;
602 int ret = -EINVAL; 590 int ret = -EINVAL;
@@ -610,22 +598,16 @@ static int mounts_open_common(struct inode *inode, struct file *file,
610 get_mnt_ns(ns); 598 get_mnt_ns(ns);
611 } 599 }
612 rcu_read_unlock(); 600 rcu_read_unlock();
613 if (ns) 601 if (ns && get_fs_path(task, &root, 1) == 0)
614 fs = get_fs_struct(task); 602 ret = 0;
615 put_task_struct(task); 603 put_task_struct(task);
616 } 604 }
617 605
618 if (!ns) 606 if (!ns)
619 goto err; 607 goto err;
620 if (!fs) 608 if (ret)
621 goto err_put_ns; 609 goto err_put_ns;
622 610
623 read_lock(&fs->lock);
624 root = fs->root;
625 path_get(&root);
626 read_unlock(&fs->lock);
627 put_fs_struct(fs);
628
629 ret = -ENOMEM; 611 ret = -ENOMEM;
630 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); 612 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
631 if (!p) 613 if (!p)