mirror of
https://review.coreboot.org/flashrom.git
synced 2025-10-13 22:10:23 +02:00
Fail immediately when trying to write/erase wp regions
This patch introduces chipset-level protections and adds checks that abort writing to flash if any of the requested regions are write-protected by chip, dynamically by a chipset, or are defined as read-only. This change is done so it's harder for user to brick his own platform. Information about read-only regions can easily be missed as flashrom can output a lot of information on screen. Even if you notice you might not know if one of the regions you requested falls inside read-only range, especially if using different names for those regions. If you are flashing multiple regions or ones that partially overlap with read-only parts then that could result in flashrom failing in the middle leaving you in unknown state. This patch was tested with multiple combinations of unprotected/protected regions: - dummy programmer ```sh flashrom -p dummy:hwwp=yes,emulate=S25FL128L --wp-enable \ --wp-range 0x00040000,0x00fc0000 \ -l <(echo '00000000:0004ffff part1') -i part1 -E ``` - internal programmer on Protectli VP6670 with Dasharo UEFI firmware with locked BIOS boot medium (PR0, part of bios region) ```sh flashrom -p internal --ifd -i me -i bios -w test.rom ``` Normal reads and flashing non-protected regions was also tested. Change-Id: Ia0dd847923e20ff0081ceae68984369e98952c2f Signed-off-by: Michał Iwanicki <michal.iwanicki@3mdeb.com> Reviewed-on: https://review.coreboot.org/c/flashrom/+/89222 Reviewed-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
This commit is contained in:

committed by
Anastasia Klimchuk

parent
45fc49e99b
commit
2a092bbef7
75
flashrom.c
75
flashrom.c
@@ -384,6 +384,22 @@ void get_flash_region(const struct flashctx *flash, int addr, struct flash_regio
|
||||
}
|
||||
}
|
||||
|
||||
void get_protected_ranges(const struct flashctx *flash, struct protected_ranges *ranges) {
|
||||
if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.get_protected_ranges) {
|
||||
flash->mst->opaque.get_protected_ranges(ranges);
|
||||
} else {
|
||||
*ranges = (const struct protected_ranges){ 0 };
|
||||
}
|
||||
}
|
||||
|
||||
void release_protected_ranges(const struct flashctx *flash, struct protected_ranges *ranges) {
|
||||
for (int i = 0; i < ranges->count; ++i) {
|
||||
free(ranges->ranges[i].name);
|
||||
}
|
||||
free(ranges->ranges);
|
||||
*ranges = (const struct protected_ranges){ 0 };
|
||||
}
|
||||
|
||||
int check_for_unwritable_regions(const struct flashctx *flash, unsigned int start, unsigned int len)
|
||||
{
|
||||
struct flash_region region;
|
||||
@@ -1817,6 +1833,58 @@ warn_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool can_change_target_regions(struct flashctx *flash) {
|
||||
bool check_wp = false;
|
||||
size_t wp_start, wp_len;
|
||||
enum flashrom_wp_mode mode;
|
||||
struct flashrom_wp_cfg *cfg = NULL;
|
||||
const struct romentry *entry = NULL;
|
||||
const struct flashrom_layout *const layout = get_layout(flash);
|
||||
struct protected_ranges ranges;
|
||||
get_protected_ranges(flash, &ranges);
|
||||
|
||||
if (flashrom_wp_cfg_new(&cfg) == FLASHROM_WP_OK &&
|
||||
flashrom_wp_read_cfg(cfg, flash) == FLASHROM_WP_OK)
|
||||
{
|
||||
flashrom_wp_get_range(&wp_start, &wp_len, cfg);
|
||||
mode = flashrom_wp_get_mode(cfg);
|
||||
if (mode != FLASHROM_WP_MODE_DISABLED && wp_len != 0)
|
||||
check_wp = true;
|
||||
}
|
||||
flashrom_wp_cfg_release(cfg);
|
||||
|
||||
while ((entry = layout_next_included(layout, entry))) {
|
||||
if (!flash->flags.skip_unwritable_regions &&
|
||||
check_for_unwritable_regions(flash, entry->region.start,
|
||||
entry->region.end - entry->region.start + 1))
|
||||
{
|
||||
release_protected_ranges(flash, &ranges);
|
||||
return false;
|
||||
}
|
||||
if (check_wp && entry->region.start < wp_start + wp_len && wp_start <= entry->region.end) {
|
||||
msg_gerr("%s: cannot fully update %s region (%#08"PRIx32"..%#08"PRIx32")"
|
||||
" due to chip's write-protection.\n", __func__,
|
||||
entry->region.name, entry->region.start, entry->region.end);
|
||||
release_protected_ranges(flash, &ranges);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < ranges.count; ++i) {
|
||||
struct flash_region prot = ranges.ranges[i];
|
||||
if (prot.write_prot && prot.start <= entry->region.end &&
|
||||
prot.end >= entry->region.start) {
|
||||
msg_gerr("%s: cannot fully update %s region (%#08"PRIx32"..%#08"PRIx32")"
|
||||
" due to chipset write-protection.\n", __func__,
|
||||
entry->region.name, entry->region.start, entry->region.end);
|
||||
release_protected_ranges(flash, &ranges);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release_protected_ranges(flash, &ranges);
|
||||
return true;
|
||||
}
|
||||
|
||||
int prepare_flash_access(struct flashctx *const flash,
|
||||
const bool read_it, const bool write_it,
|
||||
const bool erase_it, const bool verify_it)
|
||||
@@ -1831,6 +1899,13 @@ int prepare_flash_access(struct flashctx *const flash,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((write_it || erase_it) && !flash->flags.force) {
|
||||
if (!can_change_target_regions(flash)) {
|
||||
msg_cerr("At least one target region is not fully writable. Aborting.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (map_flash(flash) != 0)
|
||||
return 1;
|
||||
|
||||
|
Reference in New Issue
Block a user