Issue #522 has been updated by Nico Huber.
Valerii Huhnin wrote in #note-14:
- What are well-formed regions?
- The last address of the region should be representable as a `size_t` value?
Definitely yes.
* The last address of the region +1 should be representable as a `size_t` value?
This won't be necessary and would only complicate the implementation. Everybody seems to agree that we don't want this.
* Regions should not have size 0 ?
There seems to be consensus that we don't need it (and it would also minimally complicate the implementation). Though, we should do some testing because it is hard to assess if any part of the code expects this to work.
- What functions can assume that regions are well-formed?
- region API functions?
- SMRAM overlap check functions?
- But for sure not the SMI handlers themselves?
We should check well-formedness before a `struct region` gets filled. Then any function using a struct region can assume that it's well formed.
- Where should we check if a region is well-formed?
- Create a dedicated function to check well-formdness of regions?
- Create a dedicated constructor function and check it there?
We should explicitly check for invalid regions whenever data comes from outside of coreboot. We still need to decide on one of these two options. In any case, invalid external data should be handled gracefully.
* Check it directly in region API functions?
We wouldn't want to do explicit error handling in every level of the API. IMO, an assert() in every public API function should suffice.
- What should we do if we encounter a non-well-formed region?
- Stop the execution?
- Try to treat it as well-formed (e.g. by ignoring addresses outside of `SIZE_MAX`) ?
- Other context-dependent handling?
I'd say depending on the context as described above.
Note: I also have a concern of the usage of the `size_t` type there. Shouldn't we actually use `uintptr_t`? Might there be problems when converting between this two?
They should be the same anyway. A `struct region` only sometimes describes a region in memory, so `uintptr_t` wouldn't always be right.
After looking at the `mainboard_smi_brigthness_down()` function I think that regions whose last address is non-representable as `size_t` is a problem on its own (independently from whether or not `region_overlap()` correctly detects overlap), as having such regions would later lead to an attempt of constructing a pointer that points outside of the address space.
This is true, but in this particular case, with the particular hardware, not a problem. The register should report 0 in the lower bits (except for the masked ones). This is also why the original overflow is hard to exploit with PCI BARs.
Maximilian Brune wrote in #note-15:
- Implement a specialized function that checks if the region is well-formed and returns a boolean value. I prefer this approach over ensuring well-formdness of regions in the constructor function because this would allow us to separate the well-formdness check itself from the handling of non-well-formed regions, which would also allow us to handle non-well-formed regions differently in different contexts if needed;
I agree. The constructor should be separate from the check of itself. That gives us the ability to check for sane values where it makes sense (SMM) and leave them out for the rest (we can't check for overflows everywhere in the code base).
I proposed two different constructors in [1]. One that asserts and one that checks and allows to handle an error. I would prefer this over a separate function as it would make it clear when the check needs to be performed. If every API user with untrusted input would have to do the same `if (check(base, size)) ...`, I don't see what we win. I don't mind if somebody wants to implement it like that though. The callers that use region_create_unstrusted() in [1] are those that I identified as needing a check.
[1] https://review.coreboot.org/c/coreboot/+/79905/
- Call the region well-formdness check function directly inside the SMI handlers before the smm_points_to_smram() check function;
Sounds good.
If they all go through smm_points_to_smram(), I would check there. Otherwise, the check could be missed on any new, future callers. That the region API is used that can overflow is also an implementation detail of smm_points_to_smram().
---------------------------------------- Bug #522: `region_overlap()` function might not work as expected due to an integer overflow in `region_end()` function. https://ticket.coreboot.org/issues/522#change-1753
* Author: Vadim Zaliva * Status: New * Priority: Normal * Category: coreboot common code * Target version: none * Start date: 2023-12-27 * Affected versions: master * Related links: https://review.coreboot.org/q/topic:enforce_region_api ---------------------------------------- `region_overlap()` function checks whether or not two memory regions overlap. Memory regions are represented as a region struct that contains the region's offset and size. This function then relies on `region_end()` function to compute the end of the region. `region_end()` function is susceptible to an integer overflow, which might result in the incorrect behaviour of `region_overlap()` function.
An example of inputs that lead to wrong behaviour: ``` struct region r1 = {SIZE_MAX - 10, 20}; struct region r2 = {SIZE_MAX - 20, 15}; ``` It returns 0, but since the regions actually overlap, it should return 1.
`region_overlap()` function is used in `smm_region_overlaps_handler()` function, which is itself used in SMI handlers to validate address values that come from an untrusted environment. This is necessary to prevent security vulnerabilities such as described in [BARing the System by Yuriy Bulygin, Oleksandr Bazhaniuk et al.](https://www.c7zero.info/stuff/REConBrussels2017_BARing_the_system.pdf)
We do not have an example of an exploit based on this incorrect behaviour and are aware of the existence of one. However, theoretically, this could lead to security vulnerabilities.
This bug was found during an ongoing [Coreboot Formal Verification Project](https://zaliva.org/UCSC-Twisted-Presentation-20231211.pdf), which aims to prove some important security properties of the coreboot’s SMI handler for the Gemini Lake/Octopus platform using Coq proof assistant and Verified Software Toolchain framework.
---Files-------------------------------- diff.txt (930 Bytes)