diff options
-rw-r--r-- | arch/s390/include/asm/uaccess.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/ftrace.c | 12 | ||||
-rw-r--r-- | arch/s390/kernel/jump_label.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/maccess.c | 29 |
5 files changed, 28 insertions, 18 deletions
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index cd4c68e0398d..d64a7a62164f 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h | |||
@@ -372,5 +372,6 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo | |||
372 | } | 372 | } |
373 | 373 | ||
374 | int copy_to_user_real(void __user *dest, void *src, unsigned long count); | 374 | int copy_to_user_real(void __user *dest, void *src, unsigned long count); |
375 | void s390_kernel_write(void *dst, const void *src, size_t size); | ||
375 | 376 | ||
376 | #endif /* __S390_UACCESS_H */ | 377 | #endif /* __S390_UACCESS_H */ |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 6c79f1b44fe7..e0eaf11134b4 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -130,8 +130,7 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | |||
130 | /* Verify that the to be replaced code matches what we expect. */ | 130 | /* Verify that the to be replaced code matches what we expect. */ |
131 | if (memcmp(&orig, &old, sizeof(old))) | 131 | if (memcmp(&orig, &old, sizeof(old))) |
132 | return -EINVAL; | 132 | return -EINVAL; |
133 | if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) | 133 | s390_kernel_write((void *) rec->ip, &new, sizeof(new)); |
134 | return -EPERM; | ||
135 | return 0; | 134 | return 0; |
136 | } | 135 | } |
137 | 136 | ||
@@ -159,8 +158,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
159 | /* Verify that the to be replaced code matches what we expect. */ | 158 | /* Verify that the to be replaced code matches what we expect. */ |
160 | if (memcmp(&orig, &old, sizeof(old))) | 159 | if (memcmp(&orig, &old, sizeof(old))) |
161 | return -EINVAL; | 160 | return -EINVAL; |
162 | if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) | 161 | s390_kernel_write((void *) rec->ip, &new, sizeof(new)); |
163 | return -EPERM; | ||
164 | return 0; | 162 | return 0; |
165 | } | 163 | } |
166 | 164 | ||
@@ -231,14 +229,16 @@ int ftrace_enable_ftrace_graph_caller(void) | |||
231 | { | 229 | { |
232 | u8 op = 0x04; /* set mask field to zero */ | 230 | u8 op = 0x04; /* set mask field to zero */ |
233 | 231 | ||
234 | return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op)); | 232 | s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op)); |
233 | return 0; | ||
235 | } | 234 | } |
236 | 235 | ||
237 | int ftrace_disable_ftrace_graph_caller(void) | 236 | int ftrace_disable_ftrace_graph_caller(void) |
238 | { | 237 | { |
239 | u8 op = 0xf4; /* set mask field to all ones */ | 238 | u8 op = 0xf4; /* set mask field to all ones */ |
240 | 239 | ||
241 | return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op)); | 240 | s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op)); |
241 | return 0; | ||
242 | } | 242 | } |
243 | 243 | ||
244 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 244 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c index 830066f936c8..a90299600483 100644 --- a/arch/s390/kernel/jump_label.c +++ b/arch/s390/kernel/jump_label.c | |||
@@ -78,7 +78,7 @@ static void __jump_label_transform(struct jump_entry *entry, | |||
78 | if (memcmp((void *)entry->code, &old, sizeof(old))) | 78 | if (memcmp((void *)entry->code, &old, sizeof(old))) |
79 | jump_label_bug(entry, &old, &new); | 79 | jump_label_bug(entry, &old, &new); |
80 | } | 80 | } |
81 | probe_kernel_write((void *)entry->code, &new, sizeof(new)); | 81 | s390_kernel_write((void *)entry->code, &new, sizeof(new)); |
82 | } | 82 | } |
83 | 83 | ||
84 | static int __sm_arch_jump_label_transform(void *data) | 84 | static int __sm_arch_jump_label_transform(void *data) |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index f516edc1fbe3..389db56a2208 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -178,7 +178,7 @@ static int swap_instruction(void *data) | |||
178 | } | 178 | } |
179 | skip_ftrace: | 179 | skip_ftrace: |
180 | kcb->kprobe_status = KPROBE_SWAP_INST; | 180 | kcb->kprobe_status = KPROBE_SWAP_INST; |
181 | probe_kernel_write(p->addr, &new_insn, len); | 181 | s390_kernel_write(p->addr, &new_insn, len); |
182 | kcb->kprobe_status = status; | 182 | kcb->kprobe_status = status; |
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 2eb34bdfc613..fb737e9e0683 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c | |||
@@ -16,13 +16,7 @@ | |||
16 | #include <asm/ctl_reg.h> | 16 | #include <asm/ctl_reg.h> |
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | 18 | ||
19 | /* | 19 | static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t size) |
20 | * This function writes to kernel memory bypassing DAT and possible | ||
21 | * write protection. It copies one to four bytes from src to dst | ||
22 | * using the stura instruction. | ||
23 | * Returns the number of bytes copied or -EFAULT. | ||
24 | */ | ||
25 | static long probe_kernel_write_odd(void *dst, const void *src, size_t size) | ||
26 | { | 20 | { |
27 | unsigned long count, aligned; | 21 | unsigned long count, aligned; |
28 | int offset, mask; | 22 | int offset, mask; |
@@ -48,19 +42,34 @@ static long probe_kernel_write_odd(void *dst, const void *src, size_t size) | |||
48 | return rc ? rc : count; | 42 | return rc ? rc : count; |
49 | } | 43 | } |
50 | 44 | ||
51 | long probe_kernel_write(void *dst, const void *src, size_t size) | 45 | /* |
46 | * s390_kernel_write - write to kernel memory bypassing DAT | ||
47 | * @dst: destination address | ||
48 | * @src: source address | ||
49 | * @size: number of bytes to copy | ||
50 | * | ||
51 | * This function writes to kernel memory bypassing DAT and possible page table | ||
52 | * write protection. It writes to the destination using the sturg instruction. | ||
53 | * Therefore we have a read-modify-write sequence: the function reads four | ||
54 | * bytes from destination at a four byte boundary, modifies the bytes | ||
55 | * requested and writes the result back in a loop. | ||
56 | * | ||
57 | * Note: this means that this function may not be called concurrently on | ||
58 | * several cpus with overlapping words, since this may potentially | ||
59 | * cause data corruption. | ||
60 | */ | ||
61 | void notrace s390_kernel_write(void *dst, const void *src, size_t size) | ||
52 | { | 62 | { |
53 | long copied = 0; | 63 | long copied = 0; |
54 | 64 | ||
55 | while (size) { | 65 | while (size) { |
56 | copied = probe_kernel_write_odd(dst, src, size); | 66 | copied = s390_kernel_write_odd(dst, src, size); |
57 | if (copied < 0) | 67 | if (copied < 0) |
58 | break; | 68 | break; |
59 | dst += copied; | 69 | dst += copied; |
60 | src += copied; | 70 | src += copied; |
61 | size -= copied; | 71 | size -= copied; |
62 | } | 72 | } |
63 | return copied < 0 ? -EFAULT : 0; | ||
64 | } | 73 | } |
65 | 74 | ||
66 | static int __memcpy_real(void *dest, void *src, size_t count) | 75 | static int __memcpy_real(void *dest, void *src, size_t count) |