diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2008-01-02 09:09:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-01-02 16:13:27 -0500 |
commit | 831830b5a2b5d413407adf380ef62fe17d6fcbf2 (patch) | |
tree | b08f54f15374b5b98b0b3bea20a1d2ea8d1f50e0 | |
parent | ac40532ef0b8649e6f7f83859ea0de1c4ed08a19 (diff) |
restrict reading from /proc/<pid>/maps to those who share ->mm or can ptrace pid
Contents of /proc/*/maps is sensitive and may become sensitive after
open() (e.g. if target originally shares our ->mm and later does exec
on suid-root binary).
Check at read() (actually, ->start() of iterator) time that mm_struct
we'd grabbed and locked is
- still the ->mm of target
- equal to reader's ->mm or the target is ptracable by reader.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/proc/base.c | 20 | ||||
-rw-r--r-- | fs/proc/internal.h | 2 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 3 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 4 | ||||
-rw-r--r-- | include/linux/ptrace.h | 1 | ||||
-rw-r--r-- | kernel/ptrace.c | 4 |
6 files changed, 27 insertions, 7 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 02a63ac04178..7411bfb0b7cc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -202,6 +202,26 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
202 | (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ | 202 | (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ |
203 | security_ptrace(current,task) == 0)) | 203 | security_ptrace(current,task) == 0)) |
204 | 204 | ||
205 | struct mm_struct *mm_for_maps(struct task_struct *task) | ||
206 | { | ||
207 | struct mm_struct *mm = get_task_mm(task); | ||
208 | if (!mm) | ||
209 | return NULL; | ||
210 | down_read(&mm->mmap_sem); | ||
211 | task_lock(task); | ||
212 | if (task->mm != mm) | ||
213 | goto out; | ||
214 | if (task->mm != current->mm && __ptrace_may_attach(task) < 0) | ||
215 | goto out; | ||
216 | task_unlock(task); | ||
217 | return mm; | ||
218 | out: | ||
219 | task_unlock(task); | ||
220 | up_read(&mm->mmap_sem); | ||
221 | mmput(mm); | ||
222 | return NULL; | ||
223 | } | ||
224 | |||
205 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) | 225 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) |
206 | { | 226 | { |
207 | int res = 0; | 227 | int res = 0; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 1820eb2ef762..05b3e9006262 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -27,6 +27,8 @@ struct vmalloc_info { | |||
27 | unsigned long largest_chunk; | 27 | unsigned long largest_chunk; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | extern struct mm_struct *mm_for_maps(struct task_struct *); | ||
31 | |||
30 | #ifdef CONFIG_MMU | 32 | #ifdef CONFIG_MMU |
31 | #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) | 33 | #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) |
32 | extern void get_vmalloc_info(struct vmalloc_info *vmi); | 34 | extern void get_vmalloc_info(struct vmalloc_info *vmi); |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c24d81a5a040..8043a3eab52c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -397,12 +397,11 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
397 | if (!priv->task) | 397 | if (!priv->task) |
398 | return NULL; | 398 | return NULL; |
399 | 399 | ||
400 | mm = get_task_mm(priv->task); | 400 | mm = mm_for_maps(priv->task); |
401 | if (!mm) | 401 | if (!mm) |
402 | return NULL; | 402 | return NULL; |
403 | 403 | ||
404 | priv->tail_vma = tail_vma = get_gate_vma(priv->task); | 404 | priv->tail_vma = tail_vma = get_gate_vma(priv->task); |
405 | down_read(&mm->mmap_sem); | ||
406 | 405 | ||
407 | /* Start with last addr hint */ | 406 | /* Start with last addr hint */ |
408 | if (last_addr && (vma = find_vma(mm, last_addr))) { | 407 | if (last_addr && (vma = find_vma(mm, last_addr))) { |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index d8b8c7183c24..1932c2ca3457 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -165,15 +165,13 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
165 | if (!priv->task) | 165 | if (!priv->task) |
166 | return NULL; | 166 | return NULL; |
167 | 167 | ||
168 | mm = get_task_mm(priv->task); | 168 | mm = mm_for_maps(priv->task); |
169 | if (!mm) { | 169 | if (!mm) { |
170 | put_task_struct(priv->task); | 170 | put_task_struct(priv->task); |
171 | priv->task = NULL; | 171 | priv->task = NULL; |
172 | return NULL; | 172 | return NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | down_read(&mm->mmap_sem); | ||
176 | |||
177 | /* start from the Nth VMA */ | 175 | /* start from the Nth VMA */ |
178 | for (vml = mm->context.vmlist; vml; vml = vml->next) | 176 | for (vml = mm->context.vmlist; vml; vml = vml->next) |
179 | if (n-- == 0) | 177 | if (n-- == 0) |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index ae8146abd746..3ea5750a0f7e 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -97,6 +97,7 @@ extern void __ptrace_link(struct task_struct *child, | |||
97 | extern void __ptrace_unlink(struct task_struct *child); | 97 | extern void __ptrace_unlink(struct task_struct *child); |
98 | extern void ptrace_untrace(struct task_struct *child); | 98 | extern void ptrace_untrace(struct task_struct *child); |
99 | extern int ptrace_may_attach(struct task_struct *task); | 99 | extern int ptrace_may_attach(struct task_struct *task); |
100 | extern int __ptrace_may_attach(struct task_struct *task); | ||
100 | 101 | ||
101 | static inline void ptrace_link(struct task_struct *child, | 102 | static inline void ptrace_link(struct task_struct *child, |
102 | struct task_struct *new_parent) | 103 | struct task_struct *new_parent) |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 7c76f2ffaeaa..0c65d306f412 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -120,7 +120,7 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
120 | return ret; | 120 | return ret; |
121 | } | 121 | } |
122 | 122 | ||
123 | static int may_attach(struct task_struct *task) | 123 | int __ptrace_may_attach(struct task_struct *task) |
124 | { | 124 | { |
125 | /* May we inspect the given task? | 125 | /* May we inspect the given task? |
126 | * This check is used both for attaching with ptrace | 126 | * This check is used both for attaching with ptrace |
@@ -154,7 +154,7 @@ int ptrace_may_attach(struct task_struct *task) | |||
154 | { | 154 | { |
155 | int err; | 155 | int err; |
156 | task_lock(task); | 156 | task_lock(task); |
157 | err = may_attach(task); | 157 | err = __ptrace_may_attach(task); |
158 | task_unlock(task); | 158 | task_unlock(task); |
159 | return !err; | 159 | return !err; |
160 | } | 160 | } |