diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 23:51:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 23:51:42 -0400 |
commit | b81a618dcd3ea99de292dbe624f41ca68f464376 (patch) | |
tree | c5fbe44f944da9d7dc0c224116be77094d379c8a | |
parent | 2f284c846331fa44be1300a3c2c3e85800268a00 (diff) | |
parent | a9712bc12c40c172e393f85a9b2ba8db4bf59509 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
deal with races in /proc/*/{syscall,stack,personality}
proc: enable writing to /proc/pid/mem
proc: make check_mem_permission() return an mm_struct on success
proc: hold cred_guard_mutex in check_mem_permission()
proc: disable mem_write after exec
mm: implement access_remote_vm
mm: factor out main logic of access_process_vm
mm: use mm_struct to resolve gate vma's in __get_user_pages
mm: arch: rename in_gate_area_no_task to in_gate_area_no_mm
mm: arch: make in_gate_area take an mm_struct instead of a task_struct
mm: arch: make get_gate_vma take an mm_struct instead of a task_struct
x86: mark associated mm when running a task in 32 bit compatibility mode
x86: add context tag to mark mm when running a task in 32-bit compatibility mode
auxv: require the target to be tracable (or yourself)
close race in /proc/*/environ
report errors in /proc/*/*map* sanely
pagemap: close races with suid execve
make sessionid permissions in /proc/*/task/* match those in /proc/*
fix leaks in path_lookupat()
Fix up trivial conflicts in fs/proc/base.c
-rw-r--r-- | arch/powerpc/kernel/vdso.c | 6 | ||||
-rw-r--r-- | arch/s390/kernel/vdso.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/vsyscall/vsyscall.c | 6 | ||||
-rw-r--r-- | arch/x86/ia32/ia32_aout.c | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/mmu.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 8 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 16 | ||||
-rw-r--r-- | arch/x86/vdso/vdso32-setup.c | 15 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 7 | ||||
-rw-r--r-- | fs/proc/base.c | 181 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 23 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 6 | ||||
-rw-r--r-- | include/linux/mm.h | 12 | ||||
-rw-r--r-- | kernel/kallsyms.c | 4 | ||||
-rw-r--r-- | mm/memory.c | 73 | ||||
-rw-r--r-- | mm/mlock.c | 4 | ||||
-rw-r--r-- | mm/nommu.c | 2 |
18 files changed, 244 insertions, 134 deletions
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index fd8728729abc..142ab1008c3b 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c | |||
@@ -820,17 +820,17 @@ static int __init vdso_init(void) | |||
820 | } | 820 | } |
821 | arch_initcall(vdso_init); | 821 | arch_initcall(vdso_init); |
822 | 822 | ||
823 | int in_gate_area_no_task(unsigned long addr) | 823 | int in_gate_area_no_mm(unsigned long addr) |
824 | { | 824 | { |
825 | return 0; | 825 | return 0; |
826 | } | 826 | } |
827 | 827 | ||
828 | int in_gate_area(struct task_struct *task, unsigned long addr) | 828 | int in_gate_area(struct mm_struct *mm, unsigned long addr) |
829 | { | 829 | { |
830 | return 0; | 830 | return 0; |
831 | } | 831 | } |
832 | 832 | ||
833 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 833 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
834 | { | 834 | { |
835 | return NULL; | 835 | return NULL; |
836 | } | 836 | } |
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index f438d74dedbd..d73630b4fe1d 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c | |||
@@ -337,17 +337,17 @@ static int __init vdso_init(void) | |||
337 | } | 337 | } |
338 | arch_initcall(vdso_init); | 338 | arch_initcall(vdso_init); |
339 | 339 | ||
340 | int in_gate_area_no_task(unsigned long addr) | 340 | int in_gate_area_no_mm(unsigned long addr) |
341 | { | 341 | { |
342 | return 0; | 342 | return 0; |
343 | } | 343 | } |
344 | 344 | ||
345 | int in_gate_area(struct task_struct *task, unsigned long addr) | 345 | int in_gate_area(struct mm_struct *mm, unsigned long addr) |
346 | { | 346 | { |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 350 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
351 | { | 351 | { |
352 | return NULL; | 352 | return NULL; |
353 | } | 353 | } |
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index 242117cbad67..1d6d51a1ce79 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c | |||
@@ -94,17 +94,17 @@ const char *arch_vma_name(struct vm_area_struct *vma) | |||
94 | return NULL; | 94 | return NULL; |
95 | } | 95 | } |
96 | 96 | ||
97 | struct vm_area_struct *get_gate_vma(struct task_struct *task) | 97 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
98 | { | 98 | { |
99 | return NULL; | 99 | return NULL; |
100 | } | 100 | } |
101 | 101 | ||
102 | int in_gate_area(struct task_struct *task, unsigned long address) | 102 | int in_gate_area(struct mm_struct *mm, unsigned long address) |
103 | { | 103 | { |
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | int in_gate_area_no_task(unsigned long address) | 107 | int in_gate_area_no_mm(unsigned long address) |
108 | { | 108 | { |
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 2d93bdbc9ac0..fd843877e841 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c | |||
@@ -298,6 +298,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
298 | /* OK, This is the point of no return */ | 298 | /* OK, This is the point of no return */ |
299 | set_personality(PER_LINUX); | 299 | set_personality(PER_LINUX); |
300 | set_thread_flag(TIF_IA32); | 300 | set_thread_flag(TIF_IA32); |
301 | current->mm->context.ia32_compat = 1; | ||
301 | 302 | ||
302 | setup_new_exec(bprm); | 303 | setup_new_exec(bprm); |
303 | 304 | ||
diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 80a1dee5bea5..aeff3e89b222 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h | |||
@@ -13,6 +13,12 @@ typedef struct { | |||
13 | int size; | 13 | int size; |
14 | struct mutex lock; | 14 | struct mutex lock; |
15 | void *vdso; | 15 | void *vdso; |
16 | |||
17 | #ifdef CONFIG_X86_64 | ||
18 | /* True if mm supports a task running in 32 bit compatibility mode. */ | ||
19 | unsigned short ia32_compat; | ||
20 | #endif | ||
21 | |||
16 | } mm_context_t; | 22 | } mm_context_t; |
17 | 23 | ||
18 | #ifdef CONFIG_SMP | 24 | #ifdef CONFIG_SMP |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index bd387e8f73b4..6c9dd922ac0d 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -501,6 +501,10 @@ void set_personality_64bit(void) | |||
501 | /* Make sure to be in 64bit mode */ | 501 | /* Make sure to be in 64bit mode */ |
502 | clear_thread_flag(TIF_IA32); | 502 | clear_thread_flag(TIF_IA32); |
503 | 503 | ||
504 | /* Ensure the corresponding mm is not marked. */ | ||
505 | if (current->mm) | ||
506 | current->mm->context.ia32_compat = 0; | ||
507 | |||
504 | /* TBD: overwrites user setup. Should have two bits. | 508 | /* TBD: overwrites user setup. Should have two bits. |
505 | But 64bit processes have always behaved this way, | 509 | But 64bit processes have always behaved this way, |
506 | so it's not too bad. The main problem is just that | 510 | so it's not too bad. The main problem is just that |
@@ -516,6 +520,10 @@ void set_personality_ia32(void) | |||
516 | set_thread_flag(TIF_IA32); | 520 | set_thread_flag(TIF_IA32); |
517 | current->personality |= force_personality32; | 521 | current->personality |= force_personality32; |
518 | 522 | ||
523 | /* Mark the associated mm as containing 32-bit tasks. */ | ||
524 | if (current->mm) | ||
525 | current->mm->context.ia32_compat = 1; | ||
526 | |||
519 | /* Prepare the first "return" to user space */ | 527 | /* Prepare the first "return" to user space */ |
520 | current_thread_info()->status |= TS_COMPAT; | 528 | current_thread_info()->status |= TS_COMPAT; |
521 | } | 529 | } |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 2362b646178e..794233587287 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -862,18 +862,18 @@ static struct vm_area_struct gate_vma = { | |||
862 | .vm_flags = VM_READ | VM_EXEC | 862 | .vm_flags = VM_READ | VM_EXEC |
863 | }; | 863 | }; |
864 | 864 | ||
865 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 865 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
866 | { | 866 | { |
867 | #ifdef CONFIG_IA32_EMULATION | 867 | #ifdef CONFIG_IA32_EMULATION |
868 | if (test_tsk_thread_flag(tsk, TIF_IA32)) | 868 | if (!mm || mm->context.ia32_compat) |
869 | return NULL; | 869 | return NULL; |
870 | #endif | 870 | #endif |
871 | return &gate_vma; | 871 | return &gate_vma; |
872 | } | 872 | } |
873 | 873 | ||
874 | int in_gate_area(struct task_struct *task, unsigned long addr) | 874 | int in_gate_area(struct mm_struct *mm, unsigned long addr) |
875 | { | 875 | { |
876 | struct vm_area_struct *vma = get_gate_vma(task); | 876 | struct vm_area_struct *vma = get_gate_vma(mm); |
877 | 877 | ||
878 | if (!vma) | 878 | if (!vma) |
879 | return 0; | 879 | return 0; |
@@ -882,11 +882,11 @@ int in_gate_area(struct task_struct *task, unsigned long addr) | |||
882 | } | 882 | } |
883 | 883 | ||
884 | /* | 884 | /* |
885 | * Use this when you have no reliable task/vma, typically from interrupt | 885 | * Use this when you have no reliable mm, typically from interrupt |
886 | * context. It is less reliable than using the task's vma and may give | 886 | * context. It is less reliable than using a task's mm and may give |
887 | * false positives: | 887 | * false positives. |
888 | */ | 888 | */ |
889 | int in_gate_area_no_task(unsigned long addr) | 889 | int in_gate_area_no_mm(unsigned long addr) |
890 | { | 890 | { |
891 | return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); | 891 | return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); |
892 | } | 892 | } |
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 36df991985b2..468d591dde31 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c | |||
@@ -417,24 +417,25 @@ const char *arch_vma_name(struct vm_area_struct *vma) | |||
417 | return NULL; | 417 | return NULL; |
418 | } | 418 | } |
419 | 419 | ||
420 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 420 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
421 | { | 421 | { |
422 | struct mm_struct *mm = tsk->mm; | 422 | /* |
423 | 423 | * Check to see if the corresponding task was created in compat vdso | |
424 | /* Check to see if this task was created in compat vdso mode */ | 424 | * mode. |
425 | */ | ||
425 | if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE) | 426 | if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE) |
426 | return &gate_vma; | 427 | return &gate_vma; |
427 | return NULL; | 428 | return NULL; |
428 | } | 429 | } |
429 | 430 | ||
430 | int in_gate_area(struct task_struct *task, unsigned long addr) | 431 | int in_gate_area(struct mm_struct *mm, unsigned long addr) |
431 | { | 432 | { |
432 | const struct vm_area_struct *vma = get_gate_vma(task); | 433 | const struct vm_area_struct *vma = get_gate_vma(mm); |
433 | 434 | ||
434 | return vma && addr >= vma->vm_start && addr < vma->vm_end; | 435 | return vma && addr >= vma->vm_start && addr < vma->vm_end; |
435 | } | 436 | } |
436 | 437 | ||
437 | int in_gate_area_no_task(unsigned long addr) | 438 | int in_gate_area_no_mm(unsigned long addr) |
438 | { | 439 | { |
439 | return 0; | 440 | return 0; |
440 | } | 441 | } |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b2fae009a4b7..f34078d702d3 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1906,7 +1906,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1906 | segs = current->mm->map_count; | 1906 | segs = current->mm->map_count; |
1907 | segs += elf_core_extra_phdrs(); | 1907 | segs += elf_core_extra_phdrs(); |
1908 | 1908 | ||
1909 | gate_vma = get_gate_vma(current); | 1909 | gate_vma = get_gate_vma(current->mm); |
1910 | if (gate_vma != NULL) | 1910 | if (gate_vma != NULL) |
1911 | segs++; | 1911 | segs++; |
1912 | 1912 | ||
diff --git a/fs/namei.c b/fs/namei.c index fc858b1124c2..d0066e17d45d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1650,13 +1650,16 @@ static int path_lookupat(int dfd, const char *name, | |||
1650 | err = -ECHILD; | 1650 | err = -ECHILD; |
1651 | } | 1651 | } |
1652 | 1652 | ||
1653 | if (!err) | 1653 | if (!err) { |
1654 | err = handle_reval_path(nd); | 1654 | err = handle_reval_path(nd); |
1655 | if (err) | ||
1656 | path_put(&nd->path); | ||
1657 | } | ||
1655 | 1658 | ||
1656 | if (!err && nd->flags & LOOKUP_DIRECTORY) { | 1659 | if (!err && nd->flags & LOOKUP_DIRECTORY) { |
1657 | if (!nd->inode->i_op->lookup) { | 1660 | if (!nd->inode->i_op->lookup) { |
1658 | path_put(&nd->path); | 1661 | path_put(&nd->path); |
1659 | return -ENOTDIR; | 1662 | err = -ENOTDIR; |
1660 | } | 1663 | } |
1661 | } | 1664 | } |
1662 | 1665 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index daba13653256..5a670c11aeac 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -191,17 +191,20 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
191 | return result; | 191 | return result; |
192 | } | 192 | } |
193 | 193 | ||
194 | /* | 194 | static struct mm_struct *__check_mem_permission(struct task_struct *task) |
195 | * Return zero if current may access user memory in @task, -error if not. | ||
196 | */ | ||
197 | static int check_mem_permission(struct task_struct *task) | ||
198 | { | 195 | { |
196 | struct mm_struct *mm; | ||
197 | |||
198 | mm = get_task_mm(task); | ||
199 | if (!mm) | ||
200 | return ERR_PTR(-EINVAL); | ||
201 | |||
199 | /* | 202 | /* |
200 | * A task can always look at itself, in case it chooses | 203 | * A task can always look at itself, in case it chooses |
201 | * to use system calls instead of load instructions. | 204 | * to use system calls instead of load instructions. |
202 | */ | 205 | */ |
203 | if (task == current) | 206 | if (task == current) |
204 | return 0; | 207 | return mm; |
205 | 208 | ||
206 | /* | 209 | /* |
207 | * If current is actively ptrace'ing, and would also be | 210 | * If current is actively ptrace'ing, and would also be |
@@ -213,27 +216,53 @@ static int check_mem_permission(struct task_struct *task) | |||
213 | match = (tracehook_tracer_task(task) == current); | 216 | match = (tracehook_tracer_task(task) == current); |
214 | rcu_read_unlock(); | 217 | rcu_read_unlock(); |
215 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) | 218 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) |
216 | return 0; | 219 | return mm; |
217 | } | 220 | } |
218 | 221 | ||
219 | /* | 222 | /* |
220 | * Noone else is allowed. | 223 | * Noone else is allowed. |
221 | */ | 224 | */ |
222 | return -EPERM; | 225 | mmput(mm); |
226 | return ERR_PTR(-EPERM); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * If current may access user memory in @task return a reference to the | ||
231 | * corresponding mm, otherwise ERR_PTR. | ||
232 | */ | ||
233 | static struct mm_struct *check_mem_permission(struct task_struct *task) | ||
234 | { | ||
235 | struct mm_struct *mm; | ||
236 | int err; | ||
237 | |||
238 | /* | ||
239 | * Avoid racing if task exec's as we might get a new mm but validate | ||
240 | * against old credentials. | ||
241 | */ | ||
242 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
243 | if (err) | ||
244 | return ERR_PTR(err); | ||
245 | |||
246 | mm = __check_mem_permission(task); | ||
247 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
248 | |||
249 | return mm; | ||
223 | } | 250 | } |
224 | 251 | ||
225 | struct mm_struct *mm_for_maps(struct task_struct *task) | 252 | struct mm_struct *mm_for_maps(struct task_struct *task) |
226 | { | 253 | { |
227 | struct mm_struct *mm; | 254 | struct mm_struct *mm; |
255 | int err; | ||
228 | 256 | ||
229 | if (mutex_lock_killable(&task->signal->cred_guard_mutex)) | 257 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); |
230 | return NULL; | 258 | if (err) |
259 | return ERR_PTR(err); | ||
231 | 260 | ||
232 | mm = get_task_mm(task); | 261 | mm = get_task_mm(task); |
233 | if (mm && mm != current->mm && | 262 | if (mm && mm != current->mm && |
234 | !ptrace_may_access(task, PTRACE_MODE_READ)) { | 263 | !ptrace_may_access(task, PTRACE_MODE_READ)) { |
235 | mmput(mm); | 264 | mmput(mm); |
236 | mm = NULL; | 265 | mm = ERR_PTR(-EACCES); |
237 | } | 266 | } |
238 | mutex_unlock(&task->signal->cred_guard_mutex); | 267 | mutex_unlock(&task->signal->cred_guard_mutex); |
239 | 268 | ||
@@ -279,9 +308,9 @@ out: | |||
279 | 308 | ||
280 | static int proc_pid_auxv(struct task_struct *task, char *buffer) | 309 | static int proc_pid_auxv(struct task_struct *task, char *buffer) |
281 | { | 310 | { |
282 | int res = 0; | 311 | struct mm_struct *mm = mm_for_maps(task); |
283 | struct mm_struct *mm = get_task_mm(task); | 312 | int res = PTR_ERR(mm); |
284 | if (mm) { | 313 | if (mm && !IS_ERR(mm)) { |
285 | unsigned int nwords = 0; | 314 | unsigned int nwords = 0; |
286 | do { | 315 | do { |
287 | nwords += 2; | 316 | nwords += 2; |
@@ -318,6 +347,23 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) | |||
318 | } | 347 | } |
319 | #endif /* CONFIG_KALLSYMS */ | 348 | #endif /* CONFIG_KALLSYMS */ |
320 | 349 | ||
350 | static int lock_trace(struct task_struct *task) | ||
351 | { | ||
352 | int err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
353 | if (err) | ||
354 | return err; | ||
355 | if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { | ||
356 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
357 | return -EPERM; | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static void unlock_trace(struct task_struct *task) | ||
363 | { | ||
364 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
365 | } | ||
366 | |||
321 | #ifdef CONFIG_STACKTRACE | 367 | #ifdef CONFIG_STACKTRACE |
322 | 368 | ||
323 | #define MAX_STACK_TRACE_DEPTH 64 | 369 | #define MAX_STACK_TRACE_DEPTH 64 |
@@ -327,6 +373,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
327 | { | 373 | { |
328 | struct stack_trace trace; | 374 | struct stack_trace trace; |
329 | unsigned long *entries; | 375 | unsigned long *entries; |
376 | int err; | ||
330 | int i; | 377 | int i; |
331 | 378 | ||
332 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); | 379 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); |
@@ -337,15 +384,20 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
337 | trace.max_entries = MAX_STACK_TRACE_DEPTH; | 384 | trace.max_entries = MAX_STACK_TRACE_DEPTH; |
338 | trace.entries = entries; | 385 | trace.entries = entries; |
339 | trace.skip = 0; | 386 | trace.skip = 0; |
340 | save_stack_trace_tsk(task, &trace); | ||
341 | 387 | ||
342 | for (i = 0; i < trace.nr_entries; i++) { | 388 | err = lock_trace(task); |
343 | seq_printf(m, "[<%pK>] %pS\n", | 389 | if (!err) { |
344 | (void *)entries[i], (void *)entries[i]); | 390 | save_stack_trace_tsk(task, &trace); |
391 | |||
392 | for (i = 0; i < trace.nr_entries; i++) { | ||
393 | seq_printf(m, "[<%pK>] %pS\n", | ||
394 | (void *)entries[i], (void *)entries[i]); | ||
395 | } | ||
396 | unlock_trace(task); | ||
345 | } | 397 | } |
346 | kfree(entries); | 398 | kfree(entries); |
347 | 399 | ||
348 | return 0; | 400 | return err; |
349 | } | 401 | } |
350 | #endif | 402 | #endif |
351 | 403 | ||
@@ -508,18 +560,22 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer) | |||
508 | { | 560 | { |
509 | long nr; | 561 | long nr; |
510 | unsigned long args[6], sp, pc; | 562 | unsigned long args[6], sp, pc; |
563 | int res = lock_trace(task); | ||
564 | if (res) | ||
565 | return res; | ||
511 | 566 | ||
512 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) | 567 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) |
513 | return sprintf(buffer, "running\n"); | 568 | res = sprintf(buffer, "running\n"); |
514 | 569 | else if (nr < 0) | |
515 | if (nr < 0) | 570 | res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); |
516 | return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); | 571 | else |
517 | 572 | res = sprintf(buffer, | |
518 | return sprintf(buffer, | ||
519 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | 573 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", |
520 | nr, | 574 | nr, |
521 | args[0], args[1], args[2], args[3], args[4], args[5], | 575 | args[0], args[1], args[2], args[3], args[4], args[5], |
522 | sp, pc); | 576 | sp, pc); |
577 | unlock_trace(task); | ||
578 | return res; | ||
523 | } | 579 | } |
524 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ | 580 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ |
525 | 581 | ||
@@ -775,19 +831,14 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
775 | if (!task) | 831 | if (!task) |
776 | goto out_no_task; | 832 | goto out_no_task; |
777 | 833 | ||
778 | ret = check_mem_permission(task); | ||
779 | if (ret) | ||
780 | goto out; | ||
781 | |||
782 | ret = -ENOMEM; | 834 | ret = -ENOMEM; |
783 | page = (char *)__get_free_page(GFP_TEMPORARY); | 835 | page = (char *)__get_free_page(GFP_TEMPORARY); |
784 | if (!page) | 836 | if (!page) |
785 | goto out; | 837 | goto out; |
786 | 838 | ||
787 | ret = 0; | 839 | mm = check_mem_permission(task); |
788 | 840 | ret = PTR_ERR(mm); | |
789 | mm = get_task_mm(task); | 841 | if (IS_ERR(mm)) |
790 | if (!mm) | ||
791 | goto out_free; | 842 | goto out_free; |
792 | 843 | ||
793 | ret = -EIO; | 844 | ret = -EIO; |
@@ -801,8 +852,8 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
801 | int this_len, retval; | 852 | int this_len, retval; |
802 | 853 | ||
803 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 854 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
804 | retval = access_process_vm(task, src, page, this_len, 0); | 855 | retval = access_remote_vm(mm, src, page, this_len, 0); |
805 | if (!retval || check_mem_permission(task)) { | 856 | if (!retval) { |
806 | if (!ret) | 857 | if (!ret) |
807 | ret = -EIO; | 858 | ret = -EIO; |
808 | break; | 859 | break; |
@@ -830,10 +881,6 @@ out_no_task: | |||
830 | return ret; | 881 | return ret; |
831 | } | 882 | } |
832 | 883 | ||
833 | #define mem_write NULL | ||
834 | |||
835 | #ifndef mem_write | ||
836 | /* This is a security hazard */ | ||
837 | static ssize_t mem_write(struct file * file, const char __user *buf, | 884 | static ssize_t mem_write(struct file * file, const char __user *buf, |
838 | size_t count, loff_t *ppos) | 885 | size_t count, loff_t *ppos) |
839 | { | 886 | { |
@@ -841,19 +888,25 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
841 | char *page; | 888 | char *page; |
842 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 889 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
843 | unsigned long dst = *ppos; | 890 | unsigned long dst = *ppos; |
891 | struct mm_struct *mm; | ||
844 | 892 | ||
845 | copied = -ESRCH; | 893 | copied = -ESRCH; |
846 | if (!task) | 894 | if (!task) |
847 | goto out_no_task; | 895 | goto out_no_task; |
848 | 896 | ||
849 | copied = check_mem_permission(task); | 897 | mm = check_mem_permission(task); |
850 | if (copied) | 898 | copied = PTR_ERR(mm); |
851 | goto out; | 899 | if (IS_ERR(mm)) |
900 | goto out_task; | ||
901 | |||
902 | copied = -EIO; | ||
903 | if (file->private_data != (void *)((long)current->self_exec_id)) | ||
904 | goto out_mm; | ||
852 | 905 | ||
853 | copied = -ENOMEM; | 906 | copied = -ENOMEM; |
854 | page = (char *)__get_free_page(GFP_TEMPORARY); | 907 | page = (char *)__get_free_page(GFP_TEMPORARY); |
855 | if (!page) | 908 | if (!page) |
856 | goto out; | 909 | goto out_mm; |
857 | 910 | ||
858 | copied = 0; | 911 | copied = 0; |
859 | while (count > 0) { | 912 | while (count > 0) { |
@@ -864,7 +917,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
864 | copied = -EFAULT; | 917 | copied = -EFAULT; |
865 | break; | 918 | break; |
866 | } | 919 | } |
867 | retval = access_process_vm(task, dst, page, this_len, 1); | 920 | retval = access_remote_vm(mm, dst, page, this_len, 1); |
868 | if (!retval) { | 921 | if (!retval) { |
869 | if (!copied) | 922 | if (!copied) |
870 | copied = -EIO; | 923 | copied = -EIO; |
@@ -877,12 +930,13 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
877 | } | 930 | } |
878 | *ppos = dst; | 931 | *ppos = dst; |
879 | free_page((unsigned long) page); | 932 | free_page((unsigned long) page); |
880 | out: | 933 | out_mm: |
934 | mmput(mm); | ||
935 | out_task: | ||
881 | put_task_struct(task); | 936 | put_task_struct(task); |
882 | out_no_task: | 937 | out_no_task: |
883 | return copied; | 938 | return copied; |
884 | } | 939 | } |
885 | #endif | ||
886 | 940 | ||
887 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) | 941 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) |
888 | { | 942 | { |
@@ -919,21 +973,18 @@ static ssize_t environ_read(struct file *file, char __user *buf, | |||
919 | if (!task) | 973 | if (!task) |
920 | goto out_no_task; | 974 | goto out_no_task; |
921 | 975 | ||
922 | ret = -EPERM; | ||
923 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
924 | goto out; | ||
925 | |||
926 | ret = -ENOMEM; | 976 | ret = -ENOMEM; |
927 | page = (char *)__get_free_page(GFP_TEMPORARY); | 977 | page = (char *)__get_free_page(GFP_TEMPORARY); |
928 | if (!page) | 978 | if (!page) |
929 | goto out; | 979 | goto out; |
930 | 980 | ||
931 | ret = 0; | ||
932 | 981 | ||
933 | mm = get_task_mm(task); | 982 | mm = mm_for_maps(task); |
934 | if (!mm) | 983 | ret = PTR_ERR(mm); |
984 | if (!mm || IS_ERR(mm)) | ||
935 | goto out_free; | 985 | goto out_free; |
936 | 986 | ||
987 | ret = 0; | ||
937 | while (count > 0) { | 988 | while (count > 0) { |
938 | int this_len, retval, max_len; | 989 | int this_len, retval, max_len; |
939 | 990 | ||
@@ -2751,8 +2802,12 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
2751 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2802 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
2752 | struct pid *pid, struct task_struct *task) | 2803 | struct pid *pid, struct task_struct *task) |
2753 | { | 2804 | { |
2754 | seq_printf(m, "%08x\n", task->personality); | 2805 | int err = lock_trace(task); |
2755 | return 0; | 2806 | if (!err) { |
2807 | seq_printf(m, "%08x\n", task->personality); | ||
2808 | unlock_trace(task); | ||
2809 | } | ||
2810 | return err; | ||
2756 | } | 2811 | } |
2757 | 2812 | ||
2758 | /* | 2813 | /* |
@@ -2771,7 +2826,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2771 | REG("environ", S_IRUSR, proc_environ_operations), | 2826 | REG("environ", S_IRUSR, proc_environ_operations), |
2772 | INF("auxv", S_IRUSR, proc_pid_auxv), | 2827 | INF("auxv", S_IRUSR, proc_pid_auxv), |
2773 | ONE("status", S_IRUGO, proc_pid_status), | 2828 | ONE("status", S_IRUGO, proc_pid_status), |
2774 | ONE("personality", S_IRUSR, proc_pid_personality), | 2829 | ONE("personality", S_IRUGO, proc_pid_personality), |
2775 | INF("limits", S_IRUGO, proc_pid_limits), | 2830 | INF("limits", S_IRUGO, proc_pid_limits), |
2776 | #ifdef CONFIG_SCHED_DEBUG | 2831 | #ifdef CONFIG_SCHED_DEBUG |
2777 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2832 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
@@ -2781,7 +2836,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2781 | #endif | 2836 | #endif |
2782 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 2837 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
2783 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2838 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2784 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2839 | INF("syscall", S_IRUGO, proc_pid_syscall), |
2785 | #endif | 2840 | #endif |
2786 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 2841 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
2787 | ONE("stat", S_IRUGO, proc_tgid_stat), | 2842 | ONE("stat", S_IRUGO, proc_tgid_stat), |
@@ -2800,7 +2855,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2800 | #ifdef CONFIG_PROC_PAGE_MONITOR | 2855 | #ifdef CONFIG_PROC_PAGE_MONITOR |
2801 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 2856 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
2802 | REG("smaps", S_IRUGO, proc_smaps_operations), | 2857 | REG("smaps", S_IRUGO, proc_smaps_operations), |
2803 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 2858 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
2804 | #endif | 2859 | #endif |
2805 | #ifdef CONFIG_SECURITY | 2860 | #ifdef CONFIG_SECURITY |
2806 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 2861 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -2809,7 +2864,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2809 | INF("wchan", S_IRUGO, proc_pid_wchan), | 2864 | INF("wchan", S_IRUGO, proc_pid_wchan), |
2810 | #endif | 2865 | #endif |
2811 | #ifdef CONFIG_STACKTRACE | 2866 | #ifdef CONFIG_STACKTRACE |
2812 | ONE("stack", S_IRUSR, proc_pid_stack), | 2867 | ONE("stack", S_IRUGO, proc_pid_stack), |
2813 | #endif | 2868 | #endif |
2814 | #ifdef CONFIG_SCHEDSTATS | 2869 | #ifdef CONFIG_SCHEDSTATS |
2815 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 2870 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3111,14 +3166,14 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3111 | REG("environ", S_IRUSR, proc_environ_operations), | 3166 | REG("environ", S_IRUSR, proc_environ_operations), |
3112 | INF("auxv", S_IRUSR, proc_pid_auxv), | 3167 | INF("auxv", S_IRUSR, proc_pid_auxv), |
3113 | ONE("status", S_IRUGO, proc_pid_status), | 3168 | ONE("status", S_IRUGO, proc_pid_status), |
3114 | ONE("personality", S_IRUSR, proc_pid_personality), | 3169 | ONE("personality", S_IRUGO, proc_pid_personality), |
3115 | INF("limits", S_IRUGO, proc_pid_limits), | 3170 | INF("limits", S_IRUGO, proc_pid_limits), |
3116 | #ifdef CONFIG_SCHED_DEBUG | 3171 | #ifdef CONFIG_SCHED_DEBUG |
3117 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 3172 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
3118 | #endif | 3173 | #endif |
3119 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 3174 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
3120 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 3175 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
3121 | INF("syscall", S_IRUSR, proc_pid_syscall), | 3176 | INF("syscall", S_IRUGO, proc_pid_syscall), |
3122 | #endif | 3177 | #endif |
3123 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 3178 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
3124 | ONE("stat", S_IRUGO, proc_tid_stat), | 3179 | ONE("stat", S_IRUGO, proc_tid_stat), |
@@ -3136,7 +3191,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3136 | #ifdef CONFIG_PROC_PAGE_MONITOR | 3191 | #ifdef CONFIG_PROC_PAGE_MONITOR |
3137 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 3192 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
3138 | REG("smaps", S_IRUGO, proc_smaps_operations), | 3193 | REG("smaps", S_IRUGO, proc_smaps_operations), |
3139 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 3194 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
3140 | #endif | 3195 | #endif |
3141 | #ifdef CONFIG_SECURITY | 3196 | #ifdef CONFIG_SECURITY |
3142 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 3197 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -3145,7 +3200,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3145 | INF("wchan", S_IRUGO, proc_pid_wchan), | 3200 | INF("wchan", S_IRUGO, proc_pid_wchan), |
3146 | #endif | 3201 | #endif |
3147 | #ifdef CONFIG_STACKTRACE | 3202 | #ifdef CONFIG_STACKTRACE |
3148 | ONE("stack", S_IRUSR, proc_pid_stack), | 3203 | ONE("stack", S_IRUGO, proc_pid_stack), |
3149 | #endif | 3204 | #endif |
3150 | #ifdef CONFIG_SCHEDSTATS | 3205 | #ifdef CONFIG_SCHEDSTATS |
3151 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 3206 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3164,7 +3219,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3164 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), | 3219 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
3165 | #ifdef CONFIG_AUDITSYSCALL | 3220 | #ifdef CONFIG_AUDITSYSCALL |
3166 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), | 3221 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
3167 | REG("sessionid", S_IRUSR, proc_sessionid_operations), | 3222 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
3168 | #endif | 3223 | #endif |
3169 | #ifdef CONFIG_FAULT_INJECTION | 3224 | #ifdef CONFIG_FAULT_INJECTION |
3170 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 3225 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 636f1a1fdf87..7c708a418acc 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -121,14 +121,14 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
121 | 121 | ||
122 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 122 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
123 | if (!priv->task) | 123 | if (!priv->task) |
124 | return NULL; | 124 | return ERR_PTR(-ESRCH); |
125 | 125 | ||
126 | mm = mm_for_maps(priv->task); | 126 | mm = mm_for_maps(priv->task); |
127 | if (!mm) | 127 | if (!mm || IS_ERR(mm)) |
128 | return NULL; | 128 | return mm; |
129 | down_read(&mm->mmap_sem); | 129 | down_read(&mm->mmap_sem); |
130 | 130 | ||
131 | tail_vma = get_gate_vma(priv->task); | 131 | tail_vma = get_gate_vma(priv->task->mm); |
132 | priv->tail_vma = tail_vma; | 132 | priv->tail_vma = tail_vma; |
133 | 133 | ||
134 | /* Start with last addr hint */ | 134 | /* Start with last addr hint */ |
@@ -279,7 +279,8 @@ static int show_map(struct seq_file *m, void *v) | |||
279 | show_map_vma(m, vma); | 279 | show_map_vma(m, vma); |
280 | 280 | ||
281 | if (m->count < m->size) /* vma is copied successfully */ | 281 | if (m->count < m->size) /* vma is copied successfully */ |
282 | m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; | 282 | m->version = (vma != get_gate_vma(task->mm)) |
283 | ? vma->vm_start : 0; | ||
283 | return 0; | 284 | return 0; |
284 | } | 285 | } |
285 | 286 | ||
@@ -468,7 +469,8 @@ static int show_smap(struct seq_file *m, void *v) | |||
468 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); | 469 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); |
469 | 470 | ||
470 | if (m->count < m->size) /* vma is copied successfully */ | 471 | if (m->count < m->size) /* vma is copied successfully */ |
471 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | 472 | m->version = (vma != get_gate_vma(task->mm)) |
473 | ? vma->vm_start : 0; | ||
472 | return 0; | 474 | return 0; |
473 | } | 475 | } |
474 | 476 | ||
@@ -764,8 +766,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
764 | if (!task) | 766 | if (!task) |
765 | goto out; | 767 | goto out; |
766 | 768 | ||
767 | ret = -EACCES; | 769 | mm = mm_for_maps(task); |
768 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 770 | ret = PTR_ERR(mm); |
771 | if (!mm || IS_ERR(mm)) | ||
769 | goto out_task; | 772 | goto out_task; |
770 | 773 | ||
771 | ret = -EINVAL; | 774 | ret = -EINVAL; |
@@ -778,10 +781,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
778 | if (!count) | 781 | if (!count) |
779 | goto out_task; | 782 | goto out_task; |
780 | 783 | ||
781 | mm = get_task_mm(task); | ||
782 | if (!mm) | ||
783 | goto out_task; | ||
784 | |||
785 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | 784 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); |
786 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); | 785 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
787 | ret = -ENOMEM; | 786 | ret = -ENOMEM; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index b535d3e5d5f1..980de547c070 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -199,13 +199,13 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
199 | /* pin the task and mm whilst we play with them */ | 199 | /* pin the task and mm whilst we play with them */ |
200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
201 | if (!priv->task) | 201 | if (!priv->task) |
202 | return NULL; | 202 | return ERR_PTR(-ESRCH); |
203 | 203 | ||
204 | mm = mm_for_maps(priv->task); | 204 | mm = mm_for_maps(priv->task); |
205 | if (!mm) { | 205 | if (!mm || IS_ERR(mm)) { |
206 | put_task_struct(priv->task); | 206 | put_task_struct(priv->task); |
207 | priv->task = NULL; | 207 | priv->task = NULL; |
208 | return NULL; | 208 | return mm; |
209 | } | 209 | } |
210 | down_read(&mm->mmap_sem); | 210 | down_read(&mm->mmap_sem); |
211 | 211 | ||
diff --git a/include/linux/mm.h b/include/linux/mm.h index 294104e0891d..f9535b2c9558 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -982,6 +982,8 @@ static inline int handle_mm_fault(struct mm_struct *mm, | |||
982 | 982 | ||
983 | extern int make_pages_present(unsigned long addr, unsigned long end); | 983 | extern int make_pages_present(unsigned long addr, unsigned long end); |
984 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); | 984 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); |
985 | extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, | ||
986 | void *buf, int len, int write); | ||
985 | 987 | ||
986 | int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | 988 | int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, |
987 | unsigned long start, int len, unsigned int foll_flags, | 989 | unsigned long start, int len, unsigned int foll_flags, |
@@ -1592,13 +1594,13 @@ static inline bool kernel_page_present(struct page *page) { return true; } | |||
1592 | #endif /* CONFIG_HIBERNATION */ | 1594 | #endif /* CONFIG_HIBERNATION */ |
1593 | #endif | 1595 | #endif |
1594 | 1596 | ||
1595 | extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk); | 1597 | extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm); |
1596 | #ifdef __HAVE_ARCH_GATE_AREA | 1598 | #ifdef __HAVE_ARCH_GATE_AREA |
1597 | int in_gate_area_no_task(unsigned long addr); | 1599 | int in_gate_area_no_mm(unsigned long addr); |
1598 | int in_gate_area(struct task_struct *task, unsigned long addr); | 1600 | int in_gate_area(struct mm_struct *mm, unsigned long addr); |
1599 | #else | 1601 | #else |
1600 | int in_gate_area_no_task(unsigned long addr); | 1602 | int in_gate_area_no_mm(unsigned long addr); |
1601 | #define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);}) | 1603 | #define in_gate_area(mm, addr) ({(void)mm; in_gate_area_no_mm(addr);}) |
1602 | #endif /* __HAVE_ARCH_GATE_AREA */ | 1604 | #endif /* __HAVE_ARCH_GATE_AREA */ |
1603 | 1605 | ||
1604 | int drop_caches_sysctl_handler(struct ctl_table *, int, | 1606 | int drop_caches_sysctl_handler(struct ctl_table *, int, |
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 75dcca37d61a..a56aa58b9cb0 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
@@ -64,14 +64,14 @@ static inline int is_kernel_text(unsigned long addr) | |||
64 | if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) || | 64 | if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) || |
65 | arch_is_kernel_text(addr)) | 65 | arch_is_kernel_text(addr)) |
66 | return 1; | 66 | return 1; |
67 | return in_gate_area_no_task(addr); | 67 | return in_gate_area_no_mm(addr); |
68 | } | 68 | } |
69 | 69 | ||
70 | static inline int is_kernel(unsigned long addr) | 70 | static inline int is_kernel(unsigned long addr) |
71 | { | 71 | { |
72 | if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) | 72 | if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) |
73 | return 1; | 73 | return 1; |
74 | return in_gate_area_no_task(addr); | 74 | return in_gate_area_no_mm(addr); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int is_ksym_addr(unsigned long addr) | 77 | static int is_ksym_addr(unsigned long addr) |
diff --git a/mm/memory.c b/mm/memory.c index 20d5f7499ce2..51a5c23704af 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1486,9 +1486,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1486 | struct vm_area_struct *vma; | 1486 | struct vm_area_struct *vma; |
1487 | 1487 | ||
1488 | vma = find_extend_vma(mm, start); | 1488 | vma = find_extend_vma(mm, start); |
1489 | if (!vma && in_gate_area(tsk, start)) { | 1489 | if (!vma && in_gate_area(mm, start)) { |
1490 | unsigned long pg = start & PAGE_MASK; | 1490 | unsigned long pg = start & PAGE_MASK; |
1491 | struct vm_area_struct *gate_vma = get_gate_vma(tsk); | 1491 | struct vm_area_struct *gate_vma = get_gate_vma(mm); |
1492 | pgd_t *pgd; | 1492 | pgd_t *pgd; |
1493 | pud_t *pud; | 1493 | pud_t *pud; |
1494 | pmd_t *pmd; | 1494 | pmd_t *pmd; |
@@ -1591,10 +1591,13 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1591 | return i ? i : -EFAULT; | 1591 | return i ? i : -EFAULT; |
1592 | BUG(); | 1592 | BUG(); |
1593 | } | 1593 | } |
1594 | if (ret & VM_FAULT_MAJOR) | 1594 | |
1595 | tsk->maj_flt++; | 1595 | if (tsk) { |
1596 | else | 1596 | if (ret & VM_FAULT_MAJOR) |
1597 | tsk->min_flt++; | 1597 | tsk->maj_flt++; |
1598 | else | ||
1599 | tsk->min_flt++; | ||
1600 | } | ||
1598 | 1601 | ||
1599 | if (ret & VM_FAULT_RETRY) { | 1602 | if (ret & VM_FAULT_RETRY) { |
1600 | if (nonblocking) | 1603 | if (nonblocking) |
@@ -1641,7 +1644,8 @@ EXPORT_SYMBOL(__get_user_pages); | |||
1641 | 1644 | ||
1642 | /** | 1645 | /** |
1643 | * get_user_pages() - pin user pages in memory | 1646 | * get_user_pages() - pin user pages in memory |
1644 | * @tsk: task_struct of target task | 1647 | * @tsk: the task_struct to use for page fault accounting, or |
1648 | * NULL if faults are not to be recorded. | ||
1645 | * @mm: mm_struct of target mm | 1649 | * @mm: mm_struct of target mm |
1646 | * @start: starting user address | 1650 | * @start: starting user address |
1647 | * @nr_pages: number of pages from start to pin | 1651 | * @nr_pages: number of pages from start to pin |
@@ -3499,7 +3503,7 @@ static int __init gate_vma_init(void) | |||
3499 | __initcall(gate_vma_init); | 3503 | __initcall(gate_vma_init); |
3500 | #endif | 3504 | #endif |
3501 | 3505 | ||
3502 | struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | 3506 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) |
3503 | { | 3507 | { |
3504 | #ifdef AT_SYSINFO_EHDR | 3508 | #ifdef AT_SYSINFO_EHDR |
3505 | return &gate_vma; | 3509 | return &gate_vma; |
@@ -3508,7 +3512,7 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk) | |||
3508 | #endif | 3512 | #endif |
3509 | } | 3513 | } |
3510 | 3514 | ||
3511 | int in_gate_area_no_task(unsigned long addr) | 3515 | int in_gate_area_no_mm(unsigned long addr) |
3512 | { | 3516 | { |
3513 | #ifdef AT_SYSINFO_EHDR | 3517 | #ifdef AT_SYSINFO_EHDR |
3514 | if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) | 3518 | if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) |
@@ -3649,20 +3653,15 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, | |||
3649 | #endif | 3653 | #endif |
3650 | 3654 | ||
3651 | /* | 3655 | /* |
3652 | * Access another process' address space. | 3656 | * Access another process' address space as given in mm. If non-NULL, use the |
3653 | * Source/target buffer must be kernel space, | 3657 | * given task for page fault accounting. |
3654 | * Do not walk the page table directly, use get_user_pages | ||
3655 | */ | 3658 | */ |
3656 | int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | 3659 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, |
3660 | unsigned long addr, void *buf, int len, int write) | ||
3657 | { | 3661 | { |
3658 | struct mm_struct *mm; | ||
3659 | struct vm_area_struct *vma; | 3662 | struct vm_area_struct *vma; |
3660 | void *old_buf = buf; | 3663 | void *old_buf = buf; |
3661 | 3664 | ||
3662 | mm = get_task_mm(tsk); | ||
3663 | if (!mm) | ||
3664 | return 0; | ||
3665 | |||
3666 | down_read(&mm->mmap_sem); | 3665 | down_read(&mm->mmap_sem); |
3667 | /* ignore errors, just check how much was successfully transferred */ | 3666 | /* ignore errors, just check how much was successfully transferred */ |
3668 | while (len) { | 3667 | while (len) { |
@@ -3711,11 +3710,47 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in | |||
3711 | addr += bytes; | 3710 | addr += bytes; |
3712 | } | 3711 | } |
3713 | up_read(&mm->mmap_sem); | 3712 | up_read(&mm->mmap_sem); |
3714 | mmput(mm); | ||
3715 | 3713 | ||
3716 | return buf - old_buf; | 3714 | return buf - old_buf; |
3717 | } | 3715 | } |
3718 | 3716 | ||
3717 | /** | ||
3718 | * @access_remote_vm - access another process' address space | ||
3719 | * @mm: the mm_struct of the target address space | ||
3720 | * @addr: start address to access | ||
3721 | * @buf: source or destination buffer | ||
3722 | * @len: number of bytes to transfer | ||
3723 | * @write: whether the access is a write | ||
3724 | * | ||
3725 | * The caller must hold a reference on @mm. | ||
3726 | */ | ||
3727 | int access_remote_vm(struct mm_struct *mm, unsigned long addr, | ||
3728 | void *buf, int len, int write) | ||
3729 | { | ||
3730 | return __access_remote_vm(NULL, mm, addr, buf, len, write); | ||
3731 | } | ||
3732 | |||
3733 | /* | ||
3734 | * Access another process' address space. | ||
3735 | * Source/target buffer must be kernel space, | ||
3736 | * Do not walk the page table directly, use get_user_pages | ||
3737 | */ | ||
3738 | int access_process_vm(struct task_struct *tsk, unsigned long addr, | ||
3739 | void *buf, int len, int write) | ||
3740 | { | ||
3741 | struct mm_struct *mm; | ||
3742 | int ret; | ||
3743 | |||
3744 | mm = get_task_mm(tsk); | ||
3745 | if (!mm) | ||
3746 | return 0; | ||
3747 | |||
3748 | ret = __access_remote_vm(tsk, mm, addr, buf, len, write); | ||
3749 | mmput(mm); | ||
3750 | |||
3751 | return ret; | ||
3752 | } | ||
3753 | |||
3719 | /* | 3754 | /* |
3720 | * Print the name of a VMA. | 3755 | * Print the name of a VMA. |
3721 | */ | 3756 | */ |
diff --git a/mm/mlock.c b/mm/mlock.c index c3924c7f00be..2689a08c79af 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -237,7 +237,7 @@ long mlock_vma_pages_range(struct vm_area_struct *vma, | |||
237 | 237 | ||
238 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || | 238 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || |
239 | is_vm_hugetlb_page(vma) || | 239 | is_vm_hugetlb_page(vma) || |
240 | vma == get_gate_vma(current))) { | 240 | vma == get_gate_vma(current->mm))) { |
241 | 241 | ||
242 | __mlock_vma_pages_range(vma, start, end, NULL); | 242 | __mlock_vma_pages_range(vma, start, end, NULL); |
243 | 243 | ||
@@ -332,7 +332,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, | |||
332 | int lock = newflags & VM_LOCKED; | 332 | int lock = newflags & VM_LOCKED; |
333 | 333 | ||
334 | if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) || | 334 | if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) || |
335 | is_vm_hugetlb_page(vma) || vma == get_gate_vma(current)) | 335 | is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm)) |
336 | goto out; /* don't set VM_LOCKED, don't count */ | 336 | goto out; /* don't set VM_LOCKED, don't count */ |
337 | 337 | ||
338 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); | 338 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); |
diff --git a/mm/nommu.c b/mm/nommu.c index f59e1424d3db..e629143f9440 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -1963,7 +1963,7 @@ error: | |||
1963 | return -ENOMEM; | 1963 | return -ENOMEM; |
1964 | } | 1964 | } |
1965 | 1965 | ||
1966 | int in_gate_area_no_task(unsigned long addr) | 1966 | int in_gate_area_no_mm(unsigned long addr) |
1967 | { | 1967 | { |
1968 | return 0; | 1968 | return 0; |
1969 | } | 1969 | } |