diff options
-rw-r--r-- | Android.mk | 16 | ||||
-rw-r--r-- | applypatch/NOTICE | 41 | ||||
-rw-r--r-- | applypatch/applypatch.c | 64 | ||||
-rw-r--r-- | applypatch/applypatch.h | 4 | ||||
-rw-r--r-- | etc/init.rc | 6 | ||||
-rw-r--r-- | minelf/Retouch.c | 210 | ||||
-rw-r--r-- | minelf/Retouch.h | 6 | ||||
-rw-r--r-- | minzip/Android.mk | 8 | ||||
-rw-r--r-- | minzip/DirUtil.c | 21 | ||||
-rw-r--r-- | minzip/DirUtil.h | 10 | ||||
-rw-r--r-- | minzip/Zip.c | 25 | ||||
-rw-r--r-- | minzip/Zip.h | 10 | ||||
-rw-r--r-- | mtdutils/flash_image.c | 10 | ||||
-rw-r--r-- | recovery.cpp | 21 | ||||
-rw-r--r-- | roots.cpp | 4 | ||||
-rw-r--r-- | updater/Android.mk | 6 | ||||
-rw-r--r-- | updater/install.c | 170 | ||||
-rw-r--r-- | updater/updater.c | 15 | ||||
-rw-r--r-- | updater/updater.h | 9 |
19 files changed, 274 insertions, 382 deletions
diff --git a/Android.mk b/Android.mk index 7e48e7f64..21e6946c2 100644 --- a/Android.mk +++ b/Android.mk @@ -28,6 +28,12 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_STATIC_LIBRARIES += libext4_utils libz endif +ifeq ($(HAVE_SELINUX), true) +LOCAL_C_INCLUDES += external/libselinux/include +LOCAL_STATIC_LIBRARIES += libselinux +LOCAL_CFLAGS += -DHAVE_SELINUX +endif # HAVE_SELINUX + # This binary is in the recovery ramdisk, which is otherwise a copy of root. # It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses # a (redundant) copy of the binary in /system/bin for user builds. @@ -40,11 +46,17 @@ ifeq ($(TARGET_RECOVERY_UI_LIB),) else LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB) endif -LOCAL_STATIC_LIBRARIES += libext4_utils libz -LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt libminadbd +LOCAL_STATIC_LIBRARIES += libext4_utils +LOCAL_STATIC_LIBRARIES += libminzip libz libmtdutils libmincrypt libminadbd LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils LOCAL_STATIC_LIBRARIES += libstdc++ libc +ifeq ($(HAVE_SELINUX),true) +LOCAL_C_INCLUDES += external/libselinux/include +LOCAL_STATIC_LIBRARIES += libselinux +LOCAL_CFLAGS += -DHAVE_SELINUX +endif # HAVE_SELINUX + LOCAL_C_INCLUDES += system/extras/ext4_utils include $(BUILD_EXECUTABLE) diff --git a/applypatch/NOTICE b/applypatch/NOTICE new file mode 100644 index 000000000..6156a0ca3 --- /dev/null +++ b/applypatch/NOTICE @@ -0,0 +1,41 @@ +Copyright (C) 2009 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +bsdiff.c +bspatch.c + +Copyright 2003-2005 Colin Percival +All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted providing that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 106091386..00004e9a8 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -30,10 +30,16 @@ #include "mtdutils/mtdutils.h" #include "edify/expr.h" -int SaveFileContents(const char* filename, FileContents file); static int LoadPartitionContents(const char* filename, FileContents* file); -int ParseSha1(const char* str, uint8_t* digest); static ssize_t FileSink(unsigned char* data, ssize_t len, void* token); +static int GenerateTarget(FileContents* source_file, + const Value* source_patch_value, + FileContents* copy_file, + const Value* copy_patch_value, + const char* source_filename, + const char* target_filename, + const uint8_t target_sha1[SHA_DIGEST_SIZE], + size_t target_size); static int mtd_partitions_scanned = 0; @@ -113,11 +119,6 @@ static int compare_size_indices(const void* a, const void* b) { } } -void FreeFileContents(FileContents* file) { - if (file) free(file->data); - free(file); -} - // Load the contents of an MTD or EMMC partition into the provided // FileContents. filename should be a string of the form // "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or @@ -322,7 +323,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // Save the contents of the given FileContents object under the given // filename. Return 0 on success. -int SaveFileContents(const char* filename, FileContents file) { +int SaveFileContents(const char* filename, const FileContents* file) { int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC); if (fd < 0) { printf("failed to open \"%s\" for write: %s\n", @@ -330,10 +331,10 @@ int SaveFileContents(const char* filename, FileContents file) { return -1; } - ssize_t bytes_written = FileSink(file.data, file.size, &fd); - if (bytes_written != file.size) { + ssize_t bytes_written = FileSink(file->data, file->size, &fd); + if (bytes_written != file->size) { printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n", - filename, (long)bytes_written, (long)file.size, + filename, (long)bytes_written, (long)file->size, strerror(errno)); close(fd); return -1; @@ -341,11 +342,11 @@ int SaveFileContents(const char* filename, FileContents file) { fsync(fd); close(fd); - if (chmod(filename, file.st.st_mode) != 0) { + if (chmod(filename, file->st.st_mode) != 0) { printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) { + if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) { printf("chown of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -471,7 +472,7 @@ int ParseSha1(const char* str, uint8_t* digest) { // Search an array of sha1 strings for one matching the given sha1. // Return the index of the match on success, or -1 if no match is // found. -int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str, int num_patches) { int i; uint8_t patch_sha1[SHA_DIGEST_SIZE]; @@ -503,6 +504,7 @@ int applypatch_check(const char* filename, "sha1 sums; checking cache\n", filename); free(file.data); + file.data = NULL; // If the source file is missing or corrupted, it might be because // we were killed in the middle of patching it. A copy of it @@ -631,9 +633,10 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; + copy_file.data = NULL; + source_file.data = NULL; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; - int made_copy = 0; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file, @@ -643,6 +646,7 @@ int applypatch(const char* source_filename, // has the desired hash, nothing for us to do. printf("\"%s\" is already target; no patch needed\n", target_filename); + free(source_file.data); return 0; } } @@ -653,6 +657,7 @@ int applypatch(const char* source_filename, // Need to load the source file: either we failed to load the // target file, or we did but it's different from the source file. free(source_file.data); + source_file.data = NULL; LoadFileContents(source_filename, &source_file, RETOUCH_DO_MASK); } @@ -667,6 +672,7 @@ int applypatch(const char* source_filename, if (source_patch_value == NULL) { free(source_file.data); + source_file.data = NULL; printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file, @@ -685,16 +691,36 @@ int applypatch(const char* source_filename, if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); + free(copy_file.data); return 1; } } + int result = GenerateTarget(&source_file, source_patch_value, + ©_file, copy_patch_value, + source_filename, target_filename, + target_sha1, target_size); + free(source_file.data); + free(copy_file.data); + + return result; +} + +static int GenerateTarget(FileContents* source_file, + const Value* source_patch_value, + FileContents* copy_file, + const Value* copy_patch_value, + const char* source_filename, + const char* target_filename, + const uint8_t target_sha1[SHA_DIGEST_SIZE], + size_t target_size) { int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; FileContents* source_to_use; char* outname; + int made_copy = 0; // assume that target_filename (eg "/system/app/Foo.apk") is located // on the same filesystem as its top-level directory ("/system"). @@ -723,7 +749,7 @@ int applypatch(const char* source_filename, // We still write the original source to cache, in case // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file.size) < 0) { + if (MakeFreeSpaceOnCache(source_file->size) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -763,7 +789,7 @@ int applypatch(const char* source_filename, return 1; } - if (MakeFreeSpaceOnCache(source_file.size) < 0) { + if (MakeFreeSpaceOnCache(source_file->size) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -782,10 +808,10 @@ int applypatch(const char* source_filename, const Value* patch; if (source_patch_value != NULL) { - source_to_use = &source_file; + source_to_use = source_file; patch = source_patch_value; } else { - source_to_use = ©_file; + source_to_use = copy_file; patch = copy_patch_value; } diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index a78c89bfe..fb58843ba 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -62,9 +62,9 @@ int applypatch_check(const char* filename, int LoadFileContents(const char* filename, FileContents* file, int retouch_flag); -int SaveFileContents(const char* filename, FileContents file); +int SaveFileContents(const char* filename, const FileContents* file); void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str, +int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str, int num_patches); // bsdiff.c diff --git a/etc/init.rc b/etc/init.rc index bf4ce62b5..89a161e70 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -22,9 +22,9 @@ on init write /sys/class/android_usb/android0/idVendor 18D1 write /sys/class/android_usb/android0/idProduct D001 write /sys/class/android_usb/android0/functions adb - write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer - write /sys/class/android_usb/android0/iProduct $ro.product.model - write /sys/class/android_usb/android0/iSerial $ro.serialno + write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} + write /sys/class/android_usb/android0/iProduct ${ro.product.model} + write /sys/class/android_usb/android0/iSerial ${ro.serialno} on boot diff --git a/minelf/Retouch.c b/minelf/Retouch.c index 33809cd6d..d75eec1e8 100644 --- a/minelf/Retouch.c +++ b/minelf/Retouch.c @@ -194,213 +194,3 @@ int retouch_mask_data(uint8_t *binary_object, if (retouch_offset != NULL) *retouch_offset = offset_candidate; return RETOUCH_DATA_MATCHED; } - -// On success, _override is set to the offset that was actually applied. -// This implies that once we randomize to an offset we stick with it. -// This in turn is necessary in order to guarantee recovery after crash. -bool retouch_one_library(const char *binary_name, - const char *binary_sha1, - int32_t retouch_offset, - int32_t *retouch_offset_override) { - bool success = true; - int result; - - FileContents file; - file.data = NULL; - - char binary_name_atomic[strlen(binary_name)+10]; - strcpy(binary_name_atomic, binary_name); - strcat(binary_name_atomic, ".atomic"); - - // We need a path that exists for calling statfs() later. - // - // Assume that binary_name (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - char target_fs[strlen(binary_name)+1]; - char* slash = strchr(binary_name+1, '/'); - if (slash != NULL) { - int count = slash - binary_name; - strncpy(target_fs, binary_name, count); - target_fs[count] = '\0'; - } else { - strcpy(target_fs, binary_name); - } - - result = LoadFileContents(binary_name, &file, RETOUCH_DONT_MASK); - - if (result == 0) { - // Figure out the *apparent* offset to which this file has been - // retouched. If it looks good, we will skip processing (we might - // have crashed and during this recovery pass we don't want to - // overwrite a valuable saved file in /cache---which would happen - // if we blindly retouch everything again). NOTE: This implies - // that we might have to override the supplied retouch offset. We - // can do the override only once though: everything should match - // afterward. - - int32_t inferred_offset; - int retouch_probe_result = retouch_mask_data(file.data, - file.size, - NULL, - &inferred_offset); - - if (retouch_probe_result == RETOUCH_DATA_MATCHED) { - if ((retouch_offset == inferred_offset) || - ((retouch_offset != 0 && inferred_offset != 0) && - (retouch_offset_override != NULL))) { - // This file is OK already and we are allowed to override. - // Let's just return the offset override value. It is critical - // to skip regardless of override: a broken file might need - // recovery down the list and we should not mess up the saved - // copy by doing unnecessary retouching. - // - // NOTE: If retouching was already started with a different - // value, we will not be allowed to override. This happens - // if on the retouch list there is a patched binary (which is - // masked in apply_patch()) before there is a non-patched - // binary. - if (retouch_offset_override != NULL) - *retouch_offset_override = inferred_offset; - success = true; - goto out; - } else { - // Retouch to zero (mask the retouching), to make sure that - // the SHA-1 check will pass below. - int32_t zero = 0; - retouch_mask_data(file.data, file.size, &zero, NULL); - SHA(file.data, file.size, file.sha1); - } - } - - if (retouch_probe_result == RETOUCH_DATA_NOTAPPLICABLE) { - // In the case of not retouchable, fake it. We do not want - // to do the normal processing and overwrite the backup file: - // we might be recovering! - // - // We return a zero override, which tells the caller that we - // simply skipped the file. - if (retouch_offset_override != NULL) - *retouch_offset_override = 0; - success = true; - goto out; - } - - // If we get here, either there was a mismatch in the offset, or - // the file has not been processed yet. Continue with normal - // processing. - } - - if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) { - free(file.data); - printf("Attempting to recover source from '%s' ...\n", - CACHE_TEMP_SOURCE); - result = LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK); - if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) { - printf(" failed.\n"); - success = false; - goto out; - } - printf(" succeeded.\n"); - } - - // Retouch in-memory before worrying about backing up the original. - // - // Recovery steps will be oblivious to the actual retouch offset used, - // so might as well write out the already-retouched copy. Then, in the - // usual case, we will just swap the file locally, with no more writes - // needed. In the no-free-space case, we will then write the same to the - // original location. - - result = retouch_mask_data(file.data, file.size, &retouch_offset, NULL); - if (result != RETOUCH_DATA_MATCHED) { - success = false; - goto out; - } - if (retouch_offset_override != NULL) - *retouch_offset_override = retouch_offset; - - // How much free space do we need? - bool enough_space = false; - size_t free_space = FreeSpaceForFile(target_fs); - // 50% margin when estimating the space needed. - enough_space = (free_space > (file.size * 3 / 2)); - - // The experts say we have to allow for a retry of the - // whole process to avoid filesystem weirdness. - int retry = 1; - bool made_copy = false; - do { - // First figure out where to store a copy of the original. - // Ideally leave the original itself intact until the - // atomic swap. If no room on the same partition, fall back - // to the cache partition and remove the original. - - if (!enough_space) { - printf("Target is %ldB; free space is %ldB: not enough.\n", - (long)file.size, (long)free_space); - - retry = 0; - if (MakeFreeSpaceOnCache(file.size) < 0) { - printf("Not enough free space on '/cache'.\n"); - success = false; - goto out; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, file) < 0) { - printf("Failed to back up source file.\n"); - success = false; - goto out; - } - made_copy = true; - unlink(binary_name); - - size_t free_space = FreeSpaceForFile(target_fs); - printf("(now %ld bytes free for target)\n", (long)free_space); - } - - result = SaveFileContents(binary_name_atomic, file); - if (result != 0) { - // Maybe the filesystem was optimistic: retry. - enough_space = false; - unlink(binary_name_atomic); - printf("Saving the retouched contents failed; retrying.\n"); - continue; - } - - // Succeeded; no need to retry. - break; - } while (retry-- > 0); - - // Give the .atomic file the same owner, group, and mode of the - // original source file. - if (chmod(binary_name_atomic, file.st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", - binary_name_atomic, strerror(errno)); - success = false; - goto out; - } - if (chown(binary_name_atomic, file.st.st_uid, file.st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", - binary_name_atomic, - strerror(errno)); - success = false; - goto out; - } - - // Finally, rename the .atomic file to replace the target file. - if (rename(binary_name_atomic, binary_name) != 0) { - printf("rename of .atomic to \"%s\" failed: %s\n", - binary_name, strerror(errno)); - success = false; - goto out; - } - - // If this run created a copy, and we're here, we can delete it. - if (made_copy) unlink(CACHE_TEMP_SOURCE); - - out: - // clean up - free(file.data); - unlink(binary_name_atomic); - - return success; -} diff --git a/minelf/Retouch.h b/minelf/Retouch.h index 048d78e44..13bacd5ad 100644 --- a/minelf/Retouch.h +++ b/minelf/Retouch.h @@ -25,12 +25,6 @@ typedef struct { uint32_t blob_size; /* in bytes, located right before this struct */ } retouch_info_t __attribute__((packed)); -// Retouch a file. Use CACHED_SOURCE_TEMP to store a copy. -bool retouch_one_library(const char *binary_name, - const char *binary_sha1, - int32_t retouch_offset, - int32_t *retouch_offset_override); - #define RETOUCH_DONT_MASK 0 #define RETOUCH_DO_MASK 1 diff --git a/minzip/Android.mk b/minzip/Android.mk index b1ee67439..6c1d0969c 100644 --- a/minzip/Android.mk +++ b/minzip/Android.mk @@ -11,7 +11,13 @@ LOCAL_SRC_FILES := \ LOCAL_C_INCLUDES += \ external/zlib \ external/safe-iop/include - + +ifeq ($(HAVE_SELINUX),true) +LOCAL_C_INCLUDES += external/libselinux/include +LOCAL_STATIC_LIBRARIES += libselinux +LOCAL_CFLAGS += -DHAVE_SELINUX +endif + LOCAL_MODULE := libminzip LOCAL_CFLAGS += -Wall diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c index 20c89cd6f..0d49b5780 100644 --- a/minzip/DirUtil.c +++ b/minzip/DirUtil.c @@ -54,7 +54,8 @@ getPathDirStatus(const char *path) int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName) + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle *sehnd) { DirStatus ds; @@ -144,7 +145,25 @@ dirCreateHierarchy(const char *path, int mode, } else if (ds == DMISSING) { int err; +#ifdef HAVE_SELINUX + char *secontext = NULL; + + if (sehnd) { + selabel_lookup(sehnd, &secontext, cpath, mode); + setfscreatecon(secontext); + } +#endif + err = mkdir(cpath, mode); + +#ifdef HAVE_SELINUX + + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } +#endif + if (err != 0) { free(cpath); return -1; diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h index 0d5ea7ccb..f8be64026 100644 --- a/minzip/DirUtil.h +++ b/minzip/DirUtil.h @@ -24,6 +24,13 @@ extern "C" { #endif +#ifdef HAVE_SELINUX +#include <selinux/selinux.h> +#include <selinux/label.h> +#else +struct selabel_handle; +#endif + /* Like "mkdir -p", try to guarantee that all directories * specified in path are present, creating as many directories * as necessary. The specified mode is passed to all mkdir @@ -38,7 +45,8 @@ extern "C" { * (usually if some element of path is not a directory). */ int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName); + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle* sehnd); /* rm -rf <path> */ diff --git a/minzip/Zip.c b/minzip/Zip.c index 46d2f829e..54d5d55a3 100644 --- a/minzip/Zip.c +++ b/minzip/Zip.c @@ -930,7 +930,8 @@ static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry) bool mzExtractRecursive(const ZipArchive *pArchive, const char *zipDir, const char *targetDir, int flags, const struct utimbuf *timestamp, - void (*callback)(const char *fn, void *), void *cookie) + void (*callback)(const char *fn, void *), void *cookie, + struct selabel_handle *sehnd) { if (zipDir[0] == '/') { LOGE("mzExtractRecursive(): zipDir must be a relative path.\n"); @@ -1045,7 +1046,7 @@ bool mzExtractRecursive(const ZipArchive *pArchive, if (pEntry->fileName[pEntry->fileNameLen-1] == '/') { if (!(flags & MZ_EXTRACT_FILES_ONLY)) { int ret = dirCreateHierarchy( - targetFile, UNZIP_DIRMODE, timestamp, false); + targetFile, UNZIP_DIRMODE, timestamp, false, sehnd); if (ret != 0) { LOGE("Can't create containing directory for \"%s\": %s\n", targetFile, strerror(errno)); @@ -1059,7 +1060,7 @@ bool mzExtractRecursive(const ZipArchive *pArchive, * the containing directory exists. */ int ret = dirCreateHierarchy( - targetFile, UNZIP_DIRMODE, timestamp, true); + targetFile, UNZIP_DIRMODE, timestamp, true, sehnd); if (ret != 0) { LOGE("Can't create containing directory for \"%s\": %s\n", targetFile, strerror(errno)); @@ -1113,7 +1114,25 @@ bool mzExtractRecursive(const ZipArchive *pArchive, /* The entry is a regular file. * Open the target for writing. */ + +#ifdef HAVE_SELINUX + char *secontext = NULL; + + if (sehnd) { + selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE); + setfscreatecon(secontext); + } +#endif + int fd = creat(targetFile, UNZIP_FILEMODE); + +#ifdef HAVE_SELINUX + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } +#endif + if (fd < 0) { LOGE("Can't create target file \"%s\": %s\n", targetFile, strerror(errno)); diff --git a/minzip/Zip.h b/minzip/Zip.h index 739dbf5f2..4bb9ef6a4 100644 --- a/minzip/Zip.h +++ b/minzip/Zip.h @@ -18,6 +18,13 @@ extern "C" { #endif +#ifdef HAVE_SELINUX +#include <selinux/selinux.h> +#include <selinux/label.h> +#else +struct selabel_handle; +#endif + /* * One entry in the Zip archive. Treat this as opaque -- use accessors below. * @@ -212,7 +219,8 @@ enum { MZ_EXTRACT_FILES_ONLY = 1, MZ_EXTRACT_DRY_RUN = 2 }; bool mzExtractRecursive(const ZipArchive *pArchive, const char *zipDir, const char *targetDir, int flags, const struct utimbuf *timestamp, - void (*callback)(const char *fn, void*), void *cookie); + void (*callback)(const char *fn, void*), void *cookie, + struct selabel_handle *sehnd); #ifdef __cplusplus } diff --git a/mtdutils/flash_image.c b/mtdutils/flash_image.c index c77687602..a39d60001 100644 --- a/mtdutils/flash_image.c +++ b/mtdutils/flash_image.c @@ -42,7 +42,7 @@ void die(const char *msg, ...) { } fprintf(stderr, "%s\n", buf); - LOGE("%s\n", buf); + ALOGE("%s\n", buf); exit(1); } @@ -74,23 +74,23 @@ int main(int argc, char **argv) { MtdReadContext *in = mtd_read_partition(partition); if (in == NULL) { - LOGW("error opening %s: %s\n", argv[1], strerror(errno)); + ALOGW("error opening %s: %s\n", argv[1], strerror(errno)); // just assume it needs re-writing } else { char check[HEADER_SIZE]; int checklen = mtd_read_data(in, check, sizeof(check)); if (checklen <= 0) { - LOGW("error reading %s: %s\n", argv[1], strerror(errno)); + ALOGW("error reading %s: %s\n", argv[1], strerror(errno)); // just assume it needs re-writing } else if (checklen == headerlen && !memcmp(header, check, headerlen)) { - LOGI("header is the same, not flashing %s\n", argv[1]); + ALOGI("header is the same, not flashing %s\n", argv[1]); return 0; } mtd_read_close(in); } // Skip the header (we'll come back to it), write everything else - LOGI("flashing %s from %s\n", argv[1], argv[2]); + ALOGI("flashing %s from %s\n", argv[1], argv[2]); MtdWriteContext *out = mtd_write_partition(partition); if (out == NULL) die("error writing %s", argv[1]); diff --git a/recovery.cpp b/recovery.cpp index 2b5c65c9f..ce4358a53 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -45,6 +45,8 @@ extern "C" { #include "minadbd/adb.h" } +struct selabel_handle *sehandle; + static const struct option OPTIONS[] = { { "send_intent", required_argument, NULL, 's' }, { "update_package", required_argument, NULL, 'u' }, @@ -140,7 +142,7 @@ fopen_path(const char *path, const char *mode) { // When writing, try to create the containing directory, if necessary. // Use generous permissions, the system (init.rc) will reset them. - if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1); + if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1, sehandle); FILE *fp = fopen(path, mode); return fp; @@ -684,6 +686,10 @@ prompt_and_wait(Device* device) { break; case Device::APPLY_EXT: + // Some packages expect /cache to be mounted (eg, + // standard incremental packages expect to use /cache + // as scratch space). + ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -803,6 +809,19 @@ main(int argc, char **argv) { } } +#ifdef HAVE_SELINUX + struct selinux_opt seopts[] = { + { SELABEL_OPT_PATH, "/file_contexts" } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + + if (!sehandle) { + fprintf(stderr, "Warning: No file_contexts\n"); + ui->Print("Warning: No file_contexts\n"); + } +#endif + device->StartRecovery(); printf("Command:"); @@ -31,6 +31,8 @@ static int num_volumes = 0; static Volume* device_volumes = NULL; +extern struct selabel_handle *sehandle; + static int parse_options(char* options, Volume* volume) { char* option; while ((option = strtok(options, ","))) { @@ -269,7 +271,7 @@ int format_volume(const char* volume) { } if (strcmp(v->fs_type, "ext4") == 0) { - int result = make_ext4fs(v->device, v->length); + int result = make_ext4fs(v->device, v->length, volume, sehandle); if (result != 0) { LOGE("format_volume: make_extf4fs failed on %s\n", v->device); return -1; diff --git a/updater/Android.mk b/updater/Android.mk index 8d731db3e..f8ccb76b5 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -24,6 +24,12 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_STATIC_LIBRARIES += libext4_utils libz endif +ifeq ($(HAVE_SELINUX), true) +LOCAL_C_INCLUDES += external/libselinux/include +LOCAL_STATIC_LIBRARIES += libselinux +LOCAL_CFLAGS += -DHAVE_SELINUX +endif # HAVE_SELINUX + LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz LOCAL_STATIC_LIBRARIES += libmincrypt libbz diff --git a/updater/install.c b/updater/install.c index f68bd03c8..f981017bf 100644 --- a/updater/install.c +++ b/updater/install.c @@ -33,7 +33,6 @@ #include "edify/expr.h" #include "mincrypt/sha.h" #include "minzip/DirUtil.h" -#include "minelf/Retouch.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" #include "updater.h" @@ -79,8 +78,24 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } +#ifdef HAVE_SELINUX + char *secontext = NULL; + + if (sehandle) { + selabel_lookup(sehandle, &secontext, mount_point, 0755); + setfscreatecon(secontext); + } +#endif + mkdir(mount_point, 0755); +#ifdef HAVE_SELINUX + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } +#endif + if (strcmp(partition_type, "MTD") == 0) { mtd_scan_partitions(); const MtdPartition* mtd; @@ -177,23 +192,25 @@ done: } -// format(fs_type, partition_type, location, fs_size) +// format(fs_type, partition_type, location, fs_size, mount_point) // -// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> -// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> +// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location> +// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location> // if fs_size == 0, then make_ext4fs uses the entire partition. // if fs_size > 0, that is the size to use // if fs_size < 0, then reserve that many bytes at the end of the partition Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; - if (argc != 4) { - return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc); + if (argc != 5) { + return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc); } char* fs_type; char* partition_type; char* location; char* fs_size; - if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &fs_size) < 0) { + char* mount_point; + + if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) { return NULL; } @@ -211,6 +228,11 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } + if (strlen(mount_point) == 0) { + ErrorAbort(state, "mount_point argument to %s() can't be empty", name); + goto done; + } + if (strcmp(partition_type, "MTD") == 0) { mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(location); @@ -240,7 +262,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { result = location; #ifdef USE_EXT4 } else if (strcmp(fs_type, "ext4") == 0) { - int status = make_ext4fs(location, atoll(fs_size)); + int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); if (status != 0) { fprintf(stderr, "%s: make_ext4fs failed (%d) on %s", name, status, location); @@ -347,7 +369,7 @@ Value* PackageExtractDirFn(const char* name, State* state, bool success = mzExtractRecursive(za, zip_path, dest_path, MZ_EXTRACT_FILES_ONLY, ×tamp, - NULL, NULL); + NULL, NULL, sehandle); free(zip_path); free(dest_path); return StringValue(strdup(success ? "t" : "")); @@ -435,121 +457,6 @@ Value* PackageExtractFileFn(const char* name, State* state, } -// retouch_binaries(lib1, lib2, ...) -Value* RetouchBinariesFn(const char* name, State* state, - int argc, Expr* argv[]) { - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - - char **retouch_entries = ReadVarArgs(state, argc, argv); - if (retouch_entries == NULL) { - return StringValue(strdup("t")); - } - - // some randomness from the clock - int32_t override_base; - bool override_set = false; - int32_t random_base = time(NULL) % 1024; - // some more randomness from /dev/random - FILE *f_random = fopen("/dev/random", "rb"); - uint16_t random_bits = 0; - if (f_random != NULL) { - fread(&random_bits, 2, 1, f_random); - random_bits = random_bits % 1024; - fclose(f_random); - } - random_base = (random_base + random_bits) % 1024; - fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base); - fprintf(ui->cmd_pipe, "ui_print\n"); - - // make sure we never randomize to zero; this let's us look at a file - // and know for sure whether it has been processed; important in the - // crash recovery process - if (random_base == 0) random_base = 1; - // make sure our randomization is page-aligned - random_base *= -0x1000; - override_base = random_base; - - int i = 0; - bool success = true; - while (i < (argc - 1)) { - success = success && retouch_one_library(retouch_entries[i], - retouch_entries[i+1], - random_base, - override_set ? - NULL : - &override_base); - if (!success) - ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]); - - free(retouch_entries[i]); - free(retouch_entries[i+1]); - i += 2; - - if (success && override_base != 0) { - random_base = override_base; - override_set = true; - } - } - if (i < argc) { - free(retouch_entries[i]); - success = false; - } - free(retouch_entries); - - if (!success) { - Value* v = malloc(sizeof(Value)); - v->type = VAL_STRING; - v->data = NULL; - v->size = -1; - return v; - } - return StringValue(strdup("t")); -} - - -// undo_retouch_binaries(lib1, lib2, ...) -Value* UndoRetouchBinariesFn(const char* name, State* state, - int argc, Expr* argv[]) { - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - - char **retouch_entries = ReadVarArgs(state, argc, argv); - if (retouch_entries == NULL) { - return StringValue(strdup("t")); - } - - int i = 0; - bool success = true; - int32_t override_base; - while (i < (argc-1)) { - success = success && retouch_one_library(retouch_entries[i], - retouch_entries[i+1], - 0 /* undo => offset==0 */, - NULL); - if (!success) - ErrorAbort(state, "Failed to unretouch '%s'.", - retouch_entries[i]); - - free(retouch_entries[i]); - free(retouch_entries[i+1]); - i += 2; - } - if (i < argc) { - free(retouch_entries[i]); - success = false; - } - free(retouch_entries); - - if (!success) { - Value* v = malloc(sizeof(Value)); - v->type = VAL_STRING; - v->data = NULL; - v->size = -1; - return v; - } - return StringValue(strdup("t")); -} - - // symlink target src1 src2 ... // unlinks any previously existing src1, src2, etc before creating symlinks. Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -566,21 +473,27 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { return NULL; } + int bad = 0; int i; for (i = 0; i < argc-1; ++i) { if (unlink(srcs[i]) < 0) { if (errno != ENOENT) { fprintf(stderr, "%s: failed to remove %s: %s\n", name, srcs[i], strerror(errno)); + ++bad; } } if (symlink(target, srcs[i]) < 0) { fprintf(stderr, "%s: failed to symlink %s to %s: %s\n", name, srcs[i], target, strerror(errno)); + ++bad; } free(srcs[i]); } free(srcs); + if (bad) { + return ErrorAbort(state, "%s: some symlinks failed", name); + } return StringValue(strdup("")); } @@ -599,6 +512,7 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { char* end; int i; + int bad = 0; int uid = strtoul(args[0], &end, 0); if (*end != '\0' || args[0][0] == 0) { @@ -640,10 +554,12 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { if (chown(args[i], uid, gid) < 0) { fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n", name, args[i], uid, gid, strerror(errno)); + ++bad; } if (chmod(args[i], mode) < 0) { fprintf(stderr, "%s: chmod of %s to %o failed: %s\n", name, args[i], mode, strerror(errno)); + ++bad; } } } @@ -655,6 +571,10 @@ done: } free(args); + if (bad) { + free(result); + return ErrorAbort(state, "%s: some changes failed", name); + } return StringValue(result); } @@ -1190,8 +1110,6 @@ void RegisterInstallFunctions() { RegisterFunction("delete_recursive", DeleteFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); - RegisterFunction("retouch_binaries", RetouchBinariesFn); - RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn); RegisterFunction("symlink", SymlinkFn); RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); diff --git a/updater/updater.c b/updater/updater.c index aa626d29b..5f1580870 100644 --- a/updater/updater.c +++ b/updater/updater.c @@ -32,6 +32,8 @@ // (Note it's "updateR-script", not the older "update-script".) #define SCRIPT_NAME "META-INF/com/google/android/updater-script" +struct selabel_handle *sehandle; + int main(int argc, char** argv) { // Various things log information to stdout or stderr more or less // at random. The log file makes more sense if buffering is @@ -103,6 +105,19 @@ int main(int argc, char** argv) { return 6; } +#ifdef HAVE_SELINUX + struct selinux_opt seopts[] = { + { SELABEL_OPT_PATH, "/file_contexts" } + }; + + sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + + if (!sehandle) { + fprintf(stderr, "Warning: No file_contexts\n"); + fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); + } +#endif + // Evaluate the parsed script. UpdaterInfo updater_info; diff --git a/updater/updater.h b/updater/updater.h index bd60dc1fd..a00872ca4 100644 --- a/updater/updater.h +++ b/updater/updater.h @@ -20,10 +20,19 @@ #include <stdio.h> #include "minzip/Zip.h" +#ifdef HAVE_SELINUX +#include <selinux/selinux.h> +#include <selinux/label.h> +#else +struct selabel_handle; +#endif + typedef struct { FILE* cmd_pipe; ZipArchive* package_zip; int version; } UpdaterInfo; +extern struct selabel_handle *sehandle; + #endif |