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 | } |
