layout: Verify layout entries before building a new image using them
This fixes a SEGFAULT if a layout entry is included that addresses memory
outside the current chip's address range. flashrom will only abort if the
offending region(s) is/are included else it will just warn.
It will print warnings for regions with negative or zero-length address ranges
and bail out after checking all of them.
Also, abort for non-write operations if a layout file is given because there is
no layout support for other operations yet.
Corresponding to flashrom svn r1751.
Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/cli_classic.c b/cli_classic.c
index 70bccb5..a0c2d64 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -370,6 +370,12 @@
ret = 1;
goto out;
}
+ if (layoutfile != NULL && !write_it) {
+ msg_gerr("Layout files are currently supported for write operations only.\n");
+ ret = 1;
+ goto out;
+ }
+
if (process_include_args()) {
ret = 1;
goto out;
diff --git a/flash.h b/flash.h
index 7b88477..e320ced 100644
--- a/flash.h
+++ b/flash.h
@@ -45,6 +45,14 @@
typedef uintptr_t chipaddr;
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))
+/* Types and macros regarding the maximum flash space size supported by generic code. */
+typedef uint32_t chipoff_t; /* Able to store any addressable offset within a supported flash memory. */
+typedef uint32_t chipsize_t; /* Able to store the number of bytes of any supported flash memory. */
+#define FL_MAX_CHIPADDR_BITS (24)
+#define FL_MAX_CHIPADDR ((chipoff_t)(1ULL<<FL_MAX_CHIPADDR_BITS)-1)
+#define PRIxCHIPADDR "06"PRIx32
+#define PRIuCHIPSIZE PRIu32
+
int register_shutdown(int (*function) (void *data), void *data);
void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len);
void programmer_unmap_flash_region(void *virt_addr, size_t len);
@@ -319,7 +327,8 @@
int register_include_arg(char *name);
int process_include_args(void);
int read_romlayout(char *name);
-int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
+int normalize_romentries(const struct flashctx *flash);
+int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
void layout_cleanup(void);
/* spi.c */
diff --git a/flashrom.c b/flashrom.c
index 9169620..afab57c 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1916,6 +1916,12 @@
goto out_nofree;
}
+ if (normalize_romentries(flash)) {
+ msg_cerr("Requested regions can not be handled. Aborting.\n");
+ ret = 1;
+ goto out_nofree;
+ }
+
/* Given the existence of read locks, we want to unlock for read,
* erase and write.
*/
@@ -1995,9 +2001,8 @@
}
msg_cinfo("done.\n");
- // This should be moved into each flash part's code to do it
- // cleanly. This does the job.
- handle_romentries(flash, oldcontents, newcontents);
+ /* Build a new image taking the given layout into account. */
+ build_new_image(flash, oldcontents, newcontents);
// ////////////////////////////////////////////////////////////
diff --git a/layout.c b/layout.c
index 86351b8..08cc776 100644
--- a/layout.c
+++ b/layout.c
@@ -29,15 +29,15 @@
#define MAX_ROMLAYOUT 32
typedef struct {
- unsigned int start;
- unsigned int end;
+ chipoff_t start;
+ chipoff_t end;
unsigned int included;
char name[256];
} romentry_t;
/* rom_entries store the entries specified in a layout file and associated run-time data */
static romentry_t rom_entries[MAX_ROMLAYOUT];
-static int num_rom_entries = 0; /* the number of valid rom_entries */
+static int num_rom_entries = 0; /* the number of successfully parsed rom_entries */
/* include_args holds the arguments specified at the command line with -i. They must be processed at some point
* so that desired regions are marked as "included" in the rom_entries list. */
@@ -232,7 +232,31 @@
return best_entry;
}
-int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
+/* Validate and - if needed - normalize layout entries. */
+int normalize_romentries(const struct flashctx *flash)
+{
+ chipsize_t total_size = flash->chip->total_size * 1024;
+ int ret = 0;
+
+ int i;
+ for (i = 0; i < num_rom_entries; i++) {
+ if (rom_entries[i].start >= total_size || rom_entries[i].end >= total_size) {
+ msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's "
+ "address space.\n", rom_entries[i].name);
+ if (rom_entries[i].included)
+ ret = 1;
+ }
+ if (rom_entries[i].start > rom_entries[i].end) {
+ msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n",
+ rom_entries[i].name);
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents)
{
unsigned int start = 0;
romentry_t *entry;