mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 17:11:33 +00:00
s390/maccess: remove potentially broken probe_kernel_write()
Remove the s390 architecture implementation of probe_kernel_write() and instead use a new function s390_kernel_write() to modify kernel text and data everywhere. The s390 implementation of probe_kernel_write() was potentially broken since it modified memory in a read-modify-write fashion, which read four bytes, modified the requested bytes within those four bytes and wrote the result back. If two cpus would modify the same four byte area at different locations within that area, this could lead to corruption. Right now the only places which called probe_kernel_write() did run within stop_machine_run. Therefore the scenario can't happen right now, however that might change at any time. To fix this rename probe_kernel_write() to s390_kernel_write() which can have special semantics, like only call it while running within stop_machine(). Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
b2527d2009
commit
8a5d8473dd
@ -372,5 +372,6 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
|
||||
}
|
||||
|
||||
int copy_to_user_real(void __user *dest, void *src, unsigned long count);
|
||||
void s390_kernel_write(void *dst, const void *src, size_t size);
|
||||
|
||||
#endif /* __S390_UACCESS_H */
|
||||
|
@ -130,8 +130,7 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
|
||||
/* Verify that the to be replaced code matches what we expect. */
|
||||
if (memcmp(&orig, &old, sizeof(old)))
|
||||
return -EINVAL;
|
||||
if (probe_kernel_write((void *) rec->ip, &new, sizeof(new)))
|
||||
return -EPERM;
|
||||
s390_kernel_write((void *) rec->ip, &new, sizeof(new));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -159,8 +158,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
/* Verify that the to be replaced code matches what we expect. */
|
||||
if (memcmp(&orig, &old, sizeof(old)))
|
||||
return -EINVAL;
|
||||
if (probe_kernel_write((void *) rec->ip, &new, sizeof(new)))
|
||||
return -EPERM;
|
||||
s390_kernel_write((void *) rec->ip, &new, sizeof(new));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -231,14 +229,16 @@ int ftrace_enable_ftrace_graph_caller(void)
|
||||
{
|
||||
u8 op = 0x04; /* set mask field to zero */
|
||||
|
||||
return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
|
||||
s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftrace_disable_ftrace_graph_caller(void)
|
||||
{
|
||||
u8 op = 0xf4; /* set mask field to all ones */
|
||||
|
||||
return probe_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
|
||||
s390_kernel_write(__va(ftrace_graph_caller)+1, &op, sizeof(op));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
@ -78,7 +78,7 @@ static void __jump_label_transform(struct jump_entry *entry,
|
||||
if (memcmp((void *)entry->code, &old, sizeof(old)))
|
||||
jump_label_bug(entry, &old, &new);
|
||||
}
|
||||
probe_kernel_write((void *)entry->code, &new, sizeof(new));
|
||||
s390_kernel_write((void *)entry->code, &new, sizeof(new));
|
||||
}
|
||||
|
||||
static int __sm_arch_jump_label_transform(void *data)
|
||||
|
@ -178,7 +178,7 @@ static int swap_instruction(void *data)
|
||||
}
|
||||
skip_ftrace:
|
||||
kcb->kprobe_status = KPROBE_SWAP_INST;
|
||||
probe_kernel_write(p->addr, &new_insn, len);
|
||||
s390_kernel_write(p->addr, &new_insn, len);
|
||||
kcb->kprobe_status = status;
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,13 +16,7 @@
|
||||
#include <asm/ctl_reg.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* This function writes to kernel memory bypassing DAT and possible
|
||||
* write protection. It copies one to four bytes from src to dst
|
||||
* using the stura instruction.
|
||||
* Returns the number of bytes copied or -EFAULT.
|
||||
*/
|
||||
static long probe_kernel_write_odd(void *dst, const void *src, size_t size)
|
||||
static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t size)
|
||||
{
|
||||
unsigned long count, aligned;
|
||||
int offset, mask;
|
||||
@ -48,19 +42,34 @@ static long probe_kernel_write_odd(void *dst, const void *src, size_t size)
|
||||
return rc ? rc : count;
|
||||
}
|
||||
|
||||
long probe_kernel_write(void *dst, const void *src, size_t size)
|
||||
/*
|
||||
* s390_kernel_write - write to kernel memory bypassing DAT
|
||||
* @dst: destination address
|
||||
* @src: source address
|
||||
* @size: number of bytes to copy
|
||||
*
|
||||
* This function writes to kernel memory bypassing DAT and possible page table
|
||||
* write protection. It writes to the destination using the sturg instruction.
|
||||
* Therefore we have a read-modify-write sequence: the function reads four
|
||||
* bytes from destination at a four byte boundary, modifies the bytes
|
||||
* requested and writes the result back in a loop.
|
||||
*
|
||||
* Note: this means that this function may not be called concurrently on
|
||||
* several cpus with overlapping words, since this may potentially
|
||||
* cause data corruption.
|
||||
*/
|
||||
void notrace s390_kernel_write(void *dst, const void *src, size_t size)
|
||||
{
|
||||
long copied = 0;
|
||||
|
||||
while (size) {
|
||||
copied = probe_kernel_write_odd(dst, src, size);
|
||||
copied = s390_kernel_write_odd(dst, src, size);
|
||||
if (copied < 0)
|
||||
break;
|
||||
dst += copied;
|
||||
src += copied;
|
||||
size -= copied;
|
||||
}
|
||||
return copied < 0 ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int __memcpy_real(void *dest, void *src, size_t count)
|
||||
|
Loading…
Reference in New Issue
Block a user