https://mjg59.dreamwidth.org/63787.html
Account name: [ ] Password [ ] [Log in]
(OpenID?) (Forgot it?) [ ] Remember Me
You're viewing [personal profile] mjg59's journal
Create a Dreamwidth Account Learn More
[ ] [Interest ] [Go]
Reload page in style: site light
Matthew Garrett
Changing firmware config that doesn't want to be changed
Changing firmware config that doesn't want to be changed
Jan. 4th, 2023 07:52 pm
[personal profile] mjg59
Today I had to deal with a system that had an irritating restriction
- a firmware configuration option I really wanted to be able to
change appeared as a greyed out entry in the configuration menu. Some
emails revealed that this was a deliberate choice on the part of the
system vendor, so that seemed to be that. Thankfully in this case
there was a way around that.
One of the things UEFI introduced was a mechanism to generically
describe firmware configuration options, called Visual Forms
Representation (or VFR). At the most straightforward level, this lets
you define a set of forms containing questions, with each question
associated with a value in a variable. Questions can be made
dependent upon the answers to other questions, so you can have
options that appear or disappear based on how other questions were
answered. An example in this language might be something like:
CheckBox Prompt: "Console Redirection", Help: "Console Redirection
Enable or Disable.", QuestionFlags: 0x10, QuestionId: 53, VarStoreId:
1, VarStoreOffset: 0x39, Flags: 0x0
In which question 53 asks whether console redirection should be
enabled or disabled. Other questions can then rely on the answer to
question 53 to influence whether or not they're relevant (eg, if
console redirection is disabled, there's no point in asking which
port it should be redirected to). As a checkbox, if it's set then the
value will be set to 1, and 0 otherwise. But where's that stored?
Earlier we have another declaration:
VarStore GUID: EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9, VarStoreId: 1,
Size: 0xF4, Name: "Setup"
A UEFI variable called "Setup" and with GUID
EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9 is declared as VarStoreId 1
(matching the declaration in the question) and is 0xf4 bytes long.
The question indicates that the offset for that variable is 0x39.
Rewriting Setup-EC87D643-EBA4-4BB5-A1E5-3F3E36B20DA9 with a modified
value in offset 0x39 will allow direct manipulation of the config
option.
But how do we get this data in the first place? VFR isn't built into
the firmware directly - instead it's turned into something called
Intermediate Forms Representation, or IFR. UEFI firmware images are
typically in a standardised format, and you can use UEFITool to
extract individual components from that firmware. If you use UEFITool
to search for "Setup" there's a good chance you'll be able to find
the component that implements the setup UI. Running IFRExtractor-RS
against it will then pull out any IFR data it finds, and decompile
that into something resembling the original VFR. And now you have the
list of variables and offsets and the configuration associated with
them, even if your firmware has chosen to hide those options from
you.
Given that a bunch of these config values may be security relevant,
this seems a little concerning - what stops an attacker who has
access to the OS from simply modifying these variables directly? UEFI
avoids this by having two separate stages of boot, one where the full
firmware ("Boot Services") is available, and one where only a subset
("Runtime Services") is available. The transition is triggered by the
OS calling ExitBootServices, indicating the handoff from the firmware
owning the hardware to the OS owning the hardware. This is also
considered a security boundary - before ExitBootServices everything
running has been subject to any secure boot restrictions, and
afterwards applications can do whatever they want. UEFI variables can
be flagged as being visible in both Boot and Runtime Services, or can
be flagged as Boot Services only. As long as all the security
critical variables are Boot Services only, an attacker should never
be able to run untrusted code that could alter them.
In my case, the firmware option I wanted to alter had been enclosed
in "GrayOutIf True" blocks. But the questions were still defined and
the code that acted on those options was still present, so simply
modifying the variables while still inside Boot Services gave me what
I wanted. Note that this isn't a given! The presence of configuration
options in the IFR data doesn't mean that anything will later
actually read and make use of that variable - a vendor may have
flagged options as unavailable and then removed the code, but never
actually removed the config data. And also please do note that the
reason stuff was removed may have been that it doesn't actually work,
and altering any of these variables risks bricking your hardware in a
way that's extremely difficult to recover. And there's also no
requirement that vendors use IFR to describe their configuration, so
you may not get any help here anyway.
In summary: if you do this you may break your computer. If you don't
break your computer, it might not work anyway. I'm not going to help
you try to break your computer. And I didn't come up with any of
this, I just didn't find it all written down in one place while I was
researching it.
Tags:
* advogato,
* fedora
* Previous Entry
* Add Memory
* Share This Entry
* Next Entry
---------------------------------------------------------------------
* 2 comments
* Reply
---------------------------------------------------------------------
Flat | Top-Level Comments Only
Hii DB
Date: 2023-01-05 03:33 pm (UTC)
noodles: (Default)
From: [personal profile] noodles
Instead of dumping system firmware some machines will export the
HiiDB; the HiiDB-1b838190-4625-4ead-abc9-cd5e6af18fe0 EFI variable
gives an address/size that can be mapped which you can then parse the
Human Interface Infrastructure details out of. And poke changes back
in. It's an absolutely horrible way to reconfigure BIOS settings in a
programmatic way, but in some situations it's the best structured way
of doing so.
(Exporting this data cleanly from the kernel rather than having to
mmap /dev/mem is on my todo list, but in a typical programming
fashion the main question I have is where that information should
actually be exported to.)
* Link
* Reply
Thanks!
Date: 2023-01-06 04:32 pm (UTC)
From: (Anonymous)
Thanks for researching and showing me new ways to brick my computer ;
-)
* Link
* Reply
* Previous Entry
* Add Memory
* Share This Entry
* Next Entry
* 2 comments
* Reply
Flat | Top-Level Comments Only
Profile
Matthew Garrett
About Matthew
Power management, mobile and firmware developer on Linux. Security
developer at Aurora. Ex-biologist. [personal profile] mjg59 on
Twitter. Content here should not be interpreted as the opinion of my
employer. Also on Mastodon.
Page Summary
* [personal profile] noodles - Hii DB
* (Anonymous) - Thanks!
Expand Cut Tags
No cut tags
Top of page