From e6594408d4464ce4583dd95d5a7b82713e2b738d Mon Sep 17 00:00:00 2001 From: Vojtech Bocek Date: Sun, 31 May 2015 20:55:42 +0200 Subject: [PATCH] Use different method to workaround "restorecon_recursive /data" * Inject entries for MultiROM folders into /file_contexts instead of editing *.rc files. * Thanks nkk71 for the suggestion. --- multirom.c | 11 ++- rom_quirks.c | 195 +++++++++++++-------------------------------------- rom_quirks.h | 2 +- 3 files changed, 53 insertions(+), 155 deletions(-) diff --git a/multirom.c b/multirom.c index ddf03ec..9da3e08 100644 --- a/multirom.c +++ b/multirom.c @@ -975,9 +975,7 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to { case ROM_DEFAULT: { - mount("/realdata", "/data", "", MS_BIND, ""); - rom_quirks_on_android_mounted_fs(to_boot); - umount("/data"); + rom_quirks_on_initrd_finalized(); break; } case ROM_LINUX_INTERNAL: @@ -997,7 +995,7 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to if(multirom_create_media_link() == -1) return -1; - rom_quirks_on_android_mounted_fs(to_boot); + rom_quirks_on_initrd_finalized(); } if(to_boot->partition) @@ -2321,9 +2319,10 @@ next_itr: int multirom_mount_usb(struct usb_partition *part) { mkdir("/mnt", 0777); + mkdir("/mnt/mrom", 0777); char path[256]; - sprintf(path, "/mnt/%s", part->name); + snprintf(path, sizeof(path), "/mnt/mrom/%s", part->name); if(mkdir(path, 0777) != 0 && errno != EEXIST) { ERROR("Failed to create dir for mount %s\n", path); @@ -2331,7 +2330,7 @@ int multirom_mount_usb(struct usb_partition *part) } char src[256]; - sprintf(src, "/dev/block/%s", part->name); + snprintf(src, sizeof(src), "/dev/block/%s", part->name); if(strncmp(part->fs, "ntfs", 4) == 0) { diff --git a/rom_quirks.c b/rom_quirks.c index 0ea84e0..92f0fc7 100644 --- a/rom_quirks.c +++ b/rom_quirks.c @@ -22,141 +22,11 @@ #include #include #include -#include -#include "multirom.h" #include "rom_quirks.h" #include "lib/log.h" #include "lib/util.h" -#define MULTIROM_DIR_ANDROID "/data/media/0/multirom" -#define MULTIROM_DIR_ANDROID_LEN 22 -#define RESTORECON_LAST "security.restorecon_last" -#define RESTORECON_LAST_HACK_PATH "/data/media" -#define RESTORECON_LAST_HACK_PATH_LEN 11 - -static void write_changed_restorecons(const char *path, FILE *rc) -{ - struct dirent *dt; - char *next_path = 0; - size_t new_len, allocd = 0; - const int path_len = strlen(path); - DIR *d = opendir(path); - if(!d) - return; - - while((dt = readdir(d))) - { - if(strcmp(dt->d_name, ".") == 0 || strcmp(dt->d_name, "..") == 0) - continue; - - if(dt->d_type == DT_DIR) - { - new_len = imax((size_t)(path_len + strlen(dt->d_name) + 2), allocd); - if(new_len > allocd) - { - next_path = realloc(next_path, new_len); - allocd = new_len; - } - - snprintf(next_path, allocd, "%s/%s", path, dt->d_name); - const int next_path_len = strlen(next_path); - - if(strncmp(next_path, MULTIROM_DIR_ANDROID, next_path_len) == 0) - { - if(next_path_len != MULTIROM_DIR_ANDROID_LEN) - { - fprintf(rc, " restorecon \"%s/%s\"\n", path, dt->d_name); - write_changed_restorecons(next_path, rc); - } - } - else - { - fprintf(rc, " restorecon_recursive \"%s/%s\"\n", path, dt->d_name); - - // restorecon_recursive works only if RESTORECON_LAST xattr contains hash - // different from current file_contexts. Because /data/media/ is shared - // among multiple ROMs, this doesn't work well because some ROMs don't - // set this xattr, so restorecon thinks nothing changed but it did. - if (strncmp(next_path, RESTORECON_LAST_HACK_PATH, RESTORECON_LAST_HACK_PATH_LEN) == 0 && - (next_path[RESTORECON_LAST_HACK_PATH_LEN] == 0 || next_path[RESTORECON_LAST_HACK_PATH_LEN] == '/')) - { - removexattr(next_path, RESTORECON_LAST); - } - } - } - else - fprintf(rc, " restorecon \"%s/%s\"\n", path, dt->d_name); - } - - closedir(d); - free(next_path); -} - -static void workaround_rc_restorecon(const char *rc_file_name) -{ - FILE *f_in, *f_out; - char *name_out = NULL; - char line[512]; - char *r; - int changed = 0; - - f_in = fopen(rc_file_name, "re"); - if(!f_in) - { - ERROR("Failed to open input file %s\n", rc_file_name); - return; - } - - name_out = malloc(strlen(rc_file_name)+5); - snprintf(name_out, strlen(rc_file_name)+5, "%s.new", rc_file_name); - - f_out = fopen(name_out, "we"); - if(!f_out) - { - ERROR("Failed to open output file %s\n", name_out); - fclose(f_in); - free(name_out); - return; - } - - while(fgets(line, sizeof(line), f_in)) - { - r = strstr(line, "restorecon_recursive"); - if(r) - { - r += strlen("restorecon_recursive"); - - while(*r && isspace(*r)) - ++r; - - if(strcmp(r, "/data\n") == 0) - { - changed = 1; - fputc('#', f_out); - fputs(line, f_out); - write_changed_restorecons("/data", f_out); - } - else - fputs(line, f_out); - } - else - fputs(line, f_out); - } - - fclose(f_out); - fclose(f_in); - - if(changed) - { - rename(name_out, rc_file_name); - chmod(rc_file_name, 0750); - } - else - unlink(name_out); - free(name_out); -} - static void workaround_mount_in_sh(const char *path) { char line[512]; @@ -191,21 +61,51 @@ static void workaround_mount_in_sh(const char *path) free(tmp_name); } -void rom_quirks_on_android_mounted_fs(struct multirom_rom *rom) +static void inject_file_contexts(void) { - // CyanogenMod has init script 50selinuxrelabel which calls - // restorecon on /data. On secondary ROMs, /system is placed - // inside /data/media/ and mount-binded to /system, so restorecon - // sets contexts to files in /system as if they were in /data. - // This behaviour is there mainly because of old recoveries which - // didn't set contexts properly, so it should be safe to remove - // that file entirely. - if(rom->type != ROM_ANDROID_USB_IMG && access("/system/etc/init.d/50selinuxrelabel", F_OK) >= 0) + FILE *f; + char line[512]; + + f = fopen("/file_contexts", "re"); + if(!f) { - INFO("Removing /system/etc/init.d/50selinuxrelabel.\n"); - remove("/system/etc/init.d/50selinuxrelabel"); + ERROR("Failed to open /file_contexts!"); + return; } + while(fgets(line, sizeof(line), f)) + { + if(strstartswith(line, "/data/media/multirom")) + { + INFO("/file_contexts has been already injected."); + fclose(f); + return; + } + } + + fclose(f); + + INFO("Injecting /file_contexts"); + f = fopen("/file_contexts", "ae"); + if(!f) + { + ERROR("Failed to open /file_contexts for appending!"); + return; + } + + fputs("\n" + "# MultiROM folders\n" + "/data/media/multirom(/.*)? <>\n" + "/data/media/0/multirom(/.*)? <>\n" + "/realdata/media/multirom(/.*)? <>\n" + "/realdata/media/0/multirom(/.*)? <>\n" + "/mnt/mrom(/.*)? <>\n", + f); + fclose(f); +} + +void rom_quirks_on_initrd_finalized(void) +{ // walk over all _regular_ files in / DIR *d = opendir("/"); if(d) @@ -217,20 +117,19 @@ void rom_quirks_on_android_mounted_fs(struct multirom_rom *rom) if(dt->d_type != DT_REG) continue; - // The Android L preview (and presumably later releases) have SELinux + // The Android L and later releases have SELinux // set to "enforcing" and "restorecon_recursive /data" line in init.rc. // Restorecon on /data goes into /data/media/0/multirom/roms/ and changes // context of all secondary ROMs files to that of /data, including the files // in secondary ROMs /system dirs. We need to prevent that. - if(strstr(dt->d_name, ".rc")) - { - snprintf(buff, sizeof(buff), "/%s", dt->d_name); - workaround_rc_restorecon(buff); - } + // Right now, we do that by adding entries into /file_contexts that say + // MultiROM folders don't have any context + if(strcmp(dt->d_name, "file_contexts") == 0) + inject_file_contexts(); // franco.Kernel includes script init.fk.sh which remounts /system as read only // comment out lines with mount and /system in all .sh scripts in / - if(strendswith(dt->d_name, ".sh") && (M(rom->type) & MASK_ANDROID) && rom->type != ROM_ANDROID_USB_IMG) + if(strendswith(dt->d_name, ".sh")) { snprintf(buff, sizeof(buff), "/%s", dt->d_name); workaround_mount_in_sh(buff); diff --git a/rom_quirks.h b/rom_quirks.h index 6d1dbdc..820e629 100644 --- a/rom_quirks.h +++ b/rom_quirks.h @@ -19,6 +19,6 @@ struct multirom_rom; -void rom_quirks_on_android_mounted_fs(struct multirom_rom *rom); +void rom_quirks_on_initrd_finalized(void); #endif