Skip to content

About

The tool to read/get/extract and write/change/modify BIOS/UEFI settings from Linux terminal.

Topics

Resources

Code of conduct

Contributing

Stars

103 stars

Watchers

13 watching

Forks

Repository files navigation

uefisettings

About

uefisettings is a tool to read and write BIOS settings on a local host. It currently supports two interfaces:

  • HiiDB (used in OCP and also has partial support in other platforms)
  • iLO BlobStore (used in HPE)

Install

cargo install uefisettings

Build manually

cd /tmp
git clone https://github.com/linuxboot/uefisettings
cd uefisettings
cargo install --path .
~/.cargo/bin/uefisettings --help

Usage examples

Reset TPM

uefisettings hii set 'Pending operation' 'TPM Clear'

Check if TXT is enabled

if [[ "$(uefisettings hii get --json 'Enable Intel(R) TXT' | jq -r '.responses | .[].question.answer')" = "Enable" ]]; then
    # Do something if TXT is enabled
fi

Available commands

Commands:
  get                Auto-identify backend and get the current value of a question
  help               Print this message or the help of the given subcommand(s)
  hii                Commands which work on machines exposing the UEFI HiiDB
  identify           Auto-identify backend and display hardware/bios-information
  ilo                Commands which work on machines having HPE's Ilo BMC
  set                Auto-identify backend and set/change the value of a question
  show-translations  Show the translation/spellings database for questions and answers

hii:

Commands:
  dump-efivars    Copy the HiiDB and the EFI variables that its questions read into a new directory,
                  for --efivars on another machine
  extract-db      Dump HiiDB into a file
  get             Get the current value of a question
  help            Print this message or the help of the given subcommand(s)
  list-questions  List questions HiiDB. Note that these are not all possible questions, because we
                  don't parse certain non-useful question types
  list-strings    List all strings-id, string pairs in HiiDB
  set             Set/change the value of a question
  show-ifr        Show a human readable representation of the Hii Forms

ilo:

Commands:
  get                      Get the current value of a question
  help                     Print this message or the help of the given subcommand(s)
  set                      Set/change the value of a question
  show-attributes          List bios attributes and their current values
  show-pending-attributes  List all pending changes that will take effect after reboot

In the UEFI Shell

uefisettings.efi runs get, set, show-translations and the hii commands but extract-db and dump-efivars in the UEFI Shell, before an OS boots; it also reaches boot-service-only variables, and has no -f or --efivars.

rustup target add x86_64-unknown-uefi  # or i686-unknown-uefi, aarch64-unknown-uefi
cargo build --release --target x86_64-unknown-uefi
FS0:\> uefisettings.efi hii get --json "Activate this check box"

Exit statuses, setup passwords, hii variable-info and Secure Boot: see the appendix.


Changing UEFI settings with automation

To change BIOS settings from Linux terminal there are usually next ways available:

  • On Open Compute Project hardware - read/parse a binary database called Hii (defined in the UEFI spec) and manipulate binary files in the /sys file system to change settings. This approach may also work on some non-OCP consumer hardware like your laptops.
  • On Hewlett Packard Enterprise hardware - use HPE's redfish API to read/write settings. This requires the presence of HPE's iLO BMC.
  • Use different proprietary tools like SCELNX from AMI or conrep from HPE. However, these require additional kernel modules to be loaded.

But this tool is an unified opensource approach to manipulate UEFI settings on any platform.


How it works

For OCP hardware

  • Extract HiiDB from /dev/mem after getting offsets from efivarfs.
  • Library (hii) in Rust partially implements the UEFI Hii specification.
  • It parses the HiiDB op-codes into a DOM tree like representation which can be read by machines and humans.
  • It can ask questions about UEFI settings from HiiDB and get their answers.
  • get, set and hii list-questions evaluate the suppressif, grayoutif and disableif conditions of questions as EDK2's setup browser does, and select only questions that none of them suppresses, grays out or disables, unless --include names that state (grayed-out, suppressed, disabled); an answer ends with the state of a question that is not selectable. Where a condition cannot be evaluated from Linux, set refuses the question, while get and hii list-questions show it with the states it may be in and why. A one-of option in a suppressif counts as suppressed.
  • Change UEFI settings by calculating the correct offsets and writing to entries in efivarfs.

For HPE hardware

  • Unlike OCP Hardware, HPE does not expose HiiDB in efivarfs.
  • Instead they provide a way to change UEFI settings via iLO using the Redfish API.
  • Redfish can be consumed over:
    • Standard networking protocols like TCP but this requires authentication credentials and network access to the BMC.
    • By accessing /dev/hpilo directly. This doesn't require authentication credentials. HPE doesn't provide any documentation for this approach but they provide an opensource ilorest CLI tool which calls a closed-source dynamically loaded shared object library called ilorest_chif.so which does the magic. The transport method used here instead of TCP is called Blobstore2.
  • We are forbidden from disassembling ilorest_chif.so but we figured out most of its function signatures by looking at Apache2-licensed HPE's python ilorest CLI tool which calls it.
  • Blobstore2 communication logic and rust bindings to ilorest_chif.so are implemented in the ilorest library. Feel free to use opensource implementation instead of ilorest_chif.so to avoid license problems.

The opensource ilorest study results are published in doc/ilorest.md.


Update Thrift files

If one needs to update a file inside thrift directory then:

  1. Install fbthrift compiler: cargo install fbthrift_compiler && (sudo dnf install -y fbthrift || sudo apt install -y fbthrift)
  2. Update the .thrift file.
  3. Run ~/.cargo/bin/compiler path/to/updated/file.thrift.
  4. Run mv lib.rs path/to/generated/rust/file.rs.

For example:

# Install fbthrift compiler
cargo install fbthrift_compiler
sudo dnf install -y fbthrift

# Update file
vi thrift/uefisettings_spellings_db.thrift

# Re-generate the rust file from the thrift file.
cargo install fbthrift_compiler
~/.cargo/bin/compiler thrift/uefisettings_spellings_db.thrift
mv lib.rs thrift/rust/uefisettings_spellings_db_thrift/uefisettings_spellings_db.rs

Checks

The Makefile in the root of the repository runs the checks that a change should pass: the lints (make lint: rustfmt, clippy for x86_64, aarch64, i686 and UEFI, and the docs), the tests (make test, and make test-i686 on 32-bit glibc) and the QEMU tests (make test-e2e-qemu).

The checks need GNU make and bash, and rustup unless make RUST_TOOLCHAIN= runs them on the cargo of PATH.

make setup           # once: installs, through rustup, the Rust toolchain, components and targets of the checks
make                 # every check, stopping at the first that fails
make -k              # every check, even after one fails
make <check>...      # the named checks, e.g. make clippy-aarch64 doc
make lint test test-i686 # every check but the QEMU tests
make RUST_TOOLCHAIN= # the checks on the cargo of PATH
make help            # lists the checks

make test-i686 also needs an x86 host (x86_64 or i686), which runs the i686 test binaries, and gcc's 32-bit libraries (Ubuntu: gcc-multilib, or, next to the gcc-aarch64-linux-gnu of tests/qemu/ubuntu-packages, which conflicts with it, libc6-dev-i386 and lib32gcc-<gcc version>-dev; Fedora: glibc-devel.i686).

make test-e2e-qemu, the QEMU tests, also needs an x86_64 host with /dev/kvm and the packages that tests/qemu/README.md lists.

GitHub Actions runs the checks on every pull request and every push to main, as .github/workflows/checks.yml describes.

QEMU tests

End-to-end tests boot QEMU guests and run uefisettings against emulated firmware; tests/qemu/README.md explains how to run them.

Appendix

Inspecting a machine's settings elsewhere

hii dump-efivars copies the EFI variables that the HiiDB's questions read, so that hii get, hii list-questions and hii show-ifr can answer from them on another machine. The dump also holds the HiiDB, as hiidb.bin, and records its format and redaction in uefisettings-dump.json:

# on the machine to inspect
sudo uefisettings hii extract-db hiidb.bin
uefisettings hii dump-efivars -f hiidb.bin efivars
# on any machine
uefisettings hii list-questions --efivars efivars

extract-db reads the HiiDB from /dev/mem, which needs CAP_SYS_RAWIO. dump-efivars -f reads only efivarfs, whose files every user can read, so run it unprivileged: as root, it would leave a directory that only root can read.

Without -f, --efivars reads the HiiDB that the dump saved. A directory without uefisettings-dump.json holds plain efivar files, read with the HiiDB of -f or this machine.

The dump keeps the HiiDB whole, whose strings can name the machine (a MAC address, for one), and of each EFI variable only the bytes that questions decode unless --unredacted is given; even those can be secrets, so share it only with people you trust. A redacted dump zeroes every other byte, so --efivars refuses it with another HiiDB (-f), whose questions would read those zeros as values; a later uefisettings that decodes more reads them as values too.

Never copy a dump into /sys/firmware/efi/efivars: its files are in efivarfs's write format, so they would create absent variables and overwrite writable ones, such as BootOrder and Timeout.

AMI Setup access level

AMI firmware's Setup grays out or hides some questions by the access level of its session, which it keeps in the VarStore SystemAccess (E770BB69-BCB4-4D04-9E97-23FF9456FEAC: 0 Administrator, 1 User). Where Linux cannot read that variable, those questions are undetermined, and set refuses them unless --include selects their states, such as grayed-out. --access-level administrator|user, on get, set, hii get, hii set and hii list-questions, evaluates those conditions at the stated level instead, and fails on a HiiDB that declares no SystemAccess:

uefisettings hii list-questions --access-level administrator

--access-level changes no variable: the questions on SystemAccess itself still answer with its stored value, or why it cannot be read.

uefisettings never takes, checks or circumvents a firmware password, because UEFI variable writes carry none. With an Administrator password installed, administrator lets root select from the OS the questions that the firmware's Setup reserves for Administrator sessions, as --include grayed-out already does more broadly.

UEFI Shell details

A failing command returns EFI_ABORTED, which %lasterror% shows as 0x15 (0x80000015 on i686).

Questions never read a VarStore that a password question names: they show <ValueUnavailable: VarStore holds a password>, and set refuses them. The UEFI Shell runs no setup browser, so nothing there asks for or checks a setup password: in a HiiDB that declares a password question, set writes nothing unless --bypass-setup-password is given.

hii variable-info NAME GUID, of this build only, prints the attributes bitmask and the data size of an EFI variable, but never its data, such as of AMI firmware's AMITSESetup. It prints them as a JSON object of its own, outside the thrift IDL of the other commands, with no -j:

FS0:\> uefisettings.efi hii variable-info AMITSESetup C811FA38-42C8-4579-A9BB-60E94EDDFB34

With Secure Boot enabled, the firmware starts an image only if its signature database (db) holds the certificate of its signature or its hash, so sign uefisettings.efi with a key that the machine's db trusts.

About

The tool to read/get/extract and write/change/modify BIOS/UEFI settings from Linux terminal.

Topics

Resources

Code of conduct

Contributing

Stars

103 stars

Watchers

13 watching

Forks

Releases

Packages

Used by

Contributors

Languages