mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-04 00:06:36 +00:00
![]() After copy_optimized_instructions() copies several instructions
to the working buffer it tries to fix up the real RIP address, but it
adjusts the RIP-relative instruction with an incorrect RIP address
for the 2nd and subsequent instructions due to a bug in the logic.
This will break the kernel pretty badly (with likely outcomes such as
a kernel freeze, a crash, or worse) because probed instructions can refer
to the wrong data.
For example putting kprobes on cpumask_next() typically hits this bug.
cpumask_next() is normally like below if CONFIG_CPUMASK_OFFSTACK=y
(in this case nr_cpumask_bits is an alias of nr_cpu_ids):
<cpumask_next>:
48 89 f0 mov %rsi,%rax
8b 35 7b fb e2 00 mov 0xe2fb7b(%rip),%esi # ffffffff82db9e64 <nr_cpu_ids>
55 push %rbp
...
If we put a kprobe on it and it gets jump-optimized, it gets
patched by the kprobes code like this:
<cpumask_next>:
e9 95 7d 07 1e jmpq 0xffffffffa000207a
7b fb jnp 0xffffffff81f8a2e2 <cpumask_next+2>
e2 00 loop 0xffffffff81f8a2e9 <cpumask_next+9>
55 push %rbp
This shows that the first two MOV instructions were copied to a
trampoline buffer at 0xffffffffa000207a.
Here is the disassembled result of the trampoline, skipping
the optprobe template instructions:
# Dump of assembly code from 0xffffffffa000207a to 0xffffffffa00020ea:
54 push %rsp
...
48 83 c4 08 add $0x8,%rsp
9d popfq
48 89 f0 mov %rsi,%rax
8b 35 82 7d db e2 mov -0x1d24827e(%rip),%esi # 0xffffffff82db9e67 <nr_cpu_ids+3>
This dump shows that the second MOV accesses *(nr_cpu_ids+3) instead of
the original *nr_cpu_ids. This leads to a kernel freeze because
cpumask_next() always returns 0 and for_each_cpu() never ends.
Fix this by adding 'len' correctly to the real RIP address while
copying.
[ mingo: Improved the changelog. ]
Reported-by: Michael Rodin <michael@rodin.online>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org # v4.15+
Fixes:
|
||
---|---|---|
.. | ||
acpi | ||
apic | ||
cpu | ||
fpu | ||
kprobes | ||
.gitignore | ||
alternative.c | ||
amd_gart_64.c | ||
amd_nb.c | ||
apb_timer.c | ||
aperture_64.c | ||
apm_32.c | ||
asm-offsets.c | ||
asm-offsets_32.c | ||
asm-offsets_64.c | ||
audit_64.c | ||
bootflag.c | ||
check.c | ||
cpuid.c | ||
crash.c | ||
crash_dump_32.c | ||
crash_dump_64.c | ||
devicetree.c | ||
doublefault.c | ||
dumpstack.c | ||
dumpstack_32.c | ||
dumpstack_64.c | ||
e820.c | ||
early-quirks.c | ||
early_printk.c | ||
ebda.c | ||
eisa.c | ||
espfix_64.c | ||
ftrace.c | ||
ftrace_32.S | ||
ftrace_64.S | ||
head32.c | ||
head64.c | ||
head_32.S | ||
head_64.S | ||
hpet.c | ||
hw_breakpoint.c | ||
i8237.c | ||
i8253.c | ||
i8259.c | ||
idt.c | ||
io_delay.c | ||
ioport.c | ||
irq.c | ||
irq_32.c | ||
irq_64.c | ||
irq_work.c | ||
irqflags.S | ||
irqinit.c | ||
itmt.c | ||
jailhouse.c | ||
jump_label.c | ||
kdebugfs.c | ||
kexec-bzimage64.c | ||
kgdb.c | ||
ksysfs.c | ||
kvm.c | ||
kvmclock.c | ||
ldt.c | ||
livepatch.c | ||
machine_kexec_32.c | ||
machine_kexec_64.c | ||
macros.S | ||
Makefile | ||
mmconf-fam10h_64.c | ||
module.c | ||
mpparse.c | ||
msr.c | ||
nmi.c | ||
nmi_selftest.c | ||
paravirt-spinlocks.c | ||
paravirt.c | ||
paravirt_patch_32.c | ||
paravirt_patch_64.c | ||
pci-calgary_64.c | ||
pci-dma.c | ||
pci-iommu_table.c | ||
pci-swiotlb.c | ||
pcspeaker.c | ||
perf_regs.c | ||
platform-quirks.c | ||
pmem.c | ||
probe_roms.c | ||
process.c | ||
process.h | ||
process_32.c | ||
process_64.c | ||
ptrace.c | ||
pvclock.c | ||
quirks.c | ||
reboot.c | ||
reboot_fixups_32.c | ||
relocate_kernel_32.S | ||
relocate_kernel_64.S | ||
resource.c | ||
rtc.c | ||
setup.c | ||
setup_percpu.c | ||
signal.c | ||
signal_compat.c | ||
smp.c | ||
smpboot.c | ||
stacktrace.c | ||
step.c | ||
sys_x86_64.c | ||
sysfb.c | ||
sysfb_efi.c | ||
sysfb_simplefb.c | ||
tboot.c | ||
tce_64.c | ||
time.c | ||
tls.c | ||
tls.h | ||
topology.c | ||
trace_clock.c | ||
tracepoint.c | ||
traps.c | ||
tsc.c | ||
tsc_msr.c | ||
tsc_sync.c | ||
umip.c | ||
unwind_frame.c | ||
unwind_guess.c | ||
unwind_orc.c | ||
uprobes.c | ||
verify_cpu.S | ||
vm86_32.c | ||
vmlinux.lds.S | ||
vsmp_64.c | ||
x86_init.c |