DF-2343 / adjacency_codegen_addendum.txt
DF-2343 codegen evidence addendum (recorded from the -O0 harness kernel,
/usr/obj/usr/src/sys/UMCSH/kernel.debug, build of Sun Oct 18 21:2x UTC;
the object was later overwritten by the fixed builds -- this transcript
is the preserved record; the panic RIPs in panic.txt match it exactly).
umcs7840_calc_baudrate @ 0xffffffff80a85636 (verbatim unit, -O0):
+0x7b: 0f b6 45 ff movzbl -0x1(%rbp),%eax ; i
+0x7f: 83 c0 01 add $0x1,%eax ; i + 1
+0x82: 48 98 cltq
+0x84: 8b 04 85 c0 a2 d9 80 mov -0x7f265d40(,%rax,4),%eax
^^^^^^^^^^^^^ = 0xffffffff80d99240
= &umcs7840_baudrate_divisors[0]
-> with i==8 this loads divisors[9]:
the 1-ELEMENT OOB READ (umcs.c:1066)
+0x8b: ba 00 00 00 00 mov $0x0,%edx
+0x90: f7 75 ec divl -0x14(%rbp) ; divide by rate
-> rate==0: #DE, Fatal trap 18
(panics 1/2/3 RIP = base+0x90 = ...56c6)
+0x93: 89 c2 mov %eax,%edx ; *divisor = quotient
adjacency.txt (from the stock -O2 build of the same source) shows the
.rodata file image: divisors[0..8] = 0,115200,230400,403200,460800,
806400,921600,1572864,3145728 at 0xffffffff80d99240, and the 4 bytes at
+36 (divisors[9]) = 0x00000000 followed by zero padding -- the OOB load
reads 0 in this link, and the runtime instrumentation (scenario 1,
oob_dword=0x00000000) confirms the same value in the booted kernel.
Stock -O2 codegen (adjacency.txt, disassembly of the gcc8-generated
umcs7840_calc_baudrate.part.0): the loop-exhausted path (rate==0) is
compiled to
+0x33: xor %eax,%eax ; return 0 (success)
+0x35: mov $0xffffff80,%r8d ; clk = 8<<4
+0x3b: mov %ax,(%rsi) ; *divisor = 0
... mov %r8b,(%r9) ; *clk = 0x80
ret
with NEITHER the divisors[9] load NOR the division executed: gcc8
exploited the divide-by-zero UB. The only `div %edi` sits in the
bucket-found path where rate > divisors[i] >= 0, i.e. rate != 0.
Consequence on the shipping binary: pre_param(0) -> calc "succeeds"
with *divisor=0 -> `|| !divisor` -> EINVAL; no panic (run1.log,
two independent -O2 builds).