Commit 4df898dc authored by Sven Schnelle's avatar Sven Schnelle Committed by Vasily Gorbik

s390/kprobes: add sanity check

Check whether the specified address points to the start of an
instruction to prevent users from setting a kprobe in the mid of
an instruction which would crash the kernel.
Signed-off-by: default avatarSven Schnelle <svens@linux.ibm.com>
Reviewed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent b860b934
...@@ -120,9 +120,55 @@ static void s390_free_insn_slot(struct kprobe *p) ...@@ -120,9 +120,55 @@ static void s390_free_insn_slot(struct kprobe *p)
} }
NOKPROBE_SYMBOL(s390_free_insn_slot); NOKPROBE_SYMBOL(s390_free_insn_slot);
/* Check if paddr is at an instruction boundary */
static bool can_probe(unsigned long paddr)
{
unsigned long addr, offset = 0;
kprobe_opcode_t insn;
struct kprobe *kp;
if (paddr & 0x01)
return false;
if (!kallsyms_lookup_size_offset(paddr, NULL, &offset))
return false;
/* Decode instructions */
addr = paddr - offset;
while (addr < paddr) {
if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(insn)))
return false;
if (insn >> 8 == 0) {
if (insn != BREAKPOINT_INSTRUCTION) {
/*
* Note that QEMU inserts opcode 0x0000 to implement
* software breakpoints for guests. Since the size of
* the original instruction is unknown, stop following
* instructions and prevent setting a kprobe.
*/
return false;
}
/*
* Check if the instruction has been modified by another
* kprobe, in which case the original instruction is
* decoded.
*/
kp = get_kprobe((void *)addr);
if (!kp) {
/* not a kprobe */
return false;
}
insn = kp->opcode;
}
addr += insn_length(insn >> 8);
}
return addr == paddr;
}
int arch_prepare_kprobe(struct kprobe *p) int arch_prepare_kprobe(struct kprobe *p)
{ {
if ((unsigned long) p->addr & 0x01) if (!can_probe((unsigned long)p->addr))
return -EINVAL; return -EINVAL;
/* Make sure the probe isn't going on a difficult instruction */ /* Make sure the probe isn't going on a difficult instruction */
if (probe_is_prohibited_opcode(p->addr)) if (probe_is_prohibited_opcode(p->addr))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment