diff options
author | Lorenzo Stoakes <lstoakes@gmail.com> | 2016-10-12 20:20:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-19 11:31:25 -0400 |
commit | f307ab6dcea03f9d8e4d70508fd7d1ca57cfa7f9 (patch) | |
tree | 94a96ebae9957cf1252231a69f8904796aa2563e | |
parent | 6347e8d5bcce33fc36e651901efefbe2c93a43ef (diff) |
mm: replace access_process_vm() write parameter with gup_flags
This removes the 'write' argument from access_process_vm() and replaces
it with 'gup_flags' as use of this function previously silently implied
FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
We make this explicit as use of FOLL_FORCE can result in surprising
behaviour (and hence bugs) within the mm subsystem.
Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/alpha/kernel/ptrace.c | 9 | ||||
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 5 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/ptrace.c | 4 | ||||
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 14 | ||||
-rw-r--r-- | arch/m32r/kernel/ptrace.c | 15 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 5 | ||||
-rw-r--r-- | arch/score/kernel/ptrace.c | 10 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace_64.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/step.c | 3 | ||||
-rw-r--r-- | arch/x86/um/ptrace_32.c | 3 | ||||
-rw-r--r-- | arch/x86/um/ptrace_64.c | 3 | ||||
-rw-r--r-- | include/linux/mm.h | 3 | ||||
-rw-r--r-- | kernel/ptrace.c | 16 | ||||
-rw-r--r-- | mm/memory.c | 8 | ||||
-rw-r--r-- | mm/nommu.c | 6 | ||||
-rw-r--r-- | mm/util.c | 5 |
17 files changed, 84 insertions, 54 deletions
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index d9ee81769899..940dfb406591 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c | |||
@@ -157,14 +157,16 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data) | |||
157 | static inline int | 157 | static inline int |
158 | read_int(struct task_struct *task, unsigned long addr, int * data) | 158 | read_int(struct task_struct *task, unsigned long addr, int * data) |
159 | { | 159 | { |
160 | int copied = access_process_vm(task, addr, data, sizeof(int), 0); | 160 | int copied = access_process_vm(task, addr, data, sizeof(int), |
161 | FOLL_FORCE); | ||
161 | return (copied == sizeof(int)) ? 0 : -EIO; | 162 | return (copied == sizeof(int)) ? 0 : -EIO; |
162 | } | 163 | } |
163 | 164 | ||
164 | static inline int | 165 | static inline int |
165 | write_int(struct task_struct *task, unsigned long addr, int data) | 166 | write_int(struct task_struct *task, unsigned long addr, int data) |
166 | { | 167 | { |
167 | int copied = access_process_vm(task, addr, &data, sizeof(int), 1); | 168 | int copied = access_process_vm(task, addr, &data, sizeof(int), |
169 | FOLL_FORCE | FOLL_WRITE); | ||
168 | return (copied == sizeof(int)) ? 0 : -EIO; | 170 | return (copied == sizeof(int)) ? 0 : -EIO; |
169 | } | 171 | } |
170 | 172 | ||
@@ -281,7 +283,8 @@ long arch_ptrace(struct task_struct *child, long request, | |||
281 | /* 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. */ |
282 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | 284 | case PTRACE_PEEKTEXT: /* read word at location addr. */ |
283 | case PTRACE_PEEKDATA: | 285 | case PTRACE_PEEKDATA: |
284 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | 286 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), |
287 | FOLL_FORCE); | ||
285 | ret = -EIO; | 288 | ret = -EIO; |
286 | if (copied != sizeof(tmp)) | 289 | if (copied != sizeof(tmp)) |
287 | break; | 290 | break; |
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 8b8fe671b1a6..8d79286ee4e8 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c | |||
@@ -271,7 +271,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
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 = access_process_vm(child, addr, &tmp, |
274 | to_copy, 0); | 274 | to_copy, FOLL_FORCE); |
275 | if (copied) | 275 | if (copied) |
276 | break; | 276 | break; |
277 | 277 | ||
@@ -324,7 +324,8 @@ long arch_ptrace(struct task_struct *child, long request, | |||
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 = access_process_vm(child, addr, &data, |
327 | to_copy, 1); | 327 | to_copy, |
328 | FOLL_FORCE | FOLL_WRITE); | ||
328 | break; | 329 | break; |
329 | case BFIN_MEM_ACCESS_DMA: | 330 | case BFIN_MEM_ACCESS_DMA: |
330 | if (safe_dma_memcpy(paddr, &data, to_copy)) | 331 | if (safe_dma_memcpy(paddr, &data, to_copy)) |
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index f085229cf870..f0df654ac6fc 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), 0); | 150 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); |
151 | 151 | ||
152 | if (copied != sizeof(tmp)) | 152 | if (copied != sizeof(tmp)) |
153 | break; | 153 | break; |
@@ -279,7 +279,7 @@ static int insn_size(struct task_struct *child, unsigned long pc) | |||
279 | int opsize = 0; | 279 | int opsize = 0; |
280 | 280 | ||
281 | /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */ | 281 | /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */ |
282 | copied = access_process_vm(child, pc, &opcode, sizeof(opcode), 0); | 282 | copied = access_process_vm(child, pc, &opcode, sizeof(opcode), FOLL_FORCE); |
283 | if (copied != sizeof(opcode)) | 283 | if (copied != sizeof(opcode)) |
284 | return 0; | 284 | return 0; |
285 | 285 | ||
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 6f54d511cc50..31aa8c0f68e1 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -453,7 +453,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack, | |||
453 | return 0; | 453 | return 0; |
454 | } | 454 | } |
455 | } | 455 | } |
456 | copied = access_process_vm(child, addr, &ret, sizeof(ret), 0); | 456 | copied = access_process_vm(child, addr, &ret, sizeof(ret), FOLL_FORCE); |
457 | if (copied != sizeof(ret)) | 457 | if (copied != sizeof(ret)) |
458 | return -EIO; | 458 | return -EIO; |
459 | *val = ret; | 459 | *val = ret; |
@@ -489,7 +489,8 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack, | |||
489 | *ia64_rse_skip_regs(krbs, regnum) = val; | 489 | *ia64_rse_skip_regs(krbs, regnum) = val; |
490 | } | 490 | } |
491 | } | 491 | } |
492 | } else if (access_process_vm(child, addr, &val, sizeof(val), 1) | 492 | } else if (access_process_vm(child, addr, &val, sizeof(val), |
493 | FOLL_FORCE | FOLL_WRITE) | ||
493 | != sizeof(val)) | 494 | != sizeof(val)) |
494 | return -EIO; | 495 | return -EIO; |
495 | return 0; | 496 | return 0; |
@@ -543,7 +544,8 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw, | |||
543 | ret = ia64_peek(child, sw, user_rbs_end, addr, &val); | 544 | ret = ia64_peek(child, sw, user_rbs_end, addr, &val); |
544 | if (ret < 0) | 545 | if (ret < 0) |
545 | return ret; | 546 | return ret; |
546 | if (access_process_vm(child, addr, &val, sizeof(val), 1) | 547 | if (access_process_vm(child, addr, &val, sizeof(val), |
548 | FOLL_FORCE | FOLL_WRITE) | ||
547 | != sizeof(val)) | 549 | != sizeof(val)) |
548 | return -EIO; | 550 | return -EIO; |
549 | } | 551 | } |
@@ -559,7 +561,8 @@ ia64_sync_kernel_rbs (struct task_struct *child, struct switch_stack *sw, | |||
559 | 561 | ||
560 | /* now copy word for word from user rbs to kernel rbs: */ | 562 | /* now copy word for word from user rbs to kernel rbs: */ |
561 | for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) { | 563 | for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) { |
562 | if (access_process_vm(child, addr, &val, sizeof(val), 0) | 564 | if (access_process_vm(child, addr, &val, sizeof(val), |
565 | FOLL_FORCE) | ||
563 | != sizeof(val)) | 566 | != sizeof(val)) |
564 | return -EIO; | 567 | return -EIO; |
565 | 568 | ||
@@ -1156,7 +1159,8 @@ arch_ptrace (struct task_struct *child, long request, | |||
1156 | case PTRACE_PEEKTEXT: | 1159 | case PTRACE_PEEKTEXT: |
1157 | case PTRACE_PEEKDATA: | 1160 | case PTRACE_PEEKDATA: |
1158 | /* read word at location addr */ | 1161 | /* read word at location addr */ |
1159 | if (access_process_vm(child, addr, &data, sizeof(data), 0) | 1162 | if (access_process_vm(child, addr, &data, sizeof(data), |
1163 | FOLL_FORCE) | ||
1160 | != sizeof(data)) | 1164 | != sizeof(data)) |
1161 | return -EIO; | 1165 | return -EIO; |
1162 | /* ensure return value is not mistaken for error code */ | 1166 | /* ensure return value is not mistaken for error code */ |
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 51f5e9aa4901..c145605a981f 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c | |||
@@ -493,7 +493,8 @@ unregister_all_debug_traps(struct task_struct *child) | |||
493 | int i; | 493 | int i; |
494 | 494 | ||
495 | for (i = 0; i < p->nr_trap; i++) | 495 | for (i = 0; i < p->nr_trap; i++) |
496 | access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1); | 496 | access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), |
497 | FOLL_FORCE | FOLL_WRITE); | ||
497 | p->nr_trap = 0; | 498 | p->nr_trap = 0; |
498 | } | 499 | } |
499 | 500 | ||
@@ -537,7 +538,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc) | |||
537 | unsigned long next_insn, code; | 538 | unsigned long next_insn, code; |
538 | unsigned long addr = next_pc & ~3; | 539 | unsigned long addr = next_pc & ~3; |
539 | 540 | ||
540 | if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0) | 541 | if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), |
542 | FOLL_FORCE) | ||
541 | != sizeof(next_insn)) { | 543 | != sizeof(next_insn)) { |
542 | return -1; /* error */ | 544 | return -1; /* error */ |
543 | } | 545 | } |
@@ -546,7 +548,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc) | |||
546 | if (register_debug_trap(child, next_pc, next_insn, &code)) { | 548 | if (register_debug_trap(child, next_pc, next_insn, &code)) { |
547 | return -1; /* error */ | 549 | return -1; /* error */ |
548 | } | 550 | } |
549 | if (access_process_vm(child, addr, &code, sizeof(code), 1) | 551 | if (access_process_vm(child, addr, &code, sizeof(code), |
552 | FOLL_FORCE | FOLL_WRITE) | ||
550 | != sizeof(code)) { | 553 | != sizeof(code)) { |
551 | return -1; /* error */ | 554 | return -1; /* error */ |
552 | } | 555 | } |
@@ -562,7 +565,8 @@ withdraw_debug_trap(struct pt_regs *regs) | |||
562 | addr = (regs->bpc - 2) & ~3; | 565 | addr = (regs->bpc - 2) & ~3; |
563 | regs->bpc -= 2; | 566 | regs->bpc -= 2; |
564 | if (unregister_debug_trap(current, addr, &code)) { | 567 | if (unregister_debug_trap(current, addr, &code)) { |
565 | access_process_vm(current, addr, &code, sizeof(code), 1); | 568 | access_process_vm(current, addr, &code, sizeof(code), |
569 | FOLL_FORCE | FOLL_WRITE); | ||
566 | invalidate_cache(); | 570 | invalidate_cache(); |
567 | } | 571 | } |
568 | } | 572 | } |
@@ -589,7 +593,8 @@ void user_enable_single_step(struct task_struct *child) | |||
589 | /* Compute next pc. */ | 593 | /* Compute next pc. */ |
590 | pc = get_stack_long(child, PT_BPC); | 594 | pc = get_stack_long(child, PT_BPC); |
591 | 595 | ||
592 | if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) | 596 | if (access_process_vm(child, pc&~3, &insn, sizeof(insn), |
597 | FOLL_FORCE) | ||
593 | != sizeof(insn)) | 598 | != sizeof(insn)) |
594 | return; | 599 | return; |
595 | 600 | ||
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 283b5a1967d1..7e71a4e0281b 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c | |||
@@ -70,7 +70,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
70 | break; | 70 | break; |
71 | 71 | ||
72 | copied = access_process_vm(child, (u64)addrOthers, &tmp, | 72 | copied = access_process_vm(child, (u64)addrOthers, &tmp, |
73 | sizeof(tmp), 0); | 73 | sizeof(tmp), FOLL_FORCE); |
74 | if (copied != sizeof(tmp)) | 74 | if (copied != sizeof(tmp)) |
75 | break; | 75 | break; |
76 | ret = put_user(tmp, (u32 __user *) (unsigned long) data); | 76 | ret = put_user(tmp, (u32 __user *) (unsigned long) data); |
@@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
179 | break; | 179 | break; |
180 | ret = 0; | 180 | ret = 0; |
181 | if (access_process_vm(child, (u64)addrOthers, &data, | 181 | if (access_process_vm(child, (u64)addrOthers, &data, |
182 | sizeof(data), 1) == sizeof(data)) | 182 | sizeof(data), |
183 | FOLL_FORCE | FOLL_WRITE) == sizeof(data)) | ||
183 | break; | 184 | break; |
184 | ret = -EIO; | 185 | ret = -EIO; |
185 | break; | 186 | break; |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index f52b7db327c8..010b7b310237 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -74,7 +74,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
74 | break; | 74 | break; |
75 | 75 | ||
76 | copied = access_process_vm(child, (u64)addrOthers, &tmp, | 76 | copied = access_process_vm(child, (u64)addrOthers, &tmp, |
77 | sizeof(tmp), 0); | 77 | sizeof(tmp), FOLL_FORCE); |
78 | if (copied != sizeof(tmp)) | 78 | if (copied != sizeof(tmp)) |
79 | break; | 79 | break; |
80 | ret = put_user(tmp, (u32 __user *)data); | 80 | ret = put_user(tmp, (u32 __user *)data); |
@@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
179 | break; | 179 | break; |
180 | ret = 0; | 180 | ret = 0; |
181 | if (access_process_vm(child, (u64)addrOthers, &tmp, | 181 | if (access_process_vm(child, (u64)addrOthers, &tmp, |
182 | sizeof(tmp), 1) == sizeof(tmp)) | 182 | sizeof(tmp), |
183 | FOLL_FORCE | FOLL_WRITE) == sizeof(tmp)) | ||
183 | break; | 184 | break; |
184 | ret = -EIO; | 185 | ret = -EIO; |
185 | break; | 186 | break; |
diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 55836188b217..4f7314d5f334 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c | |||
@@ -131,7 +131,7 @@ read_tsk_long(struct task_struct *child, | |||
131 | { | 131 | { |
132 | int copied; | 132 | int copied; |
133 | 133 | ||
134 | copied = access_process_vm(child, addr, res, sizeof(*res), 0); | 134 | copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE); |
135 | 135 | ||
136 | return copied != sizeof(*res) ? -EIO : 0; | 136 | return copied != sizeof(*res) ? -EIO : 0; |
137 | } | 137 | } |
@@ -142,7 +142,7 @@ read_tsk_short(struct task_struct *child, | |||
142 | { | 142 | { |
143 | int copied; | 143 | int copied; |
144 | 144 | ||
145 | copied = access_process_vm(child, addr, res, sizeof(*res), 0); | 145 | copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE); |
146 | 146 | ||
147 | return copied != sizeof(*res) ? -EIO : 0; | 147 | return copied != sizeof(*res) ? -EIO : 0; |
148 | } | 148 | } |
@@ -153,7 +153,8 @@ write_tsk_short(struct task_struct *child, | |||
153 | { | 153 | { |
154 | int copied; | 154 | int copied; |
155 | 155 | ||
156 | copied = access_process_vm(child, addr, &val, sizeof(val), 1); | 156 | copied = access_process_vm(child, addr, &val, sizeof(val), |
157 | FOLL_FORCE | FOLL_WRITE); | ||
157 | 158 | ||
158 | return copied != sizeof(val) ? -EIO : 0; | 159 | return copied != sizeof(val) ? -EIO : 0; |
159 | } | 160 | } |
@@ -164,7 +165,8 @@ write_tsk_long(struct task_struct *child, | |||
164 | { | 165 | { |
165 | int copied; | 166 | int copied; |
166 | 167 | ||
167 | copied = access_process_vm(child, addr, &val, sizeof(val), 1); | 168 | copied = access_process_vm(child, addr, &val, sizeof(val), |
169 | FOLL_FORCE | FOLL_WRITE); | ||
168 | 170 | ||
169 | return copied != sizeof(val) ? -EIO : 0; | 171 | return copied != sizeof(val) ? -EIO : 0; |
170 | } | 172 | } |
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 9ddc4928a089..ac082dd8c67d 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c | |||
@@ -127,7 +127,8 @@ static int get_from_target(struct task_struct *target, unsigned long uaddr, | |||
127 | if (copy_from_user(kbuf, (void __user *) uaddr, len)) | 127 | if (copy_from_user(kbuf, (void __user *) uaddr, len)) |
128 | return -EFAULT; | 128 | return -EFAULT; |
129 | } else { | 129 | } else { |
130 | int len2 = access_process_vm(target, uaddr, kbuf, len, 0); | 130 | int len2 = access_process_vm(target, uaddr, kbuf, len, |
131 | FOLL_FORCE); | ||
131 | if (len2 != len) | 132 | if (len2 != len) |
132 | return -EFAULT; | 133 | return -EFAULT; |
133 | } | 134 | } |
@@ -141,7 +142,8 @@ static int set_to_target(struct task_struct *target, unsigned long uaddr, | |||
141 | if (copy_to_user((void __user *) uaddr, kbuf, len)) | 142 | if (copy_to_user((void __user *) uaddr, kbuf, len)) |
142 | return -EFAULT; | 143 | return -EFAULT; |
143 | } else { | 144 | } else { |
144 | int len2 = access_process_vm(target, uaddr, kbuf, len, 1); | 145 | int len2 = access_process_vm(target, uaddr, kbuf, len, |
146 | FOLL_FORCE | FOLL_WRITE); | ||
145 | if (len2 != len) | 147 | if (len2 != len) |
146 | return -EFAULT; | 148 | return -EFAULT; |
147 | } | 149 | } |
@@ -505,7 +507,8 @@ static int genregs32_get(struct task_struct *target, | |||
505 | if (access_process_vm(target, | 507 | if (access_process_vm(target, |
506 | (unsigned long) | 508 | (unsigned long) |
507 | ®_window[pos], | 509 | ®_window[pos], |
508 | k, sizeof(*k), 0) | 510 | k, sizeof(*k), |
511 | FOLL_FORCE) | ||
509 | != sizeof(*k)) | 512 | != sizeof(*k)) |
510 | return -EFAULT; | 513 | return -EFAULT; |
511 | k++; | 514 | k++; |
@@ -531,12 +534,14 @@ static int genregs32_get(struct task_struct *target, | |||
531 | if (access_process_vm(target, | 534 | if (access_process_vm(target, |
532 | (unsigned long) | 535 | (unsigned long) |
533 | ®_window[pos], | 536 | ®_window[pos], |
534 | ®, sizeof(reg), 0) | 537 | ®, sizeof(reg), |
538 | FOLL_FORCE) | ||
535 | != sizeof(reg)) | 539 | != sizeof(reg)) |
536 | return -EFAULT; | 540 | return -EFAULT; |
537 | if (access_process_vm(target, | 541 | if (access_process_vm(target, |
538 | (unsigned long) u, | 542 | (unsigned long) u, |
539 | ®, sizeof(reg), 1) | 543 | ®, sizeof(reg), |
544 | FOLL_FORCE | FOLL_WRITE) | ||
540 | != sizeof(reg)) | 545 | != sizeof(reg)) |
541 | return -EFAULT; | 546 | return -EFAULT; |
542 | pos++; | 547 | pos++; |
@@ -615,7 +620,8 @@ static int genregs32_set(struct task_struct *target, | |||
615 | (unsigned long) | 620 | (unsigned long) |
616 | ®_window[pos], | 621 | ®_window[pos], |
617 | (void *) k, | 622 | (void *) k, |
618 | sizeof(*k), 1) | 623 | sizeof(*k), |
624 | FOLL_FORCE | FOLL_WRITE) | ||
619 | != sizeof(*k)) | 625 | != sizeof(*k)) |
620 | return -EFAULT; | 626 | return -EFAULT; |
621 | k++; | 627 | k++; |
@@ -642,13 +648,15 @@ static int genregs32_set(struct task_struct *target, | |||
642 | if (access_process_vm(target, | 648 | if (access_process_vm(target, |
643 | (unsigned long) | 649 | (unsigned long) |
644 | u, | 650 | u, |
645 | ®, sizeof(reg), 0) | 651 | ®, sizeof(reg), |
652 | FOLL_FORCE) | ||
646 | != sizeof(reg)) | 653 | != sizeof(reg)) |
647 | return -EFAULT; | 654 | return -EFAULT; |
648 | if (access_process_vm(target, | 655 | if (access_process_vm(target, |
649 | (unsigned long) | 656 | (unsigned long) |
650 | ®_window[pos], | 657 | ®_window[pos], |
651 | ®, sizeof(reg), 1) | 658 | ®, sizeof(reg), |
659 | FOLL_FORCE | FOLL_WRITE) | ||
652 | != sizeof(reg)) | 660 | != sizeof(reg)) |
653 | return -EFAULT; | 661 | return -EFAULT; |
654 | pos++; | 662 | pos++; |
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index c9a073866ca7..a23ce84a3f6c 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c | |||
@@ -57,7 +57,8 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) | |||
57 | unsigned char opcode[15]; | 57 | unsigned char opcode[15]; |
58 | unsigned long addr = convert_ip_to_linear(child, regs); | 58 | unsigned long addr = convert_ip_to_linear(child, regs); |
59 | 59 | ||
60 | copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); | 60 | copied = access_process_vm(child, addr, opcode, sizeof(opcode), |
61 | FOLL_FORCE); | ||
61 | for (i = 0; i < copied; i++) { | 62 | for (i = 0; i < copied; i++) { |
62 | switch (opcode[i]) { | 63 | switch (opcode[i]) { |
63 | /* popf and iret */ | 64 | /* popf and iret */ |
diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 5766ead6fdb9..60a5a5a85505 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c | |||
@@ -36,7 +36,8 @@ int is_syscall(unsigned long addr) | |||
36 | * slow, but that doesn't matter, since it will be called only | 36 | * slow, but that doesn't matter, since it will be called only |
37 | * in case of singlestepping, if copy_from_user failed. | 37 | * in case of singlestepping, if copy_from_user failed. |
38 | */ | 38 | */ |
39 | n = access_process_vm(current, addr, &instr, sizeof(instr), 0); | 39 | n = access_process_vm(current, addr, &instr, sizeof(instr), |
40 | FOLL_FORCE); | ||
40 | if (n != sizeof(instr)) { | 41 | if (n != sizeof(instr)) { |
41 | printk(KERN_ERR "is_syscall : failed to read " | 42 | printk(KERN_ERR "is_syscall : failed to read " |
42 | "instruction from 0x%lx\n", addr); | 43 | "instruction from 0x%lx\n", addr); |
diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index 0b5c184dd5b3..e30202b1716e 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c | |||
@@ -212,7 +212,8 @@ int is_syscall(unsigned long addr) | |||
212 | * slow, but that doesn't matter, since it will be called only | 212 | * slow, but that doesn't matter, since it will be called only |
213 | * in case of singlestepping, if copy_from_user failed. | 213 | * in case of singlestepping, if copy_from_user failed. |
214 | */ | 214 | */ |
215 | n = access_process_vm(current, addr, &instr, sizeof(instr), 0); | 215 | n = access_process_vm(current, addr, &instr, sizeof(instr), |
216 | FOLL_FORCE); | ||
216 | if (n != sizeof(instr)) { | 217 | if (n != sizeof(instr)) { |
217 | printk("is_syscall : failed to read instruction from " | 218 | printk("is_syscall : failed to read instruction from " |
218 | "0x%lx\n", addr); | 219 | "0x%lx\n", addr); |
diff --git a/include/linux/mm.h b/include/linux/mm.h index f31bf9058587..ffbd72979ee7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -1266,7 +1266,8 @@ static inline int fixup_user_fault(struct task_struct *tsk, | |||
1266 | } | 1266 | } |
1267 | #endif | 1267 | #endif |
1268 | 1268 | ||
1269 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); | 1269 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, |
1270 | unsigned int gup_flags); | ||
1270 | 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, |
1271 | void *buf, int len, unsigned int gup_flags); | 1272 | void *buf, int len, unsigned int gup_flags); |
1272 | 1273 | ||
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 2a99027312a6..e6474f7272ec 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -537,7 +537,7 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst | |||
537 | int this_len, retval; | 537 | int this_len, retval; |
538 | 538 | ||
539 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; | 539 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; |
540 | retval = access_process_vm(tsk, src, buf, this_len, 0); | 540 | retval = access_process_vm(tsk, src, buf, this_len, FOLL_FORCE); |
541 | if (!retval) { | 541 | if (!retval) { |
542 | if (copied) | 542 | if (copied) |
543 | break; | 543 | break; |
@@ -564,7 +564,8 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds | |||
564 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; | 564 | this_len = (len > sizeof(buf)) ? sizeof(buf) : len; |
565 | if (copy_from_user(buf, src, this_len)) | 565 | if (copy_from_user(buf, src, this_len)) |
566 | return -EFAULT; | 566 | return -EFAULT; |
567 | retval = access_process_vm(tsk, dst, buf, this_len, 1); | 567 | retval = access_process_vm(tsk, dst, buf, this_len, |
568 | FOLL_FORCE | FOLL_WRITE); | ||
568 | if (!retval) { | 569 | if (!retval) { |
569 | if (copied) | 570 | if (copied) |
570 | break; | 571 | break; |
@@ -1127,7 +1128,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, | |||
1127 | unsigned long tmp; | 1128 | unsigned long tmp; |
1128 | int copied; | 1129 | int copied; |
1129 | 1130 | ||
1130 | copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); | 1131 | copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE); |
1131 | if (copied != sizeof(tmp)) | 1132 | if (copied != sizeof(tmp)) |
1132 | return -EIO; | 1133 | return -EIO; |
1133 | return put_user(tmp, (unsigned long __user *)data); | 1134 | return put_user(tmp, (unsigned long __user *)data); |
@@ -1138,7 +1139,8 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, | |||
1138 | { | 1139 | { |
1139 | int copied; | 1140 | int copied; |
1140 | 1141 | ||
1141 | copied = access_process_vm(tsk, addr, &data, sizeof(data), 1); | 1142 | copied = access_process_vm(tsk, addr, &data, sizeof(data), |
1143 | FOLL_FORCE | FOLL_WRITE); | ||
1142 | return (copied == sizeof(data)) ? 0 : -EIO; | 1144 | return (copied == sizeof(data)) ? 0 : -EIO; |
1143 | } | 1145 | } |
1144 | 1146 | ||
@@ -1155,7 +1157,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, | |||
1155 | switch (request) { | 1157 | switch (request) { |
1156 | case PTRACE_PEEKTEXT: | 1158 | case PTRACE_PEEKTEXT: |
1157 | case PTRACE_PEEKDATA: | 1159 | case PTRACE_PEEKDATA: |
1158 | ret = access_process_vm(child, addr, &word, sizeof(word), 0); | 1160 | ret = access_process_vm(child, addr, &word, sizeof(word), |
1161 | FOLL_FORCE); | ||
1159 | if (ret != sizeof(word)) | 1162 | if (ret != sizeof(word)) |
1160 | ret = -EIO; | 1163 | ret = -EIO; |
1161 | else | 1164 | else |
@@ -1164,7 +1167,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, | |||
1164 | 1167 | ||
1165 | case PTRACE_POKETEXT: | 1168 | case PTRACE_POKETEXT: |
1166 | case PTRACE_POKEDATA: | 1169 | case PTRACE_POKEDATA: |
1167 | ret = access_process_vm(child, addr, &data, sizeof(data), 1); | 1170 | ret = access_process_vm(child, addr, &data, sizeof(data), |
1171 | FOLL_FORCE | FOLL_WRITE); | ||
1168 | ret = (ret != sizeof(data) ? -EIO : 0); | 1172 | ret = (ret != sizeof(data) ? -EIO : 0); |
1169 | break; | 1173 | break; |
1170 | 1174 | ||
diff --git a/mm/memory.c b/mm/memory.c index bac2d994850e..e18c57bdc75c 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3951,20 +3951,16 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr, | |||
3951 | * Do not walk the page table directly, use get_user_pages | 3951 | * Do not walk the page table directly, use get_user_pages |
3952 | */ | 3952 | */ |
3953 | int access_process_vm(struct task_struct *tsk, unsigned long addr, | 3953 | int access_process_vm(struct task_struct *tsk, unsigned long addr, |
3954 | void *buf, int len, int write) | 3954 | void *buf, int len, unsigned int gup_flags) |
3955 | { | 3955 | { |
3956 | struct mm_struct *mm; | 3956 | struct mm_struct *mm; |
3957 | int ret; | 3957 | int ret; |
3958 | unsigned int flags = FOLL_FORCE; | ||
3959 | 3958 | ||
3960 | mm = get_task_mm(tsk); | 3959 | mm = get_task_mm(tsk); |
3961 | if (!mm) | 3960 | if (!mm) |
3962 | return 0; | 3961 | return 0; |
3963 | 3962 | ||
3964 | if (write) | 3963 | ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); |
3965 | flags |= FOLL_WRITE; | ||
3966 | |||
3967 | ret = __access_remote_vm(tsk, mm, addr, buf, len, flags); | ||
3968 | 3964 | ||
3969 | mmput(mm); | 3965 | mmput(mm); |
3970 | 3966 | ||
diff --git a/mm/nommu.c b/mm/nommu.c index 93d5bb53fc63..db5fd1795298 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -1861,7 +1861,8 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr, | |||
1861 | * Access another process' address space. | 1861 | * Access another process' address space. |
1862 | * - source/target buffer must be kernel space | 1862 | * - source/target buffer must be kernel space |
1863 | */ | 1863 | */ |
1864 | int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) | 1864 | int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, |
1865 | unsigned int gup_flags) | ||
1865 | { | 1866 | { |
1866 | struct mm_struct *mm; | 1867 | struct mm_struct *mm; |
1867 | 1868 | ||
@@ -1872,8 +1873,7 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in | |||
1872 | if (!mm) | 1873 | if (!mm) |
1873 | return 0; | 1874 | return 0; |
1874 | 1875 | ||
1875 | len = __access_remote_vm(tsk, mm, addr, buf, len, | 1876 | len = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); |
1876 | write ? FOLL_WRITE : 0); | ||
1877 | 1877 | ||
1878 | mmput(mm); | 1878 | mmput(mm); |
1879 | return len; | 1879 | return len; |
@@ -624,7 +624,7 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) | |||
624 | if (len > buflen) | 624 | if (len > buflen) |
625 | len = buflen; | 625 | len = buflen; |
626 | 626 | ||
627 | res = access_process_vm(task, arg_start, buffer, len, 0); | 627 | res = access_process_vm(task, arg_start, buffer, len, FOLL_FORCE); |
628 | 628 | ||
629 | /* | 629 | /* |
630 | * If the nul at the end of args has been overwritten, then | 630 | * If the nul at the end of args has been overwritten, then |
@@ -639,7 +639,8 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) | |||
639 | if (len > buflen - res) | 639 | if (len > buflen - res) |
640 | len = buflen - res; | 640 | len = buflen - res; |
641 | res += access_process_vm(task, env_start, | 641 | res += access_process_vm(task, env_start, |
642 | buffer+res, len, 0); | 642 | buffer+res, len, |
643 | FOLL_FORCE); | ||
643 | res = strnlen(buffer, res); | 644 | res = strnlen(buffer, res); |
644 | } | 645 | } |
645 | } | 646 | } |