diff options
author | Che-Liang Chiou <clchiou@chromium.org> | 2011-07-19 16:28:44 +0800 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-29 10:59:01 -0700 |
commit | f771480b4ce71d9863f8b6f87abe571b3209f97d (patch) | |
tree | 38b411850a5a7775a8f492eb94c3577c63afcc7e /lib | |
parent | 0eaae2c7b2d0829bff40daa5452935b076916479 (diff) |
CHROMIUM: fix recovery boot hangs
When the developer switch is turned off, the recovery boot hangs deep
inside call stack due to memory corruption caused by freeing a pointer
twice.
The pointer in question is allocated by VbExDiskGetInfo() and freed by
VbExDiskFreeInfo().
When VbExDiskGetInfo() finds no storage device or encounters an error, it
frees the VbDiskInfo pointer, but it still returns the pointer value to
its caller. And its caller frees the pointer again anyway.
So, when an error occurs or no storage device is available, the correct
implementation of VbExDiskGetInfo() should either not freeing and
returning the pointer, or freeing the pointer and returning NULL, but
not anything in between.
In additional to fix the free-twice bug, this patch also corrects the
return value of VbExDiskGetInfo() when there are too many storage device
available. This should be a success with warnings instead of an error.
BUG=chromium-os:17462
TEST=manually tested on Kaen
* Boot to Chrome OS on internal and external storage device through
normal, developer, and recovery boot path.
* The recovery boot path is tested with both developer switch on and
off.
Change-Id: I26026a86523b4b0f6c471c2a30a7394607a9c86b
Reviewed-on: http://gerrit.chromium.org/gerrit/4297
Tested-by: Che-Liang Chiou <clchiou@chromium.org>
Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/vbexport/boot_device.c | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/lib/vbexport/boot_device.c b/lib/vbexport/boot_device.c index bb159e87dc..9efebd9351 100644 --- a/lib/vbexport/boot_device.c +++ b/lib/vbexport/boot_device.c @@ -89,21 +89,24 @@ static void init_usb_storage(void) usb_stor_scan(/*mode=*/1); } -VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count, +VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count_ptr, uint32_t disk_flags) { VbDiskInfo *infos; + uint32_t count, flags; struct mmc *m; block_dev_desc_t *d; int i; + *infos_ptr = NULL; + *count_ptr = 0; + infos = (VbDiskInfo *)VbExMalloc(sizeof(VbDiskInfo) * MAX_DISK_INFO); - *infos_ptr = infos; - *count = 0; + count = 0; /* Detect all SD/MMC devices. */ for (i = 0; (m = find_mmc_device(i)) != NULL; i++) { - uint32_t flags = get_dev_flags(&m->block_dev); + flags = get_dev_flags(&m->block_dev); /* Skip this entry if the flags are not matched. */ if (!(flags & disk_flags)) @@ -115,42 +118,45 @@ VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count, continue; } - if (add_disk_info(&m->block_dev, infos, count)) { + if (add_disk_info(&m->block_dev, infos, &count)) { /* * If too many storage devices registered, * returns as many disk infos as we could * handle. */ - return 1; + goto out; } } /* To speed up, skip detecting USB if not require removable devices. */ - if (disk_flags & VB_DISK_FLAG_REMOVABLE) { - /* Detect all USB storage devices. */ - init_usb_storage(); - for (i = 0; (d = usb_stor_get_dev(i)) != NULL; i++) { - uint32_t flags = get_dev_flags(d); - - /* Skip this entry if the flags are not matched. */ - if (!(flags & disk_flags)) - continue; - - if (add_disk_info(d, infos, count)) { - /* - * If too many storage devices registered, - * returns as many disk infos as we could - * handle. - */ - return 1; - } + if (!(disk_flags & VB_DISK_FLAG_REMOVABLE)) + goto out; + + /* Detect all USB storage devices. */ + init_usb_storage(); + for (i = 0; (d = usb_stor_get_dev(i)) != NULL; i++) { + flags = get_dev_flags(d); + + /* Skip this entry if the flags are not matched. */ + if (!(flags & disk_flags)) + continue; + + if (add_disk_info(d, infos, &count)) { + /* + * If too many storage devices registered, + * returns as many disk infos as we could + * handle. + */ + goto out; } } - if (*count == 0) { +out: + if (count) { + *infos_ptr = infos; + *count_ptr = count; + } else VbExFree(infos); - infos = NULL; - } return VBERROR_SUCCESS; } |