The diff below fixes a uvm fault I'm seeing when booting an MP kernel on a
hp bc2500 blade, somewhere during acpi attach.  SP kernels don't crash, but
I think that's down to luck.  It looks like this:

ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 21, 24 pins
acpimcfg0 at acpi0 addr 0xe0000000, bus 0-64
acpihpet0 at acpi0: 14318180 Hz
uvm_fault(0xffffffff818c5860, 0xffff800000063000, 0, 1) -> e
kernel: page fault trap, code=0
Stopped at      memcpy+0xa:     repe movsq      (%rsi),%es:(%rdi)
memcpy() at memcpy+0xa
aml_rwfield() at aml_rwfield+0x205
aml_store() at aml_store+0x1eb
aml_parse() at aml_parse+0xf4c
aml_eval() at aml_eval+0x1c8
aml_parse() at aml_parse+0x183d
aml_eval() at aml_eval+0x1c8
aml_evalnode() at aml_evalnode+0x74
acpi_inidev() at acpi_inidev+0x57
aml_find_node() at aml_find_node+0x92
end trace frame: 0xffffffff81a1eab0, count: 0

This turns out to be because aml_rwgas doesn't do bounds checking on source
buffers.

_SB.PCI0._INI (evaluated in acpi_inidev) tries to figure out what OS is
running.  The method it calls to do this creates a temporary buffer:

            Name (STR0, Buffer (0x50) {})

that it copies some lies into, like "Microsoft Windows Vista", then copies that
somewhere else:

            WMIB = STR0 /* \OSFG.STR0 */

where WMIB is:

    OperationRegion (HABS, SystemMemory, HBIO, HBSZ)
    Field (HABS, AnyAcc, NoLock, Preserve)
    {
        WMIB,   33280, 

which is a fair bit bigger than the STR0 buffer.  aml_rwgas tries to read all
33280 bits from STR0 anyway, which obviously leads to crashes.

I've tested the fix on several machines running amd64 and i386 and nothing
breaks as far as I can tell.

oks, more tests, etc.?

Index: dsdt.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
retrieving revision 1.216
diff -u -p -u -p -r1.216 dsdt.c
--- dsdt.c      16 Mar 2015 20:31:46 -0000      1.216
+++ dsdt.c      28 Mar 2015 11:57:07 -0000
@@ -2286,6 +2286,9 @@ aml_rwgas(struct aml_value *rgn, int bpo
                } else {
                        /* Write to a large field.. create or convert buffer */
                        val = aml_convert(val, AML_OBJTYPE_BUFFER, -1);
+
+                       if (blen > (val->length << 3))
+                               blen = val->length << 3;
                }
                vbit = val->v_buffer;
        } else {

Reply via email to