ping

On Tue, Oct 11, 2022 at 07:21:29PM +0300, Sergii Dmytruk wrote:
> Hi again,
>
> As previously discussed on this ML, posting documentation inline for review.
>
> ================================================================================
>
> # Firmware updates vs. SPI write-protection
>
> Enabling write-protection of any kind is meant to obstruct changing data, but 
> it
> also limits what you can do to the part of firmware that's still writable. 
> This
> document is meant to cover some of the origins of such limitations and
> situations which might arise after part of a flash chip has been protected.
>
> ## Firmware updates after locking bootblock
>
> This section is primarily concerned with `coreboot`, but similar problems can
> happen for any kind of firmware.
>
> ### Risks of partial updates
>
> Partial updates can produce an unbootable image if an old bootblock doesn't 
> work
> with a more recent version of `coreboot`. This can be manifested in various
> ways ranging from an old bootblock not being able to find new romstage to 
> system
> booting successfully but data in `coreboot` tables being mangled or 
> incomplete.
>
> The incompatibilities might happen when switching version of firmware or even
> when using the same version with a slightly different configuration.
>
> Another thing that can potentially cause trouble is CBFS layout. When 
> bootblock
> is part of CBFS, it doesn't necessarily have a fixed address, moreover it can
> change location as well if it depends on file size (when bootblock's last byte
> must be the last byte of the image, which is the case on x86). If newer
> bootblock is smaller such that an old WP range now covers bootblock and some
> other file, this file won't be fully updated due to write-protection,
> potentially resulting in a corrupt image. Luckily, when bootblock is the last
> file it's normally preceded by a significant amount of empty space, which 
> won't
> let this situation to occur.
>
> On top of that, last 4 bytes of the image contain offset to the master header 
> of
> CBFS. Depending on the coreboot version this offset might be crucial for the
> loading of romstage, in which case moving CBFS within the image without 
> updating
> the offset (when it's locked by WP) can also prevent the system from booting.
>
> ### Recovering from a broken state
>
> Since broken flash won't let the system to boot, the way to fix it is to flash
> the chip externally by connecting it to a different device. A possible
> alternative could be to have a backup flash created beforehand and swapping it
> for the broken one (mainly applicable if swapping doesn't require soldering).
>
> ## Flashing whole firmware image
>
> The function of the hardware protection mechanism (`W#` or `W/` pin of flash
> chips) is to lock state of software protection thus preventing it from being
> disabled. After the chip is physically unlocked by changing the state of the
> pin, the state of the write protection doesn't change. However, in this state
> the protection can be easily turned off programmatically, which is what
> `flashrom` tries to do before performing an operation on a chip.
>
> In other words, changing state of the WP pin might be enough to be able to
> flash the chip in full. If `flashrom` errors or you don't want to rely on the
> automatic behaviour, you can try to explicitly disable the protection by 
> running
> `flashrom` like this:
>
> ```
> flashrom --wp-disable
> ```
>
> If you need to pass extra parameters to flash your chip (e.g., programmer or
> chip name), add them to the above command (order of such parameters shouldn't
> matter).
>
> Mind that in `flashrom` the code for disabling protection automatically is
> different from the code which handles `--wp-disable`. This means that they can
> sometimes produce different results, this is why you should be aware of both
> code paths that affect WP.
>
> ================================================================================
>
> # Example of partial write-protection
>
> This document provides demonstration of how one can protect part of a flash
> chip from writing using `flashrom` and its support for manipulating SPI write
> protection (WP). This kind of protection requires changing connection of WP
> pin of the chip to prevent any attempt of disabling the protection by software
> alone.
>
> **Not to be confused** with protection by flash controller of your
> motherboard (PCH protection).
>
> ## `flashrom` version
>
> At the time of writing (11 October 2022) there hasn't been a `flashrom` 
> release
> that includes WP manipulation facilities. You might have to build one from
> scratch (assuming you've already installed build dependencies):
>
> ```
> git clone --depth 1 https://github.com/flashrom/flashrom
> cd flashrom
> # the simplest case of building using GNU make
> make
> # flashrom executable will appear in current directory
> ```
>
> ## Programmer support of WP
>
> Not all programmers support manipulating WP configuration. A suitable
> programmer must either provide a dedicated API for working with WP or give
> sufficiently comprehensive access to the interface of the flash chip.
>
> In particular, on Intel platforms *internal* programmer might allow only 
> limited
> access to WP feature of chips or effectively deny it. Read "Intel chipsets"
> section of `flashrom`'s manpage for details on how you can try choosing
> sequencing type to possibly make WP work for you.
>
> In some cases external flashing might be the only option and you need to
> unscrew your device, find the chip, connect it to another device through a
> suitable adapter and finally be able to configure it as you wish.
>
> ## Chip support in `flashrom`
>
> There is a great variety of chips with some not supporting write protection at
> all and others doing it in their own peculiar way of which `flashrom` has no
> idea. So the first thing to do is to make sure that `flashrom` knows how WP
> works for your chip and chipset doesn't get in the way. Run a command like
> (adjust this and similar commands below if you're not using *internal*
> programmer or need to specify other options):
>
> ```
> flashrom --programmer internal --wp-status
> ```
>
> Seeing this output line would mean that `flashrom` doesn't know how to use WP
> feature of the chip you have:
>
> ```
> Failed to get WP status: WP operations are not implemented for this chip
> ```
>
> Otherwise the output might contain something similar to this:
>
> ```
> Protection range: start=0x00000000 length=0x00000000 (none)
> Protection mode: disabled
> ```
>
> If so, you can continue with the rest of the instructions.
>
> ## Collecting information about the range
>
> You need to know where the area you want to protect starts and ends. The 
> example
> below assumes you're trying to protect bootblock stored in CBFS at the end of
> some `coreboot` firmware. In other cases it might be a separate file which is
> put at the beginning of a chip. You need to have an idea of what you're doing
> here or have some reliable instructions to follow.
>
> In this case `cbfstool` can be used to list information about bootblock like
> this:
>
> ```
> $ cbfstool rom print | sed -n '2p; /bootblock/p'
> Name                           Offset     Type           Size   Comp
> bootblock                      0x3ef100   bootblock       36544 none
> ```
>
> However, the offset is relative to the start of CBFS region, so we also need 
> to
> find out offset of CBFS:
>
> ```
> $ cbfstool rom layout | grep CBFS
> 'COREBOOT' (CBFS, size 4161536, offset 12615680)
> ```
>
> Now we can calculate:
>
>  * start offset (CBFS offset + 64 + bootblock offset): \
>    `12615680 + 64 + 0x3ef100 = 0xff7140` \
>    (`printf "%#x\n" $(( 12615680 + 64 + 0x3ef100 ))`)
>  * end offset (start offset + bootblock size - 1): \
>    `0xff7140 + 36544 - 1 = 0xffffff` \
>    (`printf "%#x\n" $(( 0xff7140 + 36544 - 1 ))`)
>
> Thus we need to write-protect the smallest area that covers the range from
> `0xff7140` to `0xffffff` (both bounds are inclusive).
>
> "64" in the computation of start offset is offset of booblock data.
> Unfortunately, current tooling doesn't provide a reliable way of determining
> actual offset, but 64 is the typical "extra offset" one needs to add to 
> account
> for file metadata of CBFS (otherwise it can be its multiple 128 or bigger).
> Bootblock should normally end at the last byte of ROM on x86 systems, giving 
> you
> a way to test the result of computations.
>
> ## Finding a matching range
>
> In most chips the list of supported ranges is fixed and you can't specify an
> arbitrary one. Some others allow more fine-grained control, but that feature 
> is
> not supported by `flashrom` as of now.
>
> Obtain list of supported ranges from which we'll pick the best match:
>
> ```
> $ flashrom --programmer internal --wp-list
> ...
> Available protection ranges:
>         start=0x00000000 length=0x00000000 (none)
>         start=0x00000000 length=0x00001000 (lower 1/4096)
>         start=0x00fff000 length=0x00001000 (upper 1/4096)
>         start=0x00000000 length=0x00002000 (lower 1/2048)
>         start=0x00ffe000 length=0x00002000 (upper 1/2048)
>         start=0x00000000 length=0x00004000 (lower 1/1024)
>         start=0x00ffc000 length=0x00004000 (upper 1/1024)
>         start=0x00000000 length=0x00008000 (lower 1/512)
>         start=0x00ff8000 length=0x00008000 (upper 1/512)
>         start=0x00000000 length=0x00040000 (lower 1/64)
>         start=0x00fc0000 length=0x00040000 (upper 1/64)
>         start=0x00000000 length=0x00080000 (lower 1/32)
>         start=0x00f80000 length=0x00080000 (upper 1/32)
>         start=0x00000000 length=0x00100000 (lower 1/16)
>         start=0x00f00000 length=0x00100000 (upper 1/16)
>         start=0x00000000 length=0x00200000 (lower 1/8)
>         start=0x00e00000 length=0x00200000 (upper 1/8)
>         start=0x00000000 length=0x00400000 (lower 1/4)
>         start=0x00c00000 length=0x00400000 (upper 1/4)
>         start=0x00000000 length=0x00800000 (lower 1/2)
>         start=0x00800000 length=0x00800000 (upper 1/2)
>         start=0x00000000 length=0x00c00000 (lower 3/4)
>         start=0x00400000 length=0x00c00000 (upper 3/4)
>         start=0x00000000 length=0x00e00000 (lower 7/8)
>         start=0x00200000 length=0x00e00000 (upper 7/8)
>         start=0x00000000 length=0x00f00000 (lower 15/16)
>         start=0x00100000 length=0x00f00000 (upper 15/16)
>         start=0x00000000 length=0x00f80000 (lower 31/32)
>         start=0x00080000 length=0x00f80000 (upper 31/32)
>         start=0x00000000 length=0x00fc0000 (lower 63/64)
>         start=0x00040000 length=0x00fc0000 (upper 63/64)
>         start=0x00000000 length=0x00ff8000 (lower 511/512)
>         start=0x00008000 length=0x00ff8000 (upper 511/512)
>         start=0x00000000 length=0x00ffc000 (lower 1023/1024)
>         start=0x00004000 length=0x00ffc000 (upper 1023/1024)
>         start=0x00000000 length=0x00ffe000 (lower 2047/2048)
>         start=0x00002000 length=0x00ffe000 (upper 2047/2048)
>         start=0x00000000 length=0x00fff000 (lower 4095/4096)
>         start=0x00001000 length=0x00fff000 (upper 4095/4096)
>         start=0x00000000 length=0x01000000 (all)
> ```
>
> Pick a range by scanning the list in the top down order (because the smaller
> ranges come first):
>
>  - if bootblock is at the start of a chip, look for the first lower range 
> whose
>    length is greater than the end offset
>  - if bootblock is at the end of a chip, look for the first upper range which
>    starts before or at the start offset
>  - mind that you're unlikely to find an ideal match and will probably protect
>    more than you need; this is fine if that's just an empty space, but can
>    cause troubles with future updates if that's some data or metadata which
>    changes with every release
>
> This is the first upper range starting before `0xff7140`:
>
> ```
>         start=0x00fc0000 length=0x00040000 (upper 1/64)
> ```
>
> It covers `0x00fc0000 -- 0x00ffffff` which includes our bootblock. This area
> takes up 256 KiB, about 7 times bigger than our bootblock, but there is no 
> better
> choice in this case and output of `cbfstool rom layout` shows that we
> additionally include a part of 876 KiB empty space which will hopefully remain
> there in future firmware versions (it's a good idea to check before a firmware
> update).
>
> ## Protection setup
>
> The following command sets the range and enables WP at the same time, the 
> values
> are taken from the chosen range above:
>
> ```
> flashrom --programmer internal --wp-range=0x00fc0000,0x00040000 --wp-enable
> ```
>
> You can set the range and change WP status independently as well if needed
> (just specify one `--wp-*` option at a time). Make sure that hardware
> protection is off (state of `W#`/`W/` pin of the chip) or you won't be able to
> change WP configuration.
>
> On success, the output of the above command will include such lines:
>
> ```
> Enabled hardware protection
> Activated protection range: start=0x00fc0000 length=0x00040000 (upper 1/64)
> ```
>
> **Caveat**: `flashrom` automatically tries to disable WP before any operation
> on a chip (read, write, erase, verify), so double-check status of WP before
> changing state of WP pin on your chip!
>
> ## Verifying hardware protection
>
> Once you've happy with the configuration and changed state of WP pin, you can
> try disabling WP using `flashrom` to make sure that it fails now.
>
> ================================================================================
>
> Regards,
> Sergii
_______________________________________________
flashrom mailing list -- flashrom@flashrom.org
To unsubscribe send an email to flashrom-le...@flashrom.org

Reply via email to