summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk16
-rw-r--r--applypatch/applypatch.c64
-rw-r--r--applypatch/applypatch.h4
-rw-r--r--etc/init.rc6
-rw-r--r--minelf/Retouch.c210
-rw-r--r--minelf/Retouch.h6
-rw-r--r--minzip/Android.mk8
-rw-r--r--minzip/DirUtil.c21
-rw-r--r--minzip/DirUtil.h10
-rw-r--r--minzip/Zip.c25
-rw-r--r--minzip/Zip.h10
-rw-r--r--mtdutils/flash_image.c10
-rw-r--r--recovery.cpp21
-rw-r--r--roots.cpp4
-rw-r--r--updater/Android.mk6
-rw-r--r--updater/install.c177
-rw-r--r--updater/updater.c15
-rw-r--r--updater/updater.h9
18 files changed, 241 insertions, 381 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/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, &copy_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,
+ &copy_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 = &copy_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 3f95372c5..baafadca0 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' },
@@ -138,7 +140,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;
@@ -682,6 +684,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");
@@ -799,6 +805,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:");
diff --git a/roots.cpp b/roots.cpp
index 9345cb0a2..ca37cf149 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -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..31f08b85f 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,25 +192,34 @@ 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
+// mount_point is used with SELinux as the location of the mount point, absent otherwise
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 != 4 && argc != 5) {
+ return ErrorAbort(state, "%s() expects 4 or 5 args, got %d", name, argc);
}
char* fs_type;
char* partition_type;
char* location;
char* fs_size;
+ char* mount_point = NULL;
+
+#ifdef HAVE_SELINUX
+ if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
+ return NULL;
+ }
+#else
if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &fs_size) < 0) {
return NULL;
}
+#endif
if (strlen(fs_type) == 0) {
ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
@@ -211,6 +235,13 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
+#ifdef HAVE_SELINUX
+ if (!mount_point || strlen(mount_point) == 0) {
+ ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
+ goto done;
+ }
+#endif
+
if (strcmp(partition_type, "MTD") == 0) {
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(location);
@@ -240,7 +271,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 +378,7 @@ Value* PackageExtractDirFn(const char* name, State* state,
bool success = mzExtractRecursive(za, zip_path, dest_path,
MZ_EXTRACT_FILES_ONLY, &timestamp,
- NULL, NULL);
+ NULL, NULL, sehandle);
free(zip_path);
free(dest_path);
return StringValue(strdup(success ? "t" : ""));
@@ -435,121 +466,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 +482,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 +521,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 +563,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 +580,10 @@ done:
}
free(args);
+ if (bad) {
+ free(result);
+ return ErrorAbort(state, "%s: some changes failed", name);
+ }
return StringValue(result);
}
@@ -1190,8 +1119,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