[flashrom] [PATCH] layout: Verify layout entries before building a new image using them.

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Sun Sep 22 23:11:57 CEST 2013


Am 22.09.2013 21:10 schrieb Stefan Tauner:
> This fixes a SEGFAULT if a layout entry is included that addresses memory
> outside the current chip's address range.
>
> Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
> ---
>
> Before continuing with the other layout patches, I'd like to fix this
> issue (and copy the patch that fixes this also to the .7 stable branch).

Good idea.


> The macros are open for discussion not only regarding naming...
> e.g. it might be easier to declare a macro that provides the full printf
> format specification for the address, '0x06" PRIx32 "' to make the
> resulting code more readable.
>
>  flash.h    | 11 ++++++++++-
>  flashrom.c | 11 ++++++++---
>  layout.c   | 29 +++++++++++++++++++++++++++--
>  3 files changed, 45 insertions(+), 6 deletions(-)
>
> diff --git a/flash.h b/flash.h
> index 7b88477..a5033ef 100644
> --- a/flash.h
> +++ b/flash.h
> @@ -45,6 +45,14 @@
>  typedef uintptr_t chipaddr;
>  #define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))
>  
> +/* To be used in technology-independent code. */
> +#define FL_MAX_CHIPADDR (24)

This looks suspiciously like the number of address bits. It's not, and
that confused me.


> +#define FL_MAX_CHIPSIZE ((1<<FL_MAX_CHIPADDR)-1)

AFAICS it should be 1ULL, not 1.


> +#define PRIxCHIPADDR_WIDTH ((int)(FL_MAX_CHIPADDR/4))

Incorrect rounding. If FL_MAX_CHIPADDR=23, PRIxCHIPADDR_WIDTH is 5, but
it should be 6. Suggested fix: Replace FL_MAX_CHIPADDR/4 with
(FL_MAX_CHIPADDR+3)/4.


> +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 PRIxCHIPADDR PRIx32
> +
>  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 @@ __attribute__((format(printf, 2, 3)));
>  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);

Good idea.


>  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 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
>  		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 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
>  	}
>  	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..5adec67 100644
> --- a/layout.c
> +++ b/layout.c
> @@ -37,7 +37,7 @@ typedef struct {
>  
>  /* 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,32 @@ romentry_t *get_next_included_romentry(unsigned int start)
>  	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) {

If you want to do this, please make sure struct romentry has members
start/end with type chipoff_t. Otherwise that check may backfire eventually.


> +			msg_gwarn("Warning: Address range of region \"%s\" exeeds 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) {

Off-by-one: If start==end, the length is 1, but this check will trigger.
The check should be > instead of >=.


> +			msg_gwarn("Warning: Size of the address range of region \"%s\" is not positive.\n",
> +				  rom_entries[i].name);
> +			if (rom_entries[i].included)
> +				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;

Looks good otherwise.

Regards,
Carl-Daniel

-- 
http://www.hailfinger.org/





More information about the flashrom mailing list