From 4fec8e9e9a97810294c2dabe0b169198f461cafb Mon Sep 17 00:00:00 2001 From: Abhishek Arpure Date: Thu, 24 Aug 2017 15:27:16 +0530 Subject: Integer overflow observed while formatting volume While calculating volume size, get_block_device_size() returns u64 value but the returned value is assigned in ssize_t variable. This may cause integer overflow if the volume size is beyond ssize_t limit. Use int64_t instead of ssize_t in get_file_size() and explicitly check for overflow to fix the issue. Bug: 65001754 Test: mmma bootable/recovery Change-Id: I91eb30bff0bf7dcc48678efc2f414d2b79af6d0d --- roots.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'roots.cpp') diff --git a/roots.cpp b/roots.cpp index fdcbfe844..26602a710 100644 --- a/roots.cpp +++ b/roots.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -178,16 +179,22 @@ static int exec_cmd(const std::vector& args) { return WEXITSTATUS(status); } -static ssize_t get_file_size(int fd, uint64_t reserve_len) { +static int64_t get_file_size(int fd, uint64_t reserve_len) { struct stat buf; int ret = fstat(fd, &buf); if (ret) return 0; - ssize_t computed_size; + int64_t computed_size; if (S_ISREG(buf.st_mode)) { computed_size = buf.st_size - reserve_len; } else if (S_ISBLK(buf.st_mode)) { - computed_size = get_block_device_size(fd) - reserve_len; + uint64_t block_device_size = get_block_device_size(fd); + if (block_device_size < reserve_len || + block_device_size > std::numeric_limits::max()) { + computed_size = 0; + } else { + computed_size = block_device_size - reserve_len; + } } else { computed_size = 0; } @@ -231,13 +238,13 @@ int format_volume(const char* volume, const char* directory) { close(fd); } - ssize_t length = 0; + int64_t length = 0; if (v->length != 0) { length = v->length; } else if (v->key_loc != nullptr && strcmp(v->key_loc, "footer") == 0) { android::base::unique_fd fd(open(v->blk_device, O_RDONLY)); if (fd == -1) { - PLOG(ERROR) << "get_file_size: failed to open " << v->blk_device; + PLOG(ERROR) << "format_volume: failed to open " << v->blk_device; return -1; } length = get_file_size(fd.get(), CRYPT_FOOTER_OFFSET); -- cgit v1.2.3 From 2dfc1a38982c4052bb32bc7fc06edeadf3908fb9 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 27 Sep 2017 13:12:11 -0700 Subject: roots: volume_for_path() parses and tries prefixes. Commit cc323958f99e40fea06c511656c69c0b2e2d47f7 in system/core has changed fs_mgr_get_entry_for_mount_point() to do an exact match only, which breaks the behavior in volume_for_path(). This CL changes the volume_for_path() implementation to parse and pass prefixes locally. For a given path like "/cache/recovery/last_log", it will in turn attempt the prefixes of "/cache/recovery/last_log", "/cache/recovery", "/cache", "/" and return the first hit. Bug: 63912287 Test: Build and boot into recovery image on bullhead. 'View recovery logs' works. Change-Id: Ic8635b0939649dd5cc9ca501ebc3a2d1fbf5849d --- roots.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'roots.cpp') diff --git a/roots.cpp b/roots.cpp index fdcbfe844..835a1dda0 100644 --- a/roots.cpp +++ b/roots.cpp @@ -68,8 +68,27 @@ void load_volume_table() { printf("\n"); } +// Finds the volume specified by the given path. fs_mgr_get_entry_for_mount_point() does exact match +// only, so it attempts the prefixes recursively (e.g. "/cache/recovery/last_log", +// "/cache/recovery", "/cache", "/" for a given path of "/cache/recovery/last_log") and returns the +// first match or nullptr. Volume* volume_for_path(const char* path) { - return fs_mgr_get_entry_for_mount_point(fstab, path); + if (path == nullptr || path[0] == '\0') return nullptr; + std::string str(path); + while (true) { + Volume* result = fs_mgr_get_entry_for_mount_point(fstab, str.c_str()); + if (result != nullptr || str == "/") { + return result; + } + size_t slash = str.find_last_of('/'); + if (slash == std::string::npos) return nullptr; + if (slash == 0) { + str = "/"; + } else { + str = str.substr(0, slash); + } + } + return nullptr; } // Mount the volume specified by path at the given mount_point. -- cgit v1.2.3