aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-10-09 18:25:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 22:25:48 -0400
commit29a40ace841cba9b661711f042d1821cdc4ad47c (patch)
treeb04f8e2de4a4fd8e19889c2adfaef02235c678ec /fs/proc
parent5381e169e78405bd54256860f151596f5a887617 (diff)
fs/proc/task_mmu.c: shift mm_access() from m_start() to proc_maps_open()
A simple test-case from Kirill Shutemov cat /proc/self/maps >/dev/null chmod +x /proc/self/net/packet exec /proc/self/net/packet makes lockdep unhappy, cat/exec take seq_file->lock + cred_guard_mutex in the opposite order. It's a false positive and probably we should not allow "chmod +x" on proc files. Still I think that we should avoid mm_access() and cred_guard_mutex in sys_read() paths, security checking should happen at open time. Besides, this doesn't even look right if the task changes its ->mm between m_stop() and m_start(). Add the new "mm_struct *mm" member into struct proc_maps_private and change proc_maps_open() to initialize it using proc_mem_open(). Change m_start() to use priv->mm if atomic_inc_not_zero(mm_users) succeeds or return NULL (eof) otherwise. The only complication is that proc_maps_open() users should additionally do mmdrop() in fop->release(), add the new proc_map_release() helper for that. Note: this is the user-visible change, if the task execs after open("maps") the new ->mm won't be visible via this file. I hope this is fine, and this matches /proc/pid/mem bahaviour. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Oleg Nesterov <oleg@redhat.com> Reported-by: "Kirill A. Shutemov" <kirill@shutemov.name> Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Acked-by: Cyrill Gorcunov <gorcunov@openvz.org> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/internal.h1
-rw-r--r--fs/proc/task_mmu.c37
2 files changed, 29 insertions, 9 deletions
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 3c685563406f..d27182854a28 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -270,6 +270,7 @@ extern int proc_remount(struct super_block *, int *, char *);
270struct proc_maps_private { 270struct proc_maps_private {
271 struct pid *pid; 271 struct pid *pid;
272 struct task_struct *task; 272 struct task_struct *task;
273 struct mm_struct *mm;
273#ifdef CONFIG_MMU 274#ifdef CONFIG_MMU
274 struct vm_area_struct *tail_vma; 275 struct vm_area_struct *tail_vma;
275#endif 276#endif
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 4d716a09d500..a1454dac7e0a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -165,9 +165,9 @@ static void *m_start(struct seq_file *m, loff_t *pos)
165 if (!priv->task) 165 if (!priv->task)
166 return ERR_PTR(-ESRCH); 166 return ERR_PTR(-ESRCH);
167 167
168 mm = mm_access(priv->task, PTRACE_MODE_READ); 168 mm = priv->mm;
169 if (!mm || IS_ERR(mm)) 169 if (!mm || !atomic_inc_not_zero(&mm->mm_users))
170 return mm; 170 return NULL;
171 down_read(&mm->mmap_sem); 171 down_read(&mm->mmap_sem);
172 172
173 tail_vma = get_gate_vma(mm); 173 tail_vma = get_gate_vma(mm);
@@ -240,9 +240,28 @@ static int proc_maps_open(struct inode *inode, struct file *file,
240 return -ENOMEM; 240 return -ENOMEM;
241 241
242 priv->pid = proc_pid(inode); 242 priv->pid = proc_pid(inode);
243 priv->mm = proc_mem_open(inode, PTRACE_MODE_READ);
244 if (IS_ERR(priv->mm)) {
245 int err = PTR_ERR(priv->mm);
246
247 seq_release_private(inode, file);
248 return err;
249 }
250
243 return 0; 251 return 0;
244} 252}
245 253
254static int proc_map_release(struct inode *inode, struct file *file)
255{
256 struct seq_file *seq = file->private_data;
257 struct proc_maps_private *priv = seq->private;
258
259 if (priv->mm)
260 mmdrop(priv->mm);
261
262 return seq_release_private(inode, file);
263}
264
246static int do_maps_open(struct inode *inode, struct file *file, 265static int do_maps_open(struct inode *inode, struct file *file,
247 const struct seq_operations *ops) 266 const struct seq_operations *ops)
248{ 267{
@@ -398,14 +417,14 @@ const struct file_operations proc_pid_maps_operations = {
398 .open = pid_maps_open, 417 .open = pid_maps_open,
399 .read = seq_read, 418 .read = seq_read,
400 .llseek = seq_lseek, 419 .llseek = seq_lseek,
401 .release = seq_release_private, 420 .release = proc_map_release,
402}; 421};
403 422
404const struct file_operations proc_tid_maps_operations = { 423const struct file_operations proc_tid_maps_operations = {
405 .open = tid_maps_open, 424 .open = tid_maps_open,
406 .read = seq_read, 425 .read = seq_read,
407 .llseek = seq_lseek, 426 .llseek = seq_lseek,
408 .release = seq_release_private, 427 .release = proc_map_release,
409}; 428};
410 429
411/* 430/*
@@ -680,14 +699,14 @@ const struct file_operations proc_pid_smaps_operations = {
680 .open = pid_smaps_open, 699 .open = pid_smaps_open,
681 .read = seq_read, 700 .read = seq_read,
682 .llseek = seq_lseek, 701 .llseek = seq_lseek,
683 .release = seq_release_private, 702 .release = proc_map_release,
684}; 703};
685 704
686const struct file_operations proc_tid_smaps_operations = { 705const struct file_operations proc_tid_smaps_operations = {
687 .open = tid_smaps_open, 706 .open = tid_smaps_open,
688 .read = seq_read, 707 .read = seq_read,
689 .llseek = seq_lseek, 708 .llseek = seq_lseek,
690 .release = seq_release_private, 709 .release = proc_map_release,
691}; 710};
692 711
693/* 712/*
@@ -1544,13 +1563,13 @@ const struct file_operations proc_pid_numa_maps_operations = {
1544 .open = pid_numa_maps_open, 1563 .open = pid_numa_maps_open,
1545 .read = seq_read, 1564 .read = seq_read,
1546 .llseek = seq_lseek, 1565 .llseek = seq_lseek,
1547 .release = seq_release_private, 1566 .release = proc_map_release,
1548}; 1567};
1549 1568
1550const struct file_operations proc_tid_numa_maps_operations = { 1569const struct file_operations proc_tid_numa_maps_operations = {
1551 .open = tid_numa_maps_open, 1570 .open = tid_numa_maps_open,
1552 .read = seq_read, 1571 .read = seq_read,
1553 .llseek = seq_lseek, 1572 .llseek = seq_lseek,
1554 .release = seq_release_private, 1573 .release = proc_map_release,
1555}; 1574};
1556#endif /* CONFIG_NUMA */ 1575#endif /* CONFIG_NUMA */