diff options
-rw-r--r-- | arch/alpha/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 4 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 4 | ||||
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | include/linux/ptrace.h | 3 | ||||
-rw-r--r-- | kernel/ptrace.c | 42 | ||||
-rw-r--r-- | mm/memory.c | 2 | ||||
-rw-r--r-- | mm/nommu.c | 2 |
11 files changed, 52 insertions, 17 deletions
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 940dfb406591..04abdec7f496 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c | |||
@@ -283,7 +283,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
283 | /* When I and D space are separate, these will need to be fixed. */ | 283 | /* When I and D space are separate, these will need to be fixed. */ |
284 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | 284 | case PTRACE_PEEKTEXT: /* read word at location addr. */ |
285 | case PTRACE_PEEKDATA: | 285 | case PTRACE_PEEKDATA: |
286 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), | 286 | copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp), |
287 | FOLL_FORCE); | 287 | FOLL_FORCE); |
288 | ret = -EIO; | 288 | ret = -EIO; |
289 | if (copied != sizeof(tmp)) | 289 | if (copied != sizeof(tmp)) |
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 8d79286ee4e8..360d99645163 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c | |||
@@ -270,7 +270,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
270 | switch (bfin_mem_access_type(addr, to_copy)) { | 270 | switch (bfin_mem_access_type(addr, to_copy)) { |
271 | case BFIN_MEM_ACCESS_CORE: | 271 | case BFIN_MEM_ACCESS_CORE: |
272 | case BFIN_MEM_ACCESS_CORE_ONLY: | 272 | case BFIN_MEM_ACCESS_CORE_ONLY: |
273 | copied = access_process_vm(child, addr, &tmp, | 273 | copied = ptrace_access_vm(child, addr, &tmp, |
274 | to_copy, FOLL_FORCE); | 274 | to_copy, FOLL_FORCE); |
275 | if (copied) | 275 | if (copied) |
276 | break; | 276 | break; |
@@ -323,7 +323,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
323 | switch (bfin_mem_access_type(addr, to_copy)) { | 323 | switch (bfin_mem_access_type(addr, to_copy)) { |
324 | case BFIN_MEM_ACCESS_CORE: | 324 | case BFIN_MEM_ACCESS_CORE: |
325 | case BFIN_MEM_ACCESS_CORE_ONLY: | 325 | case BFIN_MEM_ACCESS_CORE_ONLY: |
326 | copied = access_process_vm(child, addr, &data, | 326 | copied = ptrace_access_vm(child, addr, &data, |
327 | to_copy, | 327 | to_copy, |
328 | FOLL_FORCE | FOLL_WRITE); | 328 | FOLL_FORCE | FOLL_WRITE); |
329 | break; | 329 | break; |
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index f0df654ac6fc..fe1f9cf7b391 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c | |||
@@ -147,7 +147,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
147 | /* The trampoline page is globally mapped, no page table to traverse.*/ | 147 | /* The trampoline page is globally mapped, no page table to traverse.*/ |
148 | tmp = *(unsigned long*)addr; | 148 | tmp = *(unsigned long*)addr; |
149 | } else { | 149 | } else { |
150 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); | 150 | copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); |
151 | 151 | ||
152 | if (copied != sizeof(tmp)) | 152 | if (copied != sizeof(tmp)) |
153 | break; | 153 | break; |
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 31aa8c0f68e1..36f660da8124 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -1159,7 +1159,7 @@ arch_ptrace (struct task_struct *child, long request, | |||
1159 | case PTRACE_PEEKTEXT: | 1159 | case PTRACE_PEEKTEXT: |
1160 | case PTRACE_PEEKDATA: | 1160 | case PTRACE_PEEKDATA: |
1161 | /* read word at location addr */ | 1161 | /* read word at location addr */ |
1162 | if (access_process_vm(child, addr, &data, sizeof(data), | 1162 | if (ptrace_access_vm(child, addr, &data, sizeof(data), |
1163 | FOLL_FORCE) | 1163 | FOLL_FORCE) |
1164 | != sizeof(data)) | 1164 | != sizeof(data)) |
1165 | return -EIO; | 1165 | return -EIO; |
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 7e71a4e0281b..5fcbdcd7abd0 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c | |||
@@ -69,7 +69,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
69 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) | 69 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) |
70 | break; | 70 | break; |
71 | 71 | ||
72 | copied = access_process_vm(child, (u64)addrOthers, &tmp, | 72 | copied = ptrace_access_vm(child, (u64)addrOthers, &tmp, |
73 | sizeof(tmp), FOLL_FORCE); | 73 | sizeof(tmp), FOLL_FORCE); |
74 | if (copied != sizeof(tmp)) | 74 | if (copied != sizeof(tmp)) |
75 | break; | 75 | break; |
@@ -178,7 +178,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
178 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) | 178 | if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) |
179 | break; | 179 | break; |
180 | ret = 0; | 180 | ret = 0; |
181 | if (access_process_vm(child, (u64)addrOthers, &data, | 181 | if (ptrace_access_vm(child, (u64)addrOthers, &data, |
182 | sizeof(data), | 182 | sizeof(data), |
183 | FOLL_FORCE | FOLL_WRITE) == sizeof(data)) | 183 | FOLL_FORCE | FOLL_WRITE) == sizeof(data)) |
184 | break; | 184 | break; |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 010b7b310237..1e887f3a61a6 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -73,7 +73,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
73 | if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) | 73 | if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) |
74 | break; | 74 | break; |
75 | 75 | ||
76 | copied = access_process_vm(child, (u64)addrOthers, &tmp, | 76 | copied = ptrace_access_vm(child, (u64)addrOthers, &tmp, |
77 | sizeof(tmp), FOLL_FORCE); | 77 | sizeof(tmp), FOLL_FORCE); |
78 | if (copied != sizeof(tmp)) | 78 | if (copied != sizeof(tmp)) |
79 | break; | 79 | break; |
@@ -178,7 +178,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
178 | if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) | 178 | if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) |
179 | break; | 179 | break; |
180 | ret = 0; | 180 | ret = 0; |
181 | if (access_process_vm(child, (u64)addrOthers, &tmp, | 181 | if (ptrace_access_vm(child, (u64)addrOthers, &tmp, |
182 | sizeof(tmp), | 182 | sizeof(tmp), |
183 | FOLL_FORCE | FOLL_WRITE) == sizeof(tmp)) | 183 | FOLL_FORCE | FOLL_WRITE) == sizeof(tmp)) |
184 | break; | 184 | break; |
diff --git a/include/linux/mm.h b/include/linux/mm.h index a92c8d73aeaf..0b5b2e4df14e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -1270,6 +1270,8 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void * | |||
1270 | unsigned int gup_flags); | 1270 | unsigned int gup_flags); |
1271 | extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, | 1271 | extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, |
1272 | void *buf, int len, unsigned int gup_flags); | 1272 | void *buf, int len, unsigned int gup_flags); |
1273 | extern int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | ||
1274 | unsigned long addr, void *buf, int len, unsigned int gup_flags); | ||
1273 | 1275 | ||
1274 | long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, | 1276 | long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, |
1275 | unsigned long start, unsigned long nr_pages, | 1277 | unsigned long start, unsigned long nr_pages, |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index e13bfdf7f314..e0e539321ab9 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -8,6 +8,9 @@ | |||
8 | #include <linux/pid_namespace.h> /* For task_active_pid_ns. */ | 8 | #include <linux/pid_namespace.h> /* For task_active_pid_ns. */ |
9 | #include <uapi/linux/ptrace.h> | 9 | #include <uapi/linux/ptrace.h> |
10 | 10 | ||
11 | extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, | ||
12 | void *buf, int len, unsigned int gup_flags); | ||
13 | |||
11 | /* | 14 | /* |
12 | * Ptrace flags | 15 | * Ptrace flags |
13 | * | 16 | * |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e82c15cadd6d..49ba7c1ade9d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -27,6 +27,35 @@ | |||
27 | #include <linux/cn_proc.h> | 27 | #include <linux/cn_proc.h> |
28 | #include <linux/compat.h> | 28 | #include <linux/compat.h> |
29 | 29 | ||
30 | /* | ||
31 | * Access another process' address space via ptrace. | ||
32 | * Source/target buffer must be kernel space, | ||
33 | * Do not walk the page table directly, use get_user_pages | ||
34 | */ | ||
35 | int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, | ||
36 | void *buf, int len, unsigned int gup_flags) | ||
37 | { | ||
38 | struct mm_struct *mm; | ||
39 | int ret; | ||
40 | |||
41 | mm = get_task_mm(tsk); | ||
42 | if (!mm) | ||
43 | return 0; | ||
44 | |||
45 | if (!tsk->ptrace || | ||
46 | (current != tsk->parent) || | ||
47 | ((get_dumpable(mm) != SUID_DUMP_USER) && | ||
48 | !ptracer_capable(tsk, mm->user_ns))) { | ||
49 | mmput(mm); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); | ||
54 | mmput(mm); | ||
55 | |||
56 | return ret; | ||
57 | } | ||
58 | |||
30 | 59 | ||
31 | /* | 60 | /* |
32 | * ptrace a task: make the debugger its new parent and | 61 | * ptrace a task: make the debugger its new parent and |
@@ -535,7 +564,8 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst | |||
535 | int this_len, retval; | 564 | int this_len, retval; |
536 | 565 | ||
537 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; | 566 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; |
538 | retval = access_process_vm(tsk, src, buf, this_len, FOLL_FORCE); | 567 | retval = ptrace_access_vm(tsk, src, buf, this_len, FOLL_FORCE); |
568 | |||
539 | if (!retval) { | 569 | if (!retval) { |
540 | if (copied) | 570 | if (copied) |
541 | break; | 571 | break; |
@@ -562,7 +592,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds | |||
562 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; | 592 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; |
563 | if (copy_from_user(buf, src, this_len)) | 593 | if (copy_from_user(buf, src, this_len)) |
564 | return -EFAULT; | 594 | return -EFAULT; |
565 | retval = access_process_vm(tsk, dst, buf, this_len, | 595 | retval = ptrace_access_vm(tsk, dst, buf, this_len, |
566 | FOLL_FORCE | FOLL_WRITE); | 596 | FOLL_FORCE | FOLL_WRITE); |
567 | if (!retval) { | 597 | if (!retval) { |
568 | if (copied) | 598 | if (copied) |
@@ -1126,7 +1156,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, | |||
1126 | unsigned long tmp; | 1156 | unsigned long tmp; |
1127 | int copied; | 1157 | int copied; |
1128 | 1158 | ||
1129 | copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE); | 1159 | copied = ptrace_access_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE); |
1130 | if (copied != sizeof(tmp)) | 1160 | if (copied != sizeof(tmp)) |
1131 | return -EIO; | 1161 | return -EIO; |
1132 | return put_user(tmp, (unsigned long __user *)data); | 1162 | return put_user(tmp, (unsigned long __user *)data); |
@@ -1137,7 +1167,7 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, | |||
1137 | { | 1167 | { |
1138 | int copied; | 1168 | int copied; |
1139 | 1169 | ||
1140 | copied = access_process_vm(tsk, addr, &data, sizeof(data), | 1170 | copied = ptrace_access_vm(tsk, addr, &data, sizeof(data), |
1141 | FOLL_FORCE | FOLL_WRITE); | 1171 | FOLL_FORCE | FOLL_WRITE); |
1142 | return (copied == sizeof(data)) ? 0 : -EIO; | 1172 | return (copied == sizeof(data)) ? 0 : -EIO; |
1143 | } | 1173 | } |
@@ -1155,7 +1185,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, | |||
1155 | switch (request) { | 1185 | switch (request) { |
1156 | case PTRACE_PEEKTEXT: | 1186 | case PTRACE_PEEKTEXT: |
1157 | case PTRACE_PEEKDATA: | 1187 | case PTRACE_PEEKDATA: |
1158 | ret = access_process_vm(child, addr, &word, sizeof(word), | 1188 | ret = ptrace_access_vm(child, addr, &word, sizeof(word), |
1159 | FOLL_FORCE); | 1189 | FOLL_FORCE); |
1160 | if (ret != sizeof(word)) | 1190 | if (ret != sizeof(word)) |
1161 | ret = -EIO; | 1191 | ret = -EIO; |
@@ -1165,7 +1195,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, | |||
1165 | 1195 | ||
1166 | case PTRACE_POKETEXT: | 1196 | case PTRACE_POKETEXT: |
1167 | case PTRACE_POKEDATA: | 1197 | case PTRACE_POKEDATA: |
1168 | ret = access_process_vm(child, addr, &data, sizeof(data), | 1198 | ret = ptrace_access_vm(child, addr, &data, sizeof(data), |
1169 | FOLL_FORCE | FOLL_WRITE); | 1199 | FOLL_FORCE | FOLL_WRITE); |
1170 | ret = (ret != sizeof(data) ? -EIO : 0); | 1200 | ret = (ret != sizeof(data) ? -EIO : 0); |
1171 | break; | 1201 | break; |
diff --git a/mm/memory.c b/mm/memory.c index e18c57bdc75c..cbb1e5e5f791 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3868,7 +3868,7 @@ EXPORT_SYMBOL_GPL(generic_access_phys); | |||
3868 | * Access another process' address space as given in mm. If non-NULL, use the | 3868 | * Access another process' address space as given in mm. If non-NULL, use the |
3869 | * given task for page fault accounting. | 3869 | * given task for page fault accounting. |
3870 | */ | 3870 | */ |
3871 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | 3871 | int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, |
3872 | unsigned long addr, void *buf, int len, unsigned int gup_flags) | 3872 | unsigned long addr, void *buf, int len, unsigned int gup_flags) |
3873 | { | 3873 | { |
3874 | struct vm_area_struct *vma; | 3874 | struct vm_area_struct *vma; |
diff --git a/mm/nommu.c b/mm/nommu.c index 8b8faaf2a9e9..44265e00b701 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -1808,7 +1808,7 @@ void filemap_map_pages(struct fault_env *fe, | |||
1808 | } | 1808 | } |
1809 | EXPORT_SYMBOL(filemap_map_pages); | 1809 | EXPORT_SYMBOL(filemap_map_pages); |
1810 | 1810 | ||
1811 | static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | 1811 | int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, |
1812 | unsigned long addr, void *buf, int len, unsigned int gup_flags) | 1812 | unsigned long addr, void *buf, int len, unsigned int gup_flags) |
1813 | { | 1813 | { |
1814 | struct vm_area_struct *vma; | 1814 | struct vm_area_struct *vma; |