NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: install/49470
The following reply was made to PR port-amd64/49470; it has been noted by GNATS.
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: Andrius V <vezhlys%gmail.com@localhost>
Cc: gnats-bugs%NetBSD.org@localhost, netbsd-bugs%NetBSD.org@localhost
Subject: Re: install/49470
Date: Thu, 15 Aug 2024 23:10:35 +0000
> Date: Fri, 16 Aug 2024 00:50:03 +0300
> From: Andrius V <vezhlys%gmail.com@localhost>
>=20
> After many additional debugging sessions and big help from Taylor I
> narrowed down the issue to the bi_getmemmap() call, or more
> specifically to getmementry(&i, buf)
> (https://nxr.netbsd.org/xref/src/sys/arch/i386/stand/lib/biosmemx.S#87)
> This method invokes BIOS call and fills the buffer[5] with defined
> values. For some reason though, with ACPI 3.0 it actually seems to get
> 6 values,
> thus leading stack corruption (overflow(?)). The sixth value is always
> 1, and is set after each and every call.
> All other buf values [0-4] and number of iterations match completely
> the ones when ACPI 2.0 is set.
Amazing! Thanks for doing the work to dig into this!
With that clue, I poked around a little bit and found this fragment on
wiki.osdev.org:
`The format of an entry is 2 uint64_t's and a uint32_t in the 20
byte version, plus one additional uint32_t in the 24 byte ACPI 3.0
version.'
https://wiki.osdev.org/Detecting_Memory_(x86)#BIOS_Function:_INT_0x15,_E=
AX_=3D_0xE820
I looked at the page history to see where this came from, and found
that from 2008 when the page was first written until 2023(!), the text
read:
`The format of an entry is 2 uint64_t's and a uint32_t in the 20
byte version, plus one additional uint32_t in the 24 byte ACPI 3.0
version (but nobody has ever seen a 24 byte one).'
https://wiki.osdev.org/index.php?title=3DDetecting_Memory_(x86)&oldid=3D=
27401#BIOS_Function:_INT_0x15,_EAX_=3D_0xE820
The edit comment says: `I have found an bios that use 24 byte entrie
for int 0x15 function 0xe820'
This page was a rewrite of an earlier page, whose last edition says:
ACPI 3.0 notes
...
* A 32 bit set of flags ("Extended Attibutes") has been appended to
the end of the 20 byte structure, making it 24 bytes.
https://wiki.osdev.org/index.php?title=3DHow_Do_I_Determine_The_Amount_O=
f_RAM&oldid=3D4759#Counting_RAM_using_the_BIOS
I looked up INT 15h E820h in the ACPI 3.0 spec, and it says:
Table 14-2 Input to the INT 15h E820h Call
...
ES:DI Buffer Pointer Pointer to an Address Range Descriptor
structure that the BIOS fills in.
ECX Buffer Size The length in bytes of the structure
passed to the BIOS. The BIOS fills in
the number of bytes of the structure
indicated in the ECX register,
maximum, or whatever amount of the
structure the BIOS implements. The
minimum size that must be supported by
both the BIOS and the caller is 20
bytes. Future implementations might
extend this structure.
...
Table 14-4 Address Range Descriptor Structure
Offset Name Description
...
16 Type Address type of this range
20 Extended Attributes See Table 14-5
https://uefi.org/sites/default/files/resources/ACPI_3.pdf#page=3D404
So this ACPI 3.0 system is probably just ignoring the size we passed
in ecx (which is definitely 20, not 24!), which is rude, but there's
probably not much we can do to convince the firmware vendor to ship
updates to these decade-old laptops.
> Workaround can be allocating more memory to buf, for example setting
> buf size to 6 (buf[6]):
> https://nxr.netbsd.org/xref/src/sys/arch/i386/stand/lib/bootinfo_memmap.c=
#40
So yes, I think that is the correct thing to do here.
Now, the BIOS is obviously violating the rules here -- we passed in a
buffer size of 20 bytes, and it wrote out 24 bytes. In principle if
we wanted to hear about the extended attributes, we could also change
getmementry to set ecx=3D24, but that's a much riskier change.
(It might even be reasonable to make a struct out of this -- not
really sure why we use an array on the stack -- but refactoring this
isn't as important as avoiding the stack buffer overrun!)
So I suggest we just change `int buf[5]' to `int buf[6]' in:
- bi_getmemmap in bootinfo_memmap.c
- getextmemx in getextmemx.c
- the comment over getmementry in biosmemx.S
(and make sure there's no sizeof(buf) that changes).
We should also put a reference to all this bug, the relevant part of
the ACPI 3.0 spec, and the wiki.osdev.org page in comments so the next
person to stumble upon buf[6] doesn't change it back to buf[5] or
wonder what that extra word is doing!
Home |
Main Index |
Thread Index |
Old Index