From 2df6c4a1d5b2abeabd3970c7ae94b98d43d8f7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Szymczyk?= Date: Thu, 15 Jan 2015 14:21:54 +0100 Subject: [PATCH] Reserve space on disk using fallocate There were crashes when android failed to extract zip archives due to out of free space on disk, with stacks like: #00 pc 00000000000156b0 /system/lib64/libc.so (memcpy+176) #01 pc 000000000002e5b8 /system/lib64/libandroidfw.so #02 pc 000000000002f488 /system/lib64/libandroidfw.so (ExtractToMemory+328) #03 pc 000000000002f5c8 /system/lib64/libandroidfw.so (ExtractEntryToFile+268) #04 pc 00000000000287d8 /system/lib64/libandroidfw.so (android::ZipFileRO::\ uncompressEntry(void*, int) const+12) Space for the file is now allocated using fallocate rather than ftruncate, since ftruncate dont actually reserve space on disk. When writes to the mmaped pointer fails to be realized due to out of space SIGBUS is the result. With this change we make sure that there is space available before mmaping the pointer. Change-Id: Ic5e8c33dbe729edb57919dacff73811b34cc2dc2 --- libziparchive/zip_archive.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 87dac0e74ba1..7ecab04a1917 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -1124,7 +1124,22 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle, return kIoError; } - int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); + int result = 0; +#if defined(__linux__) + // Make sure we have enough space on the volume to extract the compressed + // entry. Note that the call to ftruncate below will change the file size but + // will not allocate space on disk. + if (declared_length > 0) { + result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length)); + if (result == -1) { + ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s", + static_cast(declared_length + current_offset), strerror(errno)); + return kIoError; + } + } +#endif // defined(__linux__) + + result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); if (result == -1) { ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", (int64_t)(declared_length + current_offset), strerror(errno));