summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/mainboard/index.md1
-rw-r--r--Documentation/mainboard/lenovo/ivb_bios_flashing1.jpgbin0 -> 62320 bytes
-rw-r--r--Documentation/mainboard/lenovo/ivb_bios_flashing2.jpgbin0 -> 58984 bytes
-rw-r--r--Documentation/mainboard/lenovo/ivb_bios_legacy_only.jpgbin0 -> 64404 bytes
-rw-r--r--Documentation/mainboard/lenovo/ivb_bios_uefi_only.jpgbin0 -> 63883 bytes
-rw-r--r--Documentation/mainboard/lenovo/ivb_internal_flashing.md372
6 files changed, 373 insertions, 0 deletions
diff --git a/Documentation/mainboard/index.md b/Documentation/mainboard/index.md
index a0436afb1f..ce30ee2f1c 100644
--- a/Documentation/mainboard/index.md
+++ b/Documentation/mainboard/index.md
@@ -92,6 +92,7 @@ The boards in this section are not real mainboards, but emulators.
- [W530](lenovo/w530.md)
- [T430 / T530 / X230 / W530 common](lenovo/xx30_series.md)
- [T431s](lenovo/t431s.md)
+- [Internal flashing](lenovo/ivb_internal_flashing.md)
### Haswell series
diff --git a/Documentation/mainboard/lenovo/ivb_bios_flashing1.jpg b/Documentation/mainboard/lenovo/ivb_bios_flashing1.jpg
new file mode 100644
index 0000000000..10a27b08e3
--- /dev/null
+++ b/Documentation/mainboard/lenovo/ivb_bios_flashing1.jpg
Binary files differ
diff --git a/Documentation/mainboard/lenovo/ivb_bios_flashing2.jpg b/Documentation/mainboard/lenovo/ivb_bios_flashing2.jpg
new file mode 100644
index 0000000000..4be1101e5f
--- /dev/null
+++ b/Documentation/mainboard/lenovo/ivb_bios_flashing2.jpg
Binary files differ
diff --git a/Documentation/mainboard/lenovo/ivb_bios_legacy_only.jpg b/Documentation/mainboard/lenovo/ivb_bios_legacy_only.jpg
new file mode 100644
index 0000000000..aef9c7bfb1
--- /dev/null
+++ b/Documentation/mainboard/lenovo/ivb_bios_legacy_only.jpg
Binary files differ
diff --git a/Documentation/mainboard/lenovo/ivb_bios_uefi_only.jpg b/Documentation/mainboard/lenovo/ivb_bios_uefi_only.jpg
new file mode 100644
index 0000000000..7def81ed82
--- /dev/null
+++ b/Documentation/mainboard/lenovo/ivb_bios_uefi_only.jpg
Binary files differ
diff --git a/Documentation/mainboard/lenovo/ivb_internal_flashing.md b/Documentation/mainboard/lenovo/ivb_internal_flashing.md
new file mode 100644
index 0000000000..d0ac3cdd79
--- /dev/null
+++ b/Documentation/mainboard/lenovo/ivb_internal_flashing.md
@@ -0,0 +1,372 @@
+# Ivy Bridge Lenovo ThinkPad Internal Flashing
+
+## Introduction
+
+Old versions of stock BIOS for these models have several security issues.
+In order to flash coreboot internally, two of them are of interest.
+
+**First** is the fact the SMM_BWP and BLE are not enabled in BIOS
+versions released before 2014. We have tested many versions on T430 and
+X230 and found out that SMM_BWP=1 only since the update, the changelog
+of which contains following line:
+
+> (New) Improved the UEFI BIOS security feature.
+
+**Second** is [S3 Boot Script vulnerability](https://support.lenovo.com/eg/ru/product_security/s3_boot_protect),
+that was discovered and fixed later.
+
+## Requirements
+
+- USB drive (in case you need to downgrade BIOS)
+- Linux install that (can be) loaded in UEFI mode
+- [CHIPSEC](https://github.com/chipsec/chipsec)
+
+## BIOS versions
+
+Below is a table of BIOS versions that are vulnerable enough for our
+goals, per model. The version number means that you need to downgrade to
+that or earlier version.
+
+```eval_rst
++------------+--------------+
+| Model | BIOS version |
++============+==============+
+| X230 | 2.60 |
++------------+--------------+
+| X230T | 2.58 |
++------------+--------------+
+| T430 | 2.64 |
++------------+--------------+
+| T430s | 2.59 |
++------------+--------------+
+| T530 | 2.60 |
++------------+--------------+
+| W530 | 2.58 |
++------------+--------------+
+```
+
+If your BIOS version is equal or lower, skip to the
+**[Examining protections](#examining-protections-theory)** section. If not,
+go through the downgrade process, described next.
+
+## Downgrading BIOS
+
+Go to the Lenovo web site and download BIOS Update Bootable CD for your
+machine of needed version (see above).
+
+Lenovo states that BIOS has "security rollback prevention", meaning once
+you update it to some version X, you will not be able to downgrade it to
+pre-X version. That's not true. It seems that this is completely
+client-side restriction in flashing utilities (both Windows utility and
+Bootable CD). You just need to call `winflash.exe` or `dosflash.exe`
+directly. Therefore you need to modify the bootable CD image you just
+downloaded.
+
+Extract an El Torito image:
+```
+geteltorito -o ./bios.img g1uj41us.iso
+```
+Mount the partition in that image:
+```
+sudo mount -t vfat ./bios.img /mnt -o loop,offset=16384
+```
+List files, find the `AUTOEXEC.BAT` file and the `FLASH` directory:
+```
+ls /mnt
+ls /mnt/FLASH
+```
+
+Inside the `FLASH` directory, there should be a directory called
+`G1ET93WW` or similar (exact name depends on your ThinkPad model and
+BIOS version). See what's inside:
+```
+ls /mnt/FLASH/G1ET93WW
+```
+There must be a file with `.FL1` extension called `$01D2000.FL1` or
+something similar.
+
+Now open the `AUTOEXEC.BAT` file:
+```
+sudo vim /mnt/AUTOEXEC.BAT
+```
+You will see a list of commands:
+```
+@ECHO OFF
+PROMPT $p$g
+cd c:\flash
+command.com
+```
+Replace the last line (`command.com`) with this (change path to the
+`.FL1` file according to yours):
+```
+dosflash.exe /sd /file G1ET93WW\$01D2000.FL1
+```
+
+Save the file, then unmount the partition:
+```
+sudo unmount /mnt
+```
+
+Write this image to a USB drive (replace `/dev/sdX` with your USB drive
+device name):
+```
+sudo dd if=./bios.img of=/dev/sdX bs=1M
+```
+
+Now reboot and press F1 to enter BIOS settings. Open the **Startup** tab
+and set the startup mode to **Legacy** (or **Both**/**Legacy First**):
+
+![](ivb_bios_legacy_only.jpg)
+
+Press F10 to save changes and reboot.
+
+Now, before you process, make sure that AC adapter is connected! If your
+battery will die during the process, you'll likely need external
+programmer to recover.
+
+Boot from the USB drive (press F12 to select boot device), and BIOS
+flashing process should begin:
+
+![](ivb_bios_flashing1.jpg)
+
+![](ivb_bios_flashing2.jpg)
+
+It may reboot a couple of times in the process. Do not interrupt it.
+
+When it's completed, go back to the BIOS settings and set startup mode
+to **UEFI** (or **Both**/**UEFI First**). This is required for
+vulnerability exploitation.
+
+![](ivb_bios_uefi_only.jpg)
+
+Then boot to your system and make sure that `/sys/firmware/efi` or
+`/sys/firmware/efivars` exist.
+
+## Examining protections (theory)
+
+There are two main ways that Intel platform provides to protect BIOS
+chip:
+- **BIOS_CNTL** register of LPC Interface Bridge Registers (accessible
+ via PCI configuration space, offset 0xDC). It has:
+ * **SMM_BWP** (*SMM BIOS Write Protect*) bit. If set to 1, the BIOS is
+ writable only in SMM. Once set to 1, cannot be changed anymore.
+ * **BLE** (*BIOS Lock Enable*) bit. If set to 1, setting BIOSWE to 1
+ will raise SMI. Once set to 1, cannot be changed anymore.
+ * **BIOSWE** (*BIOS Write Enable*) bit. Controls whether BIOS is
+ writable. This bit is always R/W.
+- SPI Protected Range Registers (**PR0**-**PR4**) of SPI Configuration
+ Registers (SPIBAR+0x74 - SPIBAR+0x84). Each register has bits that
+ define protected range, plus WP bit, that defines whether write
+ protection is enabled.
+
+ There's also **FLOCKDN** bit of HSFS register (SPIBAR+0x04) of SPI
+ Configuration Registers. When set to 1, PR0-PR4 registers cannot be
+ written. Once set to 1, cannot be changed anymore.
+
+To be able to flash, we need SMM_BWP=0, BIOSWE=1, BLE=0, FLOCKDN=0 or
+SPI protected ranges (PRx) to have a WP bit set to 0.
+
+Let's see what we have. Examine HSFS register:
+```
+sudo chipsec_main -m chipsec.modules.common.spi_lock
+```
+You should see that FLOCKDN=1:
+```
+[x][ =======================================================================
+[x][ Module: SPI Flash Controller Configuration Locks
+[x][ =======================================================================
+[*] HSFS = 0xE009 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4)
+ [00] FDONE = 1 << Flash Cycle Done
+ [01] FCERR = 0 << Flash Cycle Error
+ [02] AEL = 0 << Access Error Log
+ [03] BERASE = 1 << Block/Sector Erase Size
+ [05] SCIP = 0 << SPI cycle in progress
+ [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status
+ [14] FDV = 1 << Flash Descriptor Valid
+ [15] FLOCKDN = 1 << Flash Configuration Lock-Down
+```
+
+Then check BIOS_CNTL and PR0-PR4:
+```
+sudo chipsec_main -m common.bios_wp
+```
+Good news: on old BIOS versions, SMM_BWP=0 and BLE=0.
+
+Bad news: there are 4 write protected SPI ranges:
+
+```
+[x][ =======================================================================
+[x][ Module: BIOS Region Write Protection
+[x][ =======================================================================
+[*] BC = 0x 8 << BIOS Control (b:d.f 00:31.0 + 0xDC)
+ [00] BIOSWE = 0 << BIOS Write Enable
+ [01] BLE = 0 << BIOS Lock Enable
+ [02] SRC = 2 << SPI Read Configuration
+ [04] TSS = 0 << Top Swap Status
+ [05] SMM_BWP = 0 << SMM BIOS Write Protection
+[-] BIOS region write protection is disabled!
+
+[*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF
+SPI Protected Ranges
+------------------------------------------------------------
+PRx (offset) | Value | Base | Limit | WP? | RP?
+------------------------------------------------------------
+PR0 (74) | 00000000 | 00000000 | 00000000 | 0 | 0
+PR1 (78) | 8BFF0B40 | 00B40000 | 00BFFFFF | 1 | 0
+PR2 (7C) | 8B100B10 | 00B10000 | 00B10FFF | 1 | 0
+PR3 (80) | 8ADE0AD0 | 00AD0000 | 00ADEFFF | 1 | 0
+PR4 (84) | 8AAF0800 | 00800000 | 00AAFFFF | 1 | 0
+```
+
+Other way to examine SPI configuration registers is to just dump SPIBAR:
+```
+sudo chipsec_util mmio dump SPIBAR
+```
+You will see SPIBAR address (0xFED1F800) and registers (for example,
+00000004 is HSFS):
+```
+[mmio] MMIO register range [0x00000000FED1F800:0x00000000FED1F800+00000200]:
++00000000: 0BFF0500
++00000004: 0004E009
+...
+```
+As you can see, the only thing we need is to unset WP bit on PR0-PR4.
+But that cannot be done once FLOCKDN is set to 1.
+
+Now the fun part!
+
+FLOCKDN may only be cleared by a hardware reset, which includes S3
+state. On S3 resume boot path, the chipset configuration has to be
+restored and it's done by executing so-called S3 Boot Scripts. You can
+dump these scripts by executing:
+```
+sudo chipsec_util uefi s3bootscript
+```
+There are many entries. Along them, you can find instructions to write
+to HSFS (remember, we know that SPIBAR is 0xFED1F800):
+```
+Entry at offset 0x2B8F (len = 0x17, header len = 0x0):
+Data:
+02 00 17 02 00 00 00 01 00 00 00 04 f8 d1 fe 00 |
+00 00 00 09 e0 04 00 |
+Decoded:
+ Opcode : S3_BOOTSCRIPT_MEM_WRITE (0x0002)
+ Width : 0x02 (4 bytes)
+ Address: 0xFED1F804
+ Count : 0x1
+ Values : 0x0004E009
+```
+These scripts are stored in memory. The vulnerability is that we can
+overwrite this memory, change these instructions and they will be
+executed on S3 resume. Once we patch that instruction to not set FLOCKDN
+bit, we will be able to write to PR0-PR4 registers.
+
+## Creating a backup
+
+Before you proceed, please create a backup of the `bios` region. Then,
+in case something goes wrong, you'll be able to flash it back externally.
+
+The `me` region is locked, so an attempt to create a full dump will fail.
+But you can back up the `bios`:
+```
+sudo flashrom -p internal -r bios_backup.rom --ifd -i bios
+```
+
+If you will ever need to flash it back, use `--ifd -i bios` as well:
+```
+sudo flashrom -p <YOUR_PROGRAMMER> -w bios_backup.rom --ifd -i bios
+```
+**Caution:** if you will omit `--ifd -i bios` for flashing, you will
+brick your machine, because your backup has `FF`s in place of `fd` and
+`me` regions. Flash only `bios` region!
+
+## Removing protections (practice)
+
+The original boot script writes 0xE009 to HSFS. FLOCKDN is 15th bit, so
+let's write 0x6009 instead:
+```
+sudo chipsec_main -m tools.uefi.s3script_modify -a replace_op,mmio_wr,0xFED1F804,0x6009,0x2
+```
+You will get a lot of output and in the end you should see something
+like this:
+```
+[*] Modifying S3 boot script entry at address 0x00000000DAF49B8F..
+[mem] 0x00000000DAF49B8F
+[*] Original entry:
+ 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 |
+ 0 0 0 9 e0 4 0 |
+[mem] buffer len = 0x17 to PA = 0x00000000DAF49B8F
+ 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 |
+ 0 0 0 9 60 0 0 | `
+[mem] 0x00000000DAF49B8F
+[*] Modified entry:
+ 2 0 17 2 0 0 0 1 0 0 0 4 f8 d1 fe 0 |
+ 0 0 0 9 60 0 0 | `
+[*] After sleep/resume, check the value of register 0xFED1F804 is 0x6009
+[+] PASSED: The script has been modified. Go to sleep..
+```
+Now go to S3, then resume and check FLOCKDN. It should be 0:
+```
+sudo chipsec_main -m chipsec.modules.common.spi_lock
+```
+```
+...
+[x][ =======================================================================
+[x][ Module: SPI Flash Controller Configuration Locks
+[x][ =======================================================================
+[*] HSFS = 0x6008 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4)
+ [00] FDONE = 0 << Flash Cycle Done
+ [01] FCERR = 0 << Flash Cycle Error
+ [02] AEL = 0 << Access Error Log
+ [03] BERASE = 1 << Block/Sector Erase Size
+ [05] SCIP = 0 << SPI cycle in progress
+ [13] FDOPSS = 1 << Flash Descriptor Override Pin-Strap Status
+ [14] FDV = 1 << Flash Descriptor Valid
+ [15] FLOCKDN = 0 << Flash Configuration Lock-Down
+[-] SPI Flash Controller configuration is not locked
+[-] FAILED: SPI Flash Controller not locked correctly.
+...
+```
+Remove WP from protected ranges:
+```
+sudo chipsec_util mmio write SPIBAR 0x74 0x4 0xAAF0800
+sudo chipsec_util mmio write SPIBAR 0x78 0x4 0xADE0AD0
+sudo chipsec_util mmio write SPIBAR 0x7C 0x4 0xB100B10
+sudo chipsec_util mmio write SPIBAR 0x80 0x4 0xBFF0B40
+```
+Verify that it worked:
+```
+sudo chipsec_main -m common.bios_wp
+```
+```
+[x][ =======================================================================
+[x][ Module: BIOS Region Write Protection
+[x][ =======================================================================
+[*] BC = 0x 9 << BIOS Control (b:d.f 00:31.0 + 0xDC)
+ [00] BIOSWE = 1 << BIOS Write Enable
+ [01] BLE = 0 << BIOS Lock Enable
+ [02] SRC = 2 << SPI Read Configuration
+ [04] TSS = 0 << Top Swap Status
+ [05] SMM_BWP = 0 << SMM BIOS Write Protection
+[-] BIOS region write protection is disabled!
+
+[*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF
+SPI Protected Ranges
+------------------------------------------------------------
+PRx (offset) | Value | Base | Limit | WP? | RP?
+------------------------------------------------------------
+PR0 (74) | 0AAF0800 | 00800000 | 00AAF000 | 0 | 0
+PR1 (78) | 0ADE0AD0 | 00AD0000 | 00ADE000 | 0 | 0
+PR2 (7C) | 0B100B10 | 00B10000 | 00B10000 | 0 | 0
+PR3 (80) | 0BFF0B40 | 00B40000 | 00BFF000 | 0 | 0
+PR4 (84) | 00000000 | 00000000 | 00000000 | 0 | 0
+```
+
+Bingo!
+
+Now you can [flash internally](/flash_tutorial/int_flashrom.md).
+Remember to flash only the `bios` region (use `--ifd -i bios -N`
+flashrom arguments). `fd` and `me` are still locked.
+
+Note that you should have an external SPI programmer as a backup method.
+It will help you recover if you flash non-working ROM by mistake.