diff --git a/.gitmodules b/.gitmodules index 30599bb5..e585ac40 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/Tasssadar/kexec-tools [submodule "adbd"] path = adbd - url = https://github.com/multirom-dev/multirom_adbd.git + url = https://github.com/vasishath/adbd diff --git a/Android.mk b/Android.mk index 7a0b6cf7..3c3382de 100644 --- a/Android.mk +++ b/Android.mk @@ -9,6 +9,7 @@ LOCAL_C_INCLUDES += $(multirom_local_path) \ external/libpng \ external/zlib \ external/freetype/include \ + external/selinux/libselinux/include \ $(multirom_local_path)/lib LOCAL_SRC_FILES:= \ @@ -22,6 +23,7 @@ LOCAL_SRC_FILES:= \ pong.c \ rcadditions.c \ rom_quirks.c \ + rq_inject_file_contexts.c \ # With these, GCC optimizes aggressively enough so full-screen alpha blending # is quick enough to be done in an animation @@ -30,15 +32,21 @@ LOCAL_CFLAGS += -O3 -funsafe-math-optimizations #LOCAL_CFLAGS += -D_FORTIFY_SOURCE=2 -fstack-protector-all -O0 -g -fno-omit-frame-pointer -Wall LOCAL_MODULE:= multirom -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libcutils libc libmultirom_static +LOCAL_STATIC_LIBRARIES := libcutils libc libmultirom_static libselinux LOCAL_WHOLE_STATIC_LIBRARIES := libm libcutils libpng libz libft2_mrom_static +ifeq ($(MR_FIRMWARE_DIR),) + LOCAL_CFLAGS += -DMR_FIRMWARE_DIR="/firmware" +else + LOCAL_CFLAGS += -DMR_FIRMWARE_DIR="\"$(MR_FIRMWARE_DIR)\"" +endif + # clone libbootimg to /system/extras/ from # https://github.com/Tasssadar/libbootimg.git LOCAL_STATIC_LIBRARIES += libbootimg diff --git a/adbd b/adbd index 9c842501..402203d5 160000 --- a/adbd +++ b/adbd @@ -1 +1 @@ -Subproject commit 9c842501f8255a7e531466d9b831295ee094ce88 +Subproject commit 402203d54640cf18d51d18e4aa55729ab460c2c2 diff --git a/device_defines.mk b/device_defines.mk index 77e8596b..c29157b5 100644 --- a/device_defines.mk +++ b/device_defines.mk @@ -87,6 +87,12 @@ else LOCAL_CFLAGS += -DMULTIROM_DEFAULT_BRIGHTNESS=40 endif +ifneq ($(TW_MAX_BRIGHTNESS),) + LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=\"$(TW_MAX_BRIGHTNESS)\" +else + LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=255 +endif + ifneq ($(MR_INPUT_ROTATION),) LOCAL_CFLAGS += -DMR_INPUT_ROTATION=$(MR_INPUT_ROTATION) endif diff --git a/install_zip/Android.mk b/install_zip/Android.mk index 4bd60be8..e6344dc8 100644 --- a/install_zip/Android.mk +++ b/install_zip/Android.mk @@ -16,14 +16,27 @@ multirom_extra_dep := ifeq ($(MR_ENCRYPTION),true) multirom_extra_dep += trampoline_encmnt linker + multirom_cp_enc_libs := \ + libcryptfslollipop.so libcrypto.so libext4_utils.so libsparse.so libext2_uuid.so libe4crypt.so libc.so libcutils.so \ + libdl.so libhardware.so liblog.so libm.so libstdc++.so \ + libc++.so libwifikeystorehal.so libsoftkeymasterdevice.so android.system.wifi.keystore@1.0.so android.hardware.weaver@1.0.so + + ifeq ($(TARGET_HW_DISK_ENCRYPTION),true) + multirom_cp_enc_libs += \ + libunwind.so libbase.so libbacktrace.so \ + libutils.so libcryptfs_hw.so + endif + ifeq ($(MR_ENCRYPTION_FAKE_PROPERTIES),true) multirom_extra_dep += libmultirom_fake_properties - else - MR_ENCRYPTION_FAKE_PROPERTIES := false + multirom_cp_enc_libs += libmultirom_fake_properties.so + multirom_extra_dep += libmultirom_fake_propertywait + multirom_cp_enc_libs += libmultirom_fake_propertywait.so + multirom_extra_dep += libmultirom_fake_logger + multirom_cp_enc_libs += libmultirom_fake_logger.so endif else MR_ENCRYPTION := false - MR_ENCRYPTION_FAKE_PROPERTIES := false endif MR_DEVICES := $(TARGET_DEVICE) @@ -42,46 +55,65 @@ $(MULTIROM_ZIP_TARGET): multirom trampoline signapk bbootimg mrom_kexec_static m @echo @echo ----- Making MultiROM ZIP installer ------ - rm -rf $(MULTIROM_INST_DIR) - mkdir -p $(MULTIROM_INST_DIR) - cp -a $(install_zip_path)/prebuilt-installer/* $(MULTIROM_INST_DIR)/ - cp -a $(TARGET_ROOT_OUT)/multirom $(MULTIROM_INST_DIR)/multirom/ - cp -a $(TARGET_ROOT_OUT)/trampoline $(MULTIROM_INST_DIR)/multirom/ - cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/mrom_kexec_static $(MULTIROM_INST_DIR)/multirom/kexec - cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/mrom_adbd $(MULTIROM_INST_DIR)/multirom/adbd - - if $(MR_ENCRYPTION); then \ + @rm -rf $(MULTIROM_INST_DIR) + @mkdir -p $(MULTIROM_INST_DIR) + @echo Copying primary files + @cp -a $(install_zip_path)/prebuilt-installer/* $(MULTIROM_INST_DIR)/ + @cp -a $(TARGET_ROOT_OUT)/multirom $(MULTIROM_INST_DIR)/multirom/ + @cp -a $(TARGET_ROOT_OUT)/trampoline $(MULTIROM_INST_DIR)/multirom/ + @cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/mrom_kexec_static $(MULTIROM_INST_DIR)/multirom/kexec + @cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/mrom_adbd $(MULTIROM_INST_DIR)/multirom/adbd + + @if $(MR_ENCRYPTION); then \ + echo "Copying decryption files"; \ mkdir -p $(MULTIROM_INST_DIR)/multirom/enc/res; \ cp -a $(TARGET_ROOT_OUT)/trampoline_encmnt $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_EXECUTABLES)/linker $(MULTIROM_INST_DIR)/multirom/enc/; \ + \ cp -a $(install_zip_path)/prebuilt-installer/multirom/res/Roboto-Regular.ttf $(MULTIROM_INST_DIR)/multirom/enc/res/; \ \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libcryptfslollipop.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libcrypto.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libc.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libcutils.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libdl.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libhardware.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/liblog.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libm.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libstdc++.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libc++.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - if $(MR_ENCRYPTION_FAKE_PROPERTIES); then \ - cp -a $(TARGET_OUT_SHARED_LIBRARIES)/libmultirom_fake_properties.so $(MULTIROM_INST_DIR)/multirom/enc/; \ - fi; \ + for f in $(multirom_cp_enc_libs); do \ + if [ -f "$(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/$$f" ]; then \ + cp -a $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)/$$f $(MULTIROM_INST_DIR)/multirom/enc/; \ + else \ + cp -a $(TARGET_OUT_SHARED_LIBRARIES)/$$f $(MULTIROM_INST_DIR)/multirom/enc/; \ + fi; \ + done; \ if [ -n "$(MR_ENCRYPTION_SETUP_SCRIPT)" ]; then sh "$(ANDROID_BUILD_TOP)/$(MR_ENCRYPTION_SETUP_SCRIPT)" "$(ANDROID_BUILD_TOP)" "$(MULTIROM_INST_DIR)/multirom/enc"; fi; \ + \ + if [ "$(TARGET_IS_64_BIT)" == "true" ]; then \ + cp -a $(TARGET_OUT_EXECUTABLES)/linker64 $(MULTIROM_INST_DIR)/multirom/enc/; \ + echo "Relinking trampoline_encmnt /system/bin/linker64 to /mrom_enc/linker64"; \ + sed -i "s|/system/bin/linker64\x0|/mrom_enc/linker64\x0\x0\x0|g" $(MULTIROM_INST_DIR)/multirom/enc/trampoline_encmnt; \ + if [ -f "$(MULTIROM_INST_DIR)/multirom/enc/qseecomd" ]; then \ + echo "Relinking qseecomd /system/bin/linker64 to /mrom_enc/linker64"; \ + sed -i "s|/system/bin/linker64\x0|/mrom_enc/linker64\x0\x0\x0|g" $(MULTIROM_INST_DIR)/multirom/enc/qseecomd; \ + fi; \ + else \ + cp -a $(TARGET_OUT_EXECUTABLES)/linker $(MULTIROM_INST_DIR)/multirom/enc/; \ + echo "Relinking trampoline_encmnt /system/bin/linker to /mrom_enc/linker"; \ + sed -i "s|/system/bin/linker\x0|/mrom_enc/linker\x0\x0\x0|g" $(MULTIROM_INST_DIR)/multirom/enc/trampoline_encmnt; \ + if [ -f "$(MULTIROM_INST_DIR)/multirom/enc/qseecomd" ]; then \ + echo "Relinking qseecomd /system/bin/linker to /mrom_enc/linker"; \ + sed -i "s|/system/bin/linker\x0|/mrom_enc/linker\x0\x0\x0|g" $(MULTIROM_INST_DIR)/multirom/enc/qseecomd; \ + fi; \ + fi; \ + \ fi - mkdir $(MULTIROM_INST_DIR)/multirom/infos - if [ -n "$(MR_INFOS)" ]; then cp -r $(PWD)/$(MR_INFOS)/* $(MULTIROM_INST_DIR)/multirom/infos/; fi - cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/bbootimg $(MULTIROM_INST_DIR)/scripts/ - cp $(PWD)/$(MR_FSTAB) $(MULTIROM_INST_DIR)/multirom/mrom.fstab - $(install_zip_path)/extract_boot_dev.sh $(PWD)/$(MR_FSTAB) $(MULTIROM_INST_DIR)/scripts/bootdev - $(install_zip_path)/make_updater_script.sh "$(MR_DEVICES)" $(MULTIROM_INST_DIR)/META-INF/com/google/android "Installing MultiROM for" - rm -f $(MULTIROM_ZIP_TARGET).zip $(MULTIROM_ZIP_TARGET)-unsigned.zip - cd $(MULTIROM_INST_DIR) && zip -qr ../$(notdir $@)-unsigned.zip * - java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar $(DEFAULT_SYSTEM_DEV_CERTIFICATE).x509.pem $(DEFAULT_SYSTEM_DEV_CERTIFICATE).pk8 $(MULTIROM_ZIP_TARGET)-unsigned.zip $(MULTIROM_ZIP_TARGET).zip - $(install_zip_path)/rename_zip.sh $(MULTIROM_ZIP_TARGET) $(TARGET_DEVICE) $(PWD)/$(multirom_local_path)/version.h $(MR_DEVICE_SPECIFIC_VERSION) + @echo Copying info files + @mkdir $(MULTIROM_INST_DIR)/multirom/infos + @if [ -n "$(MR_INFOS)" ]; then cp -vr $(PWD)/$(MR_INFOS)/* $(MULTIROM_INST_DIR)/multirom/infos/; fi + @echo Copying scripts + @cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/bbootimg $(MULTIROM_INST_DIR)/scripts/ + @cp $(PWD)/$(MR_FSTAB) $(MULTIROM_INST_DIR)/multirom/mrom_fsbat + @echo Preparing installer script + @$(install_zip_path)/extract_boot_dev.sh $(PWD)/$(MR_FSTAB) $(MULTIROM_INST_DIR)/scripts/bootdev + @$(install_zip_path)/make_updater_script.sh "$(MR_DEVICES)" $(MULTIROM_INST_DIR)/META-INF/com/google/android "Installing MultiROM for" + @echo Signing flashable zip + @rm -f $(MULTIROM_ZIP_TARGET).zip $(MULTIROM_ZIP_TARGET)-unsigned.zip + @cd $(MULTIROM_INST_DIR) && zip -qr ../$(notdir $@)-unsigned.zip * + @java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar --min-sdk-version 26 $(DEFAULT_SYSTEM_DEV_CERTIFICATE).x509.pem $(DEFAULT_SYSTEM_DEV_CERTIFICATE).pk8 $(MULTIROM_ZIP_TARGET)-unsigned.zip $(MULTIROM_ZIP_TARGET).zip + @$(install_zip_path)/rename_zip.sh $(MULTIROM_ZIP_TARGET) $(TARGET_DEVICE) $(PWD)/$(multirom_local_path)/version.h $(MR_DEVICE_SPECIFIC_VERSION) @echo ----- Made MultiROM ZIP installer -------- $@.zip .PHONY: multirom_zip @@ -94,16 +126,19 @@ MULTIROM_UNINST_DIR := $(PRODUCT_OUT)/multirom_uninstaller $(MULTIROM_UNINST_TARGET): signapk bbootimg @echo ----- Making MultiROM uninstaller ------ - rm -rf $(MULTIROM_UNINST_DIR) - mkdir -p $(MULTIROM_UNINST_DIR) - cp -a $(install_zip_path)/prebuilt-uninstaller/* $(MULTIROM_UNINST_DIR)/ - cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/bbootimg $(MULTIROM_UNINST_DIR)/scripts/ - $(install_zip_path)/extract_boot_dev.sh $(PWD)/$(MR_FSTAB) $(MULTIROM_UNINST_DIR)/scripts/bootdev - echo $(MR_RD_ADDR) > $(MULTIROM_UNINST_DIR)/scripts/rd_addr - $(install_zip_path)/make_updater_script.sh "$(MR_DEVICES)" $(MULTIROM_UNINST_DIR)/META-INF/com/google/android "MultiROM uninstaller -" - rm -f $(MULTIROM_UNINST_TARGET).zip $(MULTIROM_UNINST_TARGET)-unsigned.zip - cd $(MULTIROM_UNINST_DIR) && zip -qr ../$(notdir $@)-unsigned.zip * - java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar $(DEFAULT_SYSTEM_DEV_CERTIFICATE).x509.pem $(DEFAULT_SYSTEM_DEV_CERTIFICATE).pk8 $(MULTIROM_UNINST_TARGET)-unsigned.zip $(MULTIROM_UNINST_TARGET).zip + @rm -rf $(MULTIROM_UNINST_DIR) + @mkdir -p $(MULTIROM_UNINST_DIR) + @echo Copying files + @cp -a $(install_zip_path)/prebuilt-uninstaller/* $(MULTIROM_UNINST_DIR)/ + @cp -a $(TARGET_OUT_OPTIONAL_EXECUTABLES)/bbootimg $(MULTIROM_UNINST_DIR)/scripts/ + @echo Preparing installer script + @$(install_zip_path)/extract_boot_dev.sh $(PWD)/$(MR_FSTAB) $(MULTIROM_UNINST_DIR)/scripts/bootdev + @echo $(MR_RD_ADDR) > $(MULTIROM_UNINST_DIR)/scripts/rd_addr + @$(install_zip_path)/make_updater_script.sh "$(MR_DEVICES)" $(MULTIROM_UNINST_DIR)/META-INF/com/google/android "MultiROM uninstaller -" + @echo Signing flashable zip + @rm -f $(MULTIROM_UNINST_TARGET).zip $(MULTIROM_UNINST_TARGET)-unsigned.zip + @cd $(MULTIROM_UNINST_DIR) && zip -qr ../$(notdir $@)-unsigned.zip * + @java -Djava.library.path=$(SIGNAPK_JNI_LIBRARY_PATH) -jar $(HOST_OUT_JAVA_LIBRARIES)/signapk.jar --min-sdk-version 26 $(DEFAULT_SYSTEM_DEV_CERTIFICATE).x509.pem $(DEFAULT_SYSTEM_DEV_CERTIFICATE).pk8 $(MULTIROM_UNINST_TARGET)-unsigned.zip $(MULTIROM_UNINST_TARGET).zip @echo ----- Made MultiROM uninstaller -------- $@.zip .PHONY: multirom_uninstaller diff --git a/install_zip/prebuilt-installer/multirom/icons/romic_android.png b/install_zip/prebuilt-installer/multirom/icons/romic_android.png index 0b55c4bc..ce6d4ba2 100644 Binary files a/install_zip/prebuilt-installer/multirom/icons/romic_android.png and b/install_zip/prebuilt-installer/multirom/icons/romic_android.png differ diff --git a/install_zip/prebuilt-installer/multirom/icons/romic_android_default.png b/install_zip/prebuilt-installer/multirom/icons/romic_android_default.png new file mode 100644 index 00000000..3cbaea1e Binary files /dev/null and b/install_zip/prebuilt-installer/multirom/icons/romic_android_default.png differ diff --git a/install_zip/prebuilt-installer/multirom/icons/romic_android_old.png b/install_zip/prebuilt-installer/multirom/icons/romic_android_old.png new file mode 100644 index 00000000..0b55c4bc Binary files /dev/null and b/install_zip/prebuilt-installer/multirom/icons/romic_android_old.png differ diff --git a/install_zip/prebuilt-installer/scripts/extract_multirom.sh b/install_zip/prebuilt-installer/scripts/extract_multirom.sh index 6cd08071..3a5db8c6 100644 --- a/install_zip/prebuilt-installer/scripts/extract_multirom.sh +++ b/install_zip/prebuilt-installer/scripts/extract_multirom.sh @@ -1,15 +1,33 @@ #!/sbin/sh +cont="" base="" -if [ -d "/data/media/multirom" ] ; then - base="/data/media/multirom" -elif [ -d "/data/media/0/multirom" ] ; then - base="/data/media/0/multirom" + +# Move old installation of multirom to MultiROM/multirom +if [ -d "/data/media/multirom" ] && [ ! -d "/data/media/MultiROM/multirom" ]; then + mkdir "/data/media/MultiROM" + mv "/data/media/multirom" "/data/media/MultiROM/multirom" +elif [ -d "/data/media/0/multirom" ] && [ ! -d "/data/media/0/MultiROM/multirom" ]; then + mkdir "/data/media/0/MultiROM" + mv "/data/media/0/multirom" "/data/media/0/MultiROM/multirom" +elif [ -d "/data/media/0/MultiROM/multirom" ] && [ ! -d "/data/media/MultiROM/multirom" ]; then + mkdir "/data/media/MultiROM" + mv "/data/media/0/MultiROM/multirom" "/data/media/MultiROM/multirom" +fi + +# Check for existing dirs otherwise create them +if [ -d "/data/media/MultiROM/multirom" ] ; then + cont="/data/media/MultiROM" + base="/data/media/MultiROM/multirom" +elif [ -d "/data/media/0/MultiROM/multirom" ] ; then + cont="/data/media/0/MultiROM" + base="/data/media/0/MultiROM/multirom" else - if [ -d "/data/media/0" ] ; then - base="/data/media/0/multirom" - else - base="/data/media/multirom" - fi + cont="/data/media/MultiROM" + base="/data/media/MultiROM/multirom" + + mkdir "$cont" + chown root:root "$cont" + chmod 770 "$cont" mkdir "$base" chown root:root "$base" @@ -18,11 +36,9 @@ else mkdir "$base/roms" chown media_rw:media_rw "$base/roms" chmod 777 "$base/roms" - - touch "$base/.nomedia" - chown media_rw:media_rw "$base/.nomedia" fi +# Main installation rm "$base/boot.img-ubuntu"* rm "$base/infos/"* rm "$base/res/"* @@ -41,7 +57,20 @@ chmod 644 "$base/ubuntu-touch-init/scripts/touch" chmod 755 "$base/ubuntu-touch-sysimage-init/init" chmod 644 "$base/ubuntu-touch-sysimage-init/scripts/touch" +# Remove immutable flag so we can chmod and chown +chattr -i "$cont" + # This makes does not allows access for media scanner on android, but # still is enough for ubuntu +chmod 770 "$cont" +chown root:root "$cont" +touch "$cont/.nomedia" +chown media_rw:media_rw "$cont/.nomedia" + chmod 770 "$base" chown root:root "$base" +touch "$base/.nomedia" +chown media_rw:media_rw "$base/.nomedia" + +# Make the parent/container folder immutable to prevent sdcardfs uid/gid derivation +chattr +i "$cont" diff --git a/install_zip/prebuilt-uninstaller/scripts/clear_boot.sh b/install_zip/prebuilt-uninstaller/scripts/clear_boot.sh index f927a831..1fc82d77 100644 --- a/install_zip/prebuilt-uninstaller/scripts/clear_boot.sh +++ b/install_zip/prebuilt-uninstaller/scripts/clear_boot.sh @@ -65,8 +65,8 @@ if [ -L /tmp/boot/sbin/watchdogd ] ; then ln -sf ../init /tmp/boot/sbin/watchdogd fi -if [ -e /tmp/boot/mrom.fstab ] ; then - rm /tmp/boot/mrom.fstab +if [ -e /tmp/boot/mrom_fsbat ] ; then + rm /tmp/boot/mrom_fsbat fi # Remove encryption files diff --git a/install_zip/prebuilt-uninstaller/scripts/erase_multirom.sh b/install_zip/prebuilt-uninstaller/scripts/erase_multirom.sh index 7ef0aad5..8348f673 100644 --- a/install_zip/prebuilt-uninstaller/scripts/erase_multirom.sh +++ b/install_zip/prebuilt-uninstaller/scripts/erase_multirom.sh @@ -1,6 +1,10 @@ #!/sbin/sh base="" -if [ -d "/data/media/multirom" ] ; then +if [ -d "/data/media/MultiROM" ] ; then + base="/data/media/MultiROM" +elif [ -d "/data/media/0/MultiROM" ] ; then + base="/data/media/0/MultiROM" +elif [ -d "/data/media/multirom" ] ; then base="/data/media/multirom" elif [ -d "/data/media/0/multirom" ] ; then base="/data/media/0/multirom" diff --git a/kernel_inject/Android.mk b/kernel_inject/Android.mk index ad443940..b8084b74 100644 --- a/kernel_inject/Android.mk +++ b/kernel_inject/Android.mk @@ -10,7 +10,7 @@ LOCAL_SRC_FILES:= \ kernel_inject.c \ LOCAL_MODULE:= kernel_inject -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) diff --git a/lib/Android.mk b/lib/Android.mk index 3c5be35c..65e5ef54 100644 --- a/lib/Android.mk +++ b/lib/Android.mk @@ -21,11 +21,13 @@ common_SRC_FILES := \ touch_tracker.c \ util.c \ workers.c \ + klog.c \ common_C_INCLUDES := $(multirom_local_path)/lib \ external/libpng \ external/zlib \ external/freetype/include \ + external/selinux/libselinux/include \ system/extras/libbootimg/include \ # With these, GCC optimizes aggressively enough so full-screen alpha blending @@ -54,15 +56,26 @@ endif endif +ifeq ($(MR_DEVICE_HAS_DRM_GRAPHICS),true) + common_C_FLAGS += -DMR_DEVICE_HAS_DRM_GRAPHICS + common_C_INCLUDES += \ + external/libdrm \ + external/libdrm/include/drm + common_SRC_FILES += \ + drm.c +endif include $(CLEAR_VARS) LOCAL_MODULE := libmultirom_static -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) LOCAL_CFLAGS += $(common_C_FLAGS) LOCAL_C_INCLUDES += $(common_C_INCLUDES) +ifeq ($(MR_DEVICE_HAS_DRM_GRAPHICS),true) +LOCAL_WHOLE_STATIC_LIBRARIES := libdrm_platform +endif LOCAL_SRC_FILES := $(common_SRC_FILES) MR_NO_KEXEC_MK_OPTIONS := true 1 allowed 2 enabled 3 ui_confirm 4 ui_choice 5 forced @@ -78,13 +91,25 @@ include $(multirom_local_path)/device_defines.mk include $(BUILD_STATIC_LIBRARY) +include $(CLEAR_VARS) + +LOCAL_MODULE := libmultirom_fake_logger +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := fake_logger.c +LOCAL_SRC_FILES += klog.c + + +include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libmultirom -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := libcutils libc libm libpng libz libft2 +ifeq ($(MR_DEVICE_HAS_DRM_GRAPHICS),true) +LOCAL_WHOLE_STATIC_LIBRARIES := libdrm_platform +endif LOCAL_CFLAGS += $(common_C_FLAGS) LOCAL_SRC_FILES := $(common_SRC_FILES) LOCAL_C_INCLUDES += $(common_C_INCLUDES) diff --git a/lib/drm.c b/lib/drm.c new file mode 100644 index 00000000..9a062b2e --- /dev/null +++ b/lib/drm.c @@ -0,0 +1,603 @@ +/* + * Copyright (C) 2015 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "framebuffer.h" +#include "log.h" +#include "util.h" + +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) + +typedef struct GRSurface { + int width; + int height; + int row_bytes; + int pixel_bytes; + unsigned char* data; //This is the actual FB +} GRSurface; + +typedef struct drm_surface { + GRSurface base; + uint32_t fb_id; + uint32_t handle; +}drm_surface; + +static drm_surface *drm_surfaces[2]; +static int current_buffer; +static GRSurface *draw_buf = NULL; + +static drmModeCrtc *main_monitor_crtc; +static drmModeConnector *main_monitor_connector; + +static int drm_fd = -1; + +static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { + if (crtc) { + drmModeSetCrtc(drm_fd, crtc->crtc_id, + 0, // fb_id + 0, 0, // x,y + NULL, // connectors + 0, // connector_count + NULL); // mode + } +} + +static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc, + struct drm_surface *surface) { + int32_t ret; + + ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, + surface->fb_id, + 0, 0, // x,y + &main_monitor_connector->connector_id, + 1, // connector_count + &main_monitor_crtc->mode); + + if (ret) + INFO("drmModeSetCrtc failed ret=%d\n", ret); +} + +static void drm_blank(bool blank, int buffer) { + if (blank) + drm_disable_crtc(drm_fd, main_monitor_crtc); + else + drm_enable_crtc(drm_fd, main_monitor_crtc, + drm_surfaces[buffer]); +} + +static void drm_destroy_surface(struct drm_surface *surface) { + struct drm_gem_close gem_close; + int ret; + + if(!surface) + return; + + if (surface->base.data) + munmap(surface->base.data, + surface->base.row_bytes * surface->base.height); + + if (surface->fb_id) { + ret = drmModeRmFB(drm_fd, surface->fb_id); + if (ret) + INFO("drmModeRmFB failed ret=%d\n", ret); + } + + if (surface->handle) { + memset(&gem_close, 0, sizeof(gem_close)); + gem_close.handle = surface->handle; + + ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret) + INFO("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret); + } + + free(surface); +} + +static int drm_format_to_bpp(uint32_t format) { + switch(format) { + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + return 32; + case DRM_FORMAT_RGB565: + return 16; + default: + INFO("Unknown format %d\n", format); + return 32; + } +} + +static drm_surface *drm_create_surface(int width, int height) { + struct drm_surface *surface; + struct drm_mode_create_dumb create_dumb; + uint32_t format; + int ret; + + surface = (struct drm_surface*)calloc(1, sizeof(*surface)); + if (!surface) { + INFO("Can't allocate memory\n"); + return NULL; + } + +#if defined(RECOVERY_ABGR) + format = DRM_FORMAT_RGBA8888; + INFO("setting DRM_FORMAT_RGBA8888 and GGL_PIXEL_FORMAT_RGBA_8888\n"); +#elif defined(RECOVERY_BGRA) + format = DRM_FORMAT_ARGB8888; + INFO("setting DRM_FORMAT_ARGB8888 and GGL_PIXEL_FORMAT_RGBA_8888\n"); +#elif defined(RECOVERY_RGBA) + format = DRM_FORMAT_ABGR8888; + INFO("setting DRM_FORMAT_ABGR8888 and GGL_PIXEL_FORMAT_BGRA_8888, GGL_PIXEL_FORMAT may not match!\n"); +#elif defined(RECOVERY_RGBX) + format = DRM_FORMAT_XBGR8888; + INFO("setting DRM_FORMAT_XBGR8888 and GGL_PIXEL_FORMAT_BGRA_8888, GGL_PIXEL_FORMAT may not match!\n"); +#else + format = DRM_FORMAT_RGB565; + INFO("setting DRM_FORMAT_RGB565 and GGL_PIXEL_FORMAT_RGB_565\n"); +#endif + + memset(&create_dumb, 0, sizeof(create_dumb)); + create_dumb.height = height; + create_dumb.width = width; + create_dumb.bpp = drm_format_to_bpp(format); + create_dumb.flags = 0; + + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret) { + INFO("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL; + } + surface->handle = create_dumb.handle; + + uint32_t handles[4], pitches[4], offsets[4]; + + handles[0] = surface->handle; + pitches[0] = create_dumb.pitch; + offsets[0] = 0; + + ret = drmModeAddFB2(drm_fd, width, height, + format, handles, pitches, offsets, + &(surface->fb_id), 0); + if (ret) { + INFO("drmModeAddFB2 failed ret=%d\n", ret); + drm_destroy_surface(surface); + return NULL; + } + + struct drm_mode_map_dumb map_dumb; + memset(&map_dumb, 0, sizeof(map_dumb)); + map_dumb.handle = create_dumb.handle; + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + if (ret) { + INFO("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL;; + } + + surface->base.height = height; + surface->base.width = width; + surface->base.row_bytes = create_dumb.pitch; + surface->base.pixel_bytes = create_dumb.bpp / 8; + surface->base.data = (unsigned char*) + mmap(NULL, + surface->base.height * surface->base.row_bytes, + PROT_READ | PROT_WRITE, MAP_SHARED, + drm_fd, map_dumb.offset); + if (surface->base.data == MAP_FAILED) { + perror("mmap() failed"); + drm_destroy_surface(surface); + return NULL; + } + + return surface; +} + +static drmModeCrtc *find_crtc_for_connector(int fd, + drmModeRes *resources, + drmModeConnector *connector) { + int i, j; + drmModeEncoder *encoder; + int32_t crtc; + + /* + * Find the encoder. If we already have one, just use it. + */ + if (connector->encoder_id) + encoder = drmModeGetEncoder(fd, connector->encoder_id); + else + encoder = NULL; + + if (encoder && encoder->crtc_id) { + crtc = encoder->crtc_id; + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + + /* + * Didn't find anything, try to find a crtc and encoder combo. + */ + crtc = -1; + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + + if (encoder) { + for (j = 0; j < resources->count_crtcs; j++) { + if (!(encoder->possible_crtcs & (1 << j))) + continue; + crtc = resources->crtcs[j]; + break; + } + if (crtc >= 0) { + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + } + } + + return NULL; +} + +static drmModeConnector *find_used_connector_by_type(int fd, + drmModeRes *resources, + unsigned type) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->connector_type == type) && + (connector->connection == DRM_MODE_CONNECTED) && + (connector->count_modes > 0)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_first_connected_connector(int fd, + drmModeRes *resources) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->count_modes > 0) && + (connector->connection == DRM_MODE_CONNECTED)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources, + uint32_t *mode_index) { + unsigned i = 0; + int modes; + /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */ + unsigned kConnectorPriority[] = { + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_DSI, + }; + + drmModeConnector *main_monitor_connector = NULL; + do { + main_monitor_connector = find_used_connector_by_type(fd, + resources, + kConnectorPriority[i]); + i++; + } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority)); + + /* If we didn't find a connector, grab the first one that is connected. */ + if (!main_monitor_connector) + main_monitor_connector = + find_first_connected_connector(fd, resources); + + /* If we still didn't find a connector, give up and return. */ + if (!main_monitor_connector) + return NULL; + + *mode_index = 0; + for (modes = 0; modes < main_monitor_connector->count_modes; modes++) { + if (main_monitor_connector->modes[modes].type & + DRM_MODE_TYPE_PREFERRED) { + *mode_index = modes; + break; + } + } + + return main_monitor_connector; +} + +static void disable_non_main_crtcs(int fd, + drmModeRes *resources, + drmModeCrtc* main_crtc) { + int i; + drmModeCrtc* crtc; + + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + crtc = find_crtc_for_connector(fd, resources, connector); + if (crtc->crtc_id != main_crtc->crtc_id) + drm_disable_crtc(fd, crtc); + drmModeFreeCrtc(crtc); + } +} + +static int drm_init(struct framebuffer *fb) { + drmModeRes *res = NULL; + uint32_t selected_mode; + char *dev_name; + int width, height; + int ret, i; + + /* Consider DRM devices in order. */ + for (i = 0; i < DRM_MAX_MINOR; i++) { + uint64_t cap = 0; + + ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i); + INFO("trying %s\n", dev_name); + if (ret < 0) + continue; + + drm_fd = open(dev_name, O_RDWR, 0); + free(dev_name); + if (drm_fd < 0) { + INFO("open failed with error %s", strerror(errno)); + continue; + } + + /* We need dumb buffers. */ + ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + close(drm_fd); + continue; + } + + res = drmModeGetResources(drm_fd); + if (!res) { + close(drm_fd); + continue; + } + + /* Use this device if it has at least one connected monitor. */ + if (res->count_crtcs > 0 && res->count_connectors > 0) + if (find_first_connected_connector(drm_fd, res)) + break; + + drmModeFreeResources(res); + close(drm_fd); + res = NULL; + } + + if (drm_fd < 0 || res == NULL) { + perror("cannot find/open a drm device"); + return -1; + } + + main_monitor_connector = find_main_monitor(drm_fd, + res, &selected_mode); + + if (!main_monitor_connector) { + INFO("main_monitor_connector not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return -1; + } + + main_monitor_crtc = find_crtc_for_connector(drm_fd, res, + main_monitor_connector); + + if (!main_monitor_crtc) { + INFO("main_monitor_crtc not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return -1; + } + + disable_non_main_crtcs(drm_fd, + res, main_monitor_crtc); + + INFO("selected mode %d\n", selected_mode); + main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; + + width = main_monitor_crtc->mode.hdisplay; + height = main_monitor_crtc->mode.vdisplay; + + drmModeFreeResources(res); + + drm_surfaces[0] = drm_create_surface(width, height); + drm_surfaces[1] = drm_create_surface(width, height); + if (!drm_surfaces[0] || !drm_surfaces[1]) { + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeResources(res); + close(drm_fd); + return -1; + } + + draw_buf = (GRSurface *)malloc(sizeof(GRSurface)); + if (!draw_buf) { + INFO("failed to alloc draw_buf\n"); + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeResources(res); + close(drm_fd); + return -1; + } + + memcpy(draw_buf, &drm_surfaces[0]->base, sizeof(GRSurface)); + + /*Assign framebuffer properties here to maintain compatibility*/ + + fb_width = draw_buf->width; + fb_height = draw_buf->height; + fb->stride = draw_buf->row_bytes / draw_buf->pixel_bytes; + fb->size = draw_buf->height * draw_buf->row_bytes * draw_buf->pixel_bytes; + fb->vi.bits_per_pixel = draw_buf->pixel_bytes * 8; + fb->vi.xres = fb_width; + fb->vi.yres = fb_height; + fb->vi.xres_virtual = fb_width; + fb->vi.yres_virtual = fb_height; + INFO("Pixel format: %dx%d @ %dbpp\n", fb->vi.xres, fb->vi.yres, fb->vi.bits_per_pixel); + +#ifdef RECOVERY_BGRA + INFO("Pixel format: BGRA_8888\n"); + fb->vi.red.offset = 8; + fb->vi.red.length = 8; + fb->vi.green.offset = 16; + fb->vi.green.length = 8; + fb->vi.blue.offset = 24; + fb->vi.blue.length = 8; + fb->vi.transp.offset = 0; + fb->vi.transp.length = 8; +#elif defined(RECOVERY_RGBX) + INFO("Pixel format: RGBX_8888\n"); + fb->vi.red.offset = 24; + fb->vi.red.length = 8; + fb->vi.green.offset = 16; + fb->vi.green.length = 8; + fb->vi.blue.offset = 8; + fb->vi.blue.length = 8; + fb->vi.transp.offset = 0; + fb->vi.transp.length = 8; +#elif defined(RECOVERY_RGBA) + INFO("Pixel format: RGBA_8888\n"); + fb->vi.red.offset = 0; + fb->vi.red.length = 8; + fb->vi.green.offset = 8; + fb->vi.green.length = 8; + fb->vi.blue.offset = 16; + fb->vi.blue.length = 8; + fb->vi.transp.offset = 24; + fb->vi.transp.length = 8; +#elif defined(RECOVERY_RGB_565) + INFO("Pixel format: RGB_565\n"); + fb->vi.blue.offset = 0; + fb->vi.green.offset = 5; + fb->vi.red.offset = 11; + fb->vi.blue.length = 5; + fb->vi.green.length = 6; + fb->vi.red.length = 5; + fb->vi.blue.msb_right = 0; + fb->vi.green.msb_right = 0; + fb->vi.red.msb_right = 0; + fb->vi.transp.offset = 0; + fb->vi.transp.length = 0; +#elif defined(RECOVERY_ABGR) + INFO("Pixel format: ABGR_8888\n"); + fb->vi.red.offset = 0; + fb->vi.red.length = 8; + fb->vi.green.offset = 8; + fb->vi.green.length = 8; + fb->vi.blue.offset = 16; + fb->vi.blue.length = 8; + fb->vi.transp.offset = 24; + fb->vi.transp.length = 8; +#else +#error "Unknown pixel format" +#endif + + + draw_buf->data = (unsigned char *)calloc(draw_buf->height * draw_buf->row_bytes, 1); + if (!draw_buf->data) { + INFO("failed to alloc draw_buf surface\n"); + free(draw_buf); + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeResources(res); + close(drm_fd); + return -1; + } + + drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); + + current_buffer = 0; + + return 0; +} + +static int drm_update(struct framebuffer *fb) { + int ret; + + memcpy(drm_surfaces[current_buffer]->base.data, + draw_buf->data, draw_buf->height * draw_buf->row_bytes); + + + ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, + drm_surfaces[current_buffer]->fb_id, 0, NULL); + + if (ret < 0) { + ERROR("drmModePageFlip failed ret=%d\n", ret); + return -1; + } + + current_buffer = 1 - current_buffer; + + return 0; +} + +static void* drm_get_frame_dest(struct framebuffer *fb) { + + return draw_buf->data; +} + +static void drm_exit(struct framebuffer *fb) { + drm_disable_crtc(drm_fd, main_monitor_crtc); + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeCrtc(main_monitor_crtc); + drmModeFreeConnector(main_monitor_connector); + close(drm_fd); + drm_fd = -1; +} + +const struct fb_impl fb_impl_drm = { + .name = "Drm", + .impl_id = FB_IMPL_DRM, + .open = drm_init, + .close = drm_exit, + .update = drm_update, + .get_frame_dest = drm_get_frame_dest, +}; diff --git a/lib/fake_logger.c b/lib/fake_logger.c new file mode 100644 index 00000000..347ee78f --- /dev/null +++ b/lib/fake_logger.c @@ -0,0 +1,18 @@ +#include + +#define LOG_BUF_MAX 51200 +extern void multirom_klog_write(int level, const char* fmt, ...); +extern void multirom_klog_set_level(int level); +#define INFO(tag, fmt, ...) multirom_klog_write(6, "<6>%s: " fmt, tag, ##__VA_ARGS__) + +int __android_log_print(int prio, const char* tag, const char* fmt, ...) { + + char buf[LOG_BUF_MAX]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + buf[LOG_BUF_MAX - 1] = 0; + INFO(tag, "%s", buf); + return 0; +} diff --git a/lib/framebuffer.c b/lib/framebuffer.c index b0123502..48215499 100644 --- a/lib/framebuffer.c +++ b/lib/framebuffer.c @@ -95,9 +95,13 @@ int fb_open_impl(void) extern struct fb_impl fb_impl_ ## N; \ impls[ID] = &fb_impl_ ## N; +#ifdef MR_DEVICE_HAS_DRM_GRAPHICS + ADD_IMPL(FB_IMPL_DRM, drm); +#else ADD_IMPL(FB_IMPL_GENERIC, generic); #ifdef MR_USE_QCOM_OVERLAY ADD_IMPL(FB_IMPL_QCOM_OVERLAY, qcom_overlay); +#endif #endif if(fb_force_generic) @@ -123,6 +127,7 @@ int fb_open(int rotation) { memset(&fb, 0, sizeof(struct framebuffer)); +#ifndef MR_DEVICE_HAS_DRM_GRAPHICS fb.fd = open("/dev/graphics/fb0", O_RDWR | O_CLOEXEC); if (fb.fd < 0) return -1; @@ -174,6 +179,11 @@ int fb_open(int rotation) fb.stride = (fb_rotation%180 == 0) ? fb.vi.xres_virtual : fb.vi.yres; fb.size = fb.vi.xres_virtual*fb.vi.yres*PIXEL_SIZE; +#else + if(fb_open_impl() < 0) + goto fail; +#endif + fb.buffer = malloc(fb.size); fb_memset(fb.buffer, fb_convert_color(BLACK), fb.size); @@ -248,6 +258,7 @@ void fb_dump_info(void) void fb_set_brightness(int val) { + val = (val/255) * atoi(TW_MAX_BRIGHTNESS); #ifdef TW_BRIGHTNESS_PATH FILE *f = fopen(TW_BRIGHTNESS_PATH, "we"); if(!f) @@ -615,12 +626,9 @@ void fb_draw_rect(fb_rect *r) if(alpha == 0) return; -#if defined(RECOVERY_RGBX) || (RECOVERY_RGBA) || defined(RECOVERY_ABGR) +#if defined(RECOVERY_RGBX) || (RECOVERY_RGBA) || defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) const uint32_t premult_color_rb = ((color & 0xFF00FF) * (alpha)) >> 8; const uint32_t premult_color_g = ((color & 0x00FF00) * (alpha)) >> 8; -#elif defined(RECOVERY_BGRA) - const uint32_t premult_color_rb = (((color >> 8) & 0xFF00FF) * (alpha)) >> 8; - const uint32_t premult_color_g = (((color >> 8) & 0x00FF00) * (alpha)) >> 8; #elif defined(RECOVERY_RGB_565) const uint8_t alpha5b = (alpha >> 3) + 1; const uint8_t alpha6b = (alpha >> 2) + 1; @@ -660,14 +668,10 @@ void fb_draw_rect(fb_rect *r) #else for(x = 0; x < rendered_w; ++x) { - #if defined(RECOVERY_RGBX) || defined(RECOVERY_RGBA) || defined(RECOVERY_ABGR) + #if defined(RECOVERY_RGBX) || defined(RECOVERY_RGBA) || defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) const uint32_t rb = (premult_color_rb & 0xFF00FF) + ((inv_alpha * (*bits & 0xFF00FF)) >> 8); const uint32_t g = (premult_color_g & 0x00FF00) + ((inv_alpha * (*bits & 0x00FF00)) >> 8); *bits = 0xFF000000 | (rb & 0xFF00FF) | (g & 0x00FF00); - #elif defined(RECOVERY_BGRA) - const uint32_t rb = (premult_color_rb & 0xFF00FF) + ((inv_alpha * ((*bits >> 8) & 0xFF00FF)) >> 8); - const uint32_t g = (premult_color_g & 0x00FF00) + ((inv_alpha * ((*bits >> 8) & 0x00FF00)) >> 8); - *bits = 0xFF000000 | (rb & 0xFF00FF) | (g & 0x00FF00); #elif defined(RECOVERY_RGB_565) const uint16_t rb = (premult_color_rb & 0xF81F) + ((inv_alpha5b * (*bits & 0xF81F)) >> 5); const uint16_t g = (premult_color_g & 0x7E0) + ((inv_alpha6b * (*bits & 0x7E0)) >> 6); diff --git a/lib/framebuffer.h b/lib/framebuffer.h index f96e5bb6..544f482e 100644 --- a/lib/framebuffer.h +++ b/lib/framebuffer.h @@ -102,6 +102,9 @@ enum #ifdef MR_USE_QCOM_OVERLAY FB_IMPL_QCOM_OVERLAY, #endif +#ifdef MR_DEVICE_HAS_DRM_GRAPHICS + FB_IMPL_DRM, +#endif FB_IMPL_GENERIC, // must be last diff --git a/lib/fstab.c b/lib/fstab.c index a3fdaf3e..22847559 100644 --- a/lib/fstab.c +++ b/lib/fstab.c @@ -338,8 +338,8 @@ struct fstab *fstab_auto_load(void) char path[64]; path[0] = 0; - if(access("/mrom.fstab", F_OK) >= 0) - strcpy(path, "/mrom.fstab"); + if(access("/mrom_fsbat", F_OK) >= 0) + strcpy(path, "/mrom_fsbat"); else { DIR *d = opendir("/"); diff --git a/lib/inject.c b/lib/inject.c index 25523222..be217244 100644 --- a/lib/inject.c +++ b/lib/inject.c @@ -50,7 +50,7 @@ static int get_img_trampoline_ver(struct bootimg *img) return ver; } -static int copy_rd_files(UNUSED const char *path, UNUSED const char *busybox_path) +static int copy_rd_files(UNUSED const char *path, const char *target) { char buf[256]; char path_dir[64]; @@ -58,33 +58,26 @@ static int copy_rd_files(UNUSED const char *path, UNUSED const char *busybox_pat char path_main[64]; char path_mrom_enc[64]; char path_mrom_fstab[64]; + char path_hwservice_contexts[64]; + char path_nonplat_hwservice_contexts[64]; char path_ueventd[64]; char path_watchdog[64]; - if (access(TMP_RD2, F_OK) != -1) - { - snprintf(path_dir, sizeof(path_dir), TMP_RD2_UNPACKED_DIR); - snprintf(path_init, sizeof(path_init), TMP_RD2_UNPACKED_DIR "/init"); - snprintf(path_main, sizeof(path_main), TMP_RD2_UNPACKED_DIR "/main_init"); - snprintf(path_mrom_enc, sizeof(path_mrom_enc), TMP_RD2_UNPACKED_DIR "/mrom_enc"); - snprintf(path_mrom_fstab, sizeof(path_mrom_fstab), TMP_RD2_UNPACKED_DIR "/mrom.fstab"); - snprintf(path_ueventd, sizeof(path_ueventd), TMP_RD2_UNPACKED_DIR "/sbin/ueventd"); - snprintf(path_watchdog, sizeof(path_watchdog), TMP_RD2_UNPACKED_DIR "/sbin/watchdogd"); - } - else - { - snprintf(path_dir, sizeof(path_dir), TMP_RD_UNPACKED_DIR); - if (access(TMP_RD_UNPACKED_DIR "/init.real", F_OK) != -1) { - snprintf(path_init, sizeof(path_init), TMP_RD_UNPACKED_DIR "/init.real"); - } else { - snprintf(path_init, sizeof(path_init), TMP_RD_UNPACKED_DIR "/init"); - } - snprintf(path_main, sizeof(path_main), TMP_RD_UNPACKED_DIR "/main_init"); - snprintf(path_mrom_enc, sizeof(path_mrom_enc), TMP_RD_UNPACKED_DIR "/mrom_enc"); - snprintf(path_mrom_fstab, sizeof(path_mrom_fstab), TMP_RD_UNPACKED_DIR "/mrom.fstab"); - snprintf(path_ueventd, sizeof(path_ueventd), TMP_RD_UNPACKED_DIR "/sbin/ueventd"); - snprintf(path_watchdog, sizeof(path_watchdog), TMP_RD_UNPACKED_DIR "/sbin/watchdogd"); + + snprintf(path_dir, sizeof(path_dir), "%s", target); + snprintf(path_init, sizeof(path_init), "%s%s", target, "/init.real"); + if (access(path_init, F_OK) != -1) { + snprintf(path_init, sizeof(path_init), "%s%s", target, "/init.real"); + } else { + snprintf(path_init, sizeof(path_init), "%s%s", target, "/init"); } + snprintf(path_main, sizeof(path_main), "%s%s", target, "/main_init"); + snprintf(path_mrom_enc, sizeof(path_mrom_enc), "%s%s", target, "/mrom_enc"); + snprintf(path_mrom_fstab, sizeof(path_mrom_fstab), "%s%s", target, "/mrom_fsbat"); + snprintf(path_hwservice_contexts, sizeof(path_hwservice_contexts), "%s%s", target, "/plat_hwservice_contexts"); + snprintf(path_nonplat_hwservice_contexts, sizeof(path_nonplat_hwservice_contexts), "%s%s", target, "/nonplat_hwservice_contexts"); + snprintf(path_ueventd, sizeof(path_ueventd), "%s%s", target, "/sbin/ueventd"); + snprintf(path_watchdog, sizeof(path_watchdog), "%s%s", target, "/sbin/watchdogd"); if (access(path_main, F_OK) < 0 && rename(path_init, path_main)) @@ -106,11 +99,15 @@ static int copy_rd_files(UNUSED const char *path, UNUSED const char *busybox_pat symlink("../main_init", path_watchdog); #ifdef MR_USE_MROM_FSTAB - snprintf(buf, sizeof(buf), "%s/mrom.fstab", mrom_dir()); + snprintf(buf, sizeof(buf), "%s/mrom_fsbat", mrom_dir()); copy_file(buf, path_mrom_fstab); #else remove(path_mrom_fstab); #endif + snprintf(buf, sizeof(buf), "%s/plat_hwservice_contexts", mrom_dir()); + copy_file(buf, path_hwservice_contexts); + snprintf(buf, sizeof(buf), "%s/nonplat_hwservice_contexts", mrom_dir()); + copy_file(buf, path_nonplat_hwservice_contexts); #ifdef MR_ENCRYPTION remove_dir(path_mrom_enc); @@ -126,21 +123,13 @@ static int copy_rd_files(UNUSED const char *path, UNUSED const char *busybox_pat #define RD_GZIP 1 #define RD_LZ4 2 -static int inject_second_rd(const char *path, const char *second_path) -{ - int result = -1; - uint32_t magic = 0; - FILE *f = fopen(path, "re"); - if(!f) - { - ERROR("Couldn't open %s!\n", path); - return -1; - } - fread(&magic, sizeof(magic), 1, f); - fclose(f); +int decompress_second_rd(const char* target, const char *second_path) { + int result = -1; - mkdir(TMP_RD2_UNPACKED_DIR, 0755); + char second_unpacked_dir[256]; + sprintf(second_unpacked_dir, "%s/%s", target, "second"); + mkdir(second_unpacked_dir, 0755); // Decompress initrd int type; @@ -148,10 +137,10 @@ static int inject_second_rd(const char *path, const char *second_path) char busybox_path[256]; snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); - char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; - snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" cat \"%s\" | \"$B\" cpio -i", busybox_path, TMP_RD2_UNPACKED_DIR, second_path); + snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" cat \"%s\" | \"$B\" cpio -i", busybox_path, second_unpacked_dir, second_path); + char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; int r; char *out = run_get_stdout_with_exit(cmd, &r); if (r != 0) @@ -159,33 +148,48 @@ static int inject_second_rd(const char *path, const char *second_path) ERROR("Output: %s\n", out); ERROR("Failed to unpack second ramdisk!%s\n", buff); goto fail; + } else { + return 0; } +fail: + remove_dir(second_unpacked_dir); + return result; +} - // Update files - if (copy_rd_files(second_path, busybox_path) < 0) - { - goto fail; - } +int pack_second_rd(const char *second_path, const char* unpacked_dir) { + int result = -1; + char second_unpacked_dir[256]; + sprintf(second_unpacked_dir, "%s/%s", unpacked_dir, "second"); // Pack initrd again - snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc > \"%s\"", busybox_path, TMP_RD2_UNPACKED_DIR, second_path); + char buff[256]; + char busybox_path[256]; + snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); + snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc > \"%s\"", busybox_path, second_unpacked_dir, second_path); - out = run_get_stdout_with_exit(cmd, &r); + char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; + int r; + char *out = run_get_stdout_with_exit(cmd, &r); if (r != 0) { ERROR("Output: %s\n", out); ERROR("Failed to pack ramdisk.cpio!\n"); goto fail; + } else { + return 0; } success: result = 0; fail: - remove_dir(TMP_RD2_UNPACKED_DIR); + remove_dir(second_unpacked_dir); return result; + } -static int inject_rd(const char *path, const char *second_path) -{ + + +int decompress_rd(const char *path, const char* target, int* type) { + int result = -1; uint32_t magic = 0; @@ -198,26 +202,24 @@ static int inject_rd(const char *path, const char *second_path) fread(&magic, sizeof(magic), 1, f); fclose(f); - remove_dir(TMP_RD_UNPACKED_DIR); - mkdir(TMP_RD_UNPACKED_DIR, 0755); + remove_dir(target); + mkdir(target, 0755); // Decompress initrd - int type; char buff[256]; char busybox_path[256]; snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); - char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; if((magic & 0xFFFF) == 0x8B1F) { - type = RD_GZIP; - snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" gzip -d -c \"%s\" | \"$B\" cpio -i", busybox_path, TMP_RD_UNPACKED_DIR, path); + *type = RD_GZIP; + snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" gzip -d -c \"%s\" | \"$B\" cpio -i", busybox_path, target, path); } else if(magic == 0x184C2102) { - type = RD_LZ4; - snprintf(buff, sizeof(buff), "cd \"%s\"; \"%s/lz4\" -d \"%s\" stdout | \"%s\" cpio -i", TMP_RD_UNPACKED_DIR, mrom_dir(), path, busybox_path); + *type = RD_LZ4; + snprintf(buff, sizeof(buff), "cd \"%s\"; \"%s/lz4\" -d \"%s\" stdout | \"%s\" cpio -i", target, mrom_dir(), path, busybox_path); } else { @@ -225,6 +227,7 @@ static int inject_rd(const char *path, const char *second_path) goto success; } + char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; int r = run_cmd(cmd); if(r != 0) { @@ -232,43 +235,112 @@ static int inject_rd(const char *path, const char *second_path) goto fail; } - if (access(TMP_RD2, F_OK) != -1) + char second_path[256]; + sprintf(second_path, "%s/%s", target, "sbin/ramdisk.cpio"); + if (access(second_path, F_OK) != -1) { - if (inject_second_rd(path, second_path) < 0) + if (decompress_second_rd(target, second_path) < 0) { goto fail; + } else { + return 0; } + } else { + return 0; } - else if (copy_rd_files(path, busybox_path) < 0) +success: + result = 0; +fail: + remove_dir(target); + return result; +} + +int pack_rd(const char *path, const char *target, int type) { + + // Pack ramdisk + char second_path[256]; + sprintf(second_path, "%s/%s", target, "sbin/ramdisk.cpio"); + if (access(second_path, F_OK) != -1) { - goto fail; + pack_second_rd(second_path, target); } - // Pack ramdisk + char buff[256]; + char busybox_path[256]; + snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); switch (type) { case RD_GZIP: - snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"$B\" gzip > \"%s\"", busybox_path, TMP_RD_UNPACKED_DIR, path); + snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"$B\" gzip > \"%s\"", busybox_path, target, path); break; case RD_LZ4: - snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"%s/lz4\" stdin \"%s\"", busybox_path, TMP_RD_UNPACKED_DIR, mrom_dir(), path); + snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"%s/lz4\" stdin \"%s\"", busybox_path, target, mrom_dir(), path); break; } + char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; + int r; r = run_cmd(cmd); if(r != 0) { ERROR("Failed to pack ramdisk!\n"); + return -1; + } else { + return 0; + } +} + + +static int inject_rd(const char *path) +{ + int result = -1; + int type; + + char *copy_target; + if (decompress_rd(path, TMP_RD_UNPACKED_DIR, &type)) { goto fail; } + if (!access(TMP_RD2_UNPACKED_DIR, F_OK)) { + copy_target = TMP_RD2_UNPACKED_DIR; + } else { + copy_target = TMP_RD_UNPACKED_DIR; + } + + if (copy_rd_files(path, copy_target) < 0) + { + goto fail; + } + + if (pack_rd(path, TMP_RD_UNPACKED_DIR, type) < 0) { + goto fail; + } + + success: result = 0; fail: - remove_dir(TMP_RD_UNPACKED_DIR); return result; } +int inject_cmdline(struct bootimg *image) +{ + int res = 0; + char* custom_cmdline = "printk.devkmsg=on androidboot.android_dt_dir=/fakefsbat/"; + + char* cmdline = libbootimg_get_cmdline(&image->hdr); + char* newcmdline = NULL; + if (!strstr(cmdline, custom_cmdline)) { + asprintf(&newcmdline, "%s %s", cmdline, custom_cmdline); + + libbootimg_set_cmdline(&image->hdr, newcmdline); + free(newcmdline); + free(cmdline); + } + + return res; +} + int inject_bootimg(const char *img_path, int force) { int res = -1; @@ -312,7 +384,7 @@ int inject_bootimg(const char *img_path, int force) goto exit; } - if(inject_rd(initrd_tmp_name, initrd2_tmp_name) >= 0) + if(inject_rd(initrd_tmp_name) >= 0 && inject_cmdline(&img) == 0) { // Update the boot.img snprintf((char*)img.hdr.name, BOOT_NAME_SIZE, "tr_ver%d", VERSION_TRAMPOLINE); diff --git a/lib/inject.h b/lib/inject.h index 6b2f6c49..7313be98 100644 --- a/lib/inject.h +++ b/lib/inject.h @@ -19,5 +19,9 @@ #define INJECT_H int inject_bootimg(const char *img_path, int force); +int decompress_second_rd(const char* target, const char *second_path); +int pack_second_rd(const char *second_path, const char* unpacked_dir); +int decompress_rd(const char *path, const char* target, int* type); +int pack_rd(const char *path, const char *target, int type); #endif diff --git a/lib/klog.c b/lib/klog.c new file mode 100644 index 00000000..fff10d71 --- /dev/null +++ b/lib/klog.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +static int klog_fd = -1; +static int klog_level = 6; + +int multirom_klog_get_level(void) { + return klog_level; +} + +void multirom_klog_set_level(int level) { + klog_level = level; +} + +void multirom_klog_init(void) { + if (klog_fd >= 0) return; /* Already initialized */ + + /*klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); + if (klog_fd >= 0) { + return; + }*/ + + static const char* name = "/__kmsg__"; + if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) { + klog_fd = open(name, O_WRONLY | O_CLOEXEC); + unlink(name); + } +} + +void multirom_klog_close() { + close(klog_fd); +} + +#define LOG_BUF_MAX 51200 + +void multirom_klog_writev(int level, const struct iovec* iov, int iov_count) { + if (level > klog_level) return; + if (klog_fd < 0) multirom_klog_init(); + if (klog_fd < 0) return; + TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count)); +} + +void multirom_klog_write(int level, const char* fmt, ...) { + if (level > klog_level) return; + char buf[LOG_BUF_MAX]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + buf[LOG_BUF_MAX - 1] = 0; + + struct iovec iov[1]; + iov[0].iov_base = buf; + iov[0].iov_len = strlen(buf); + multirom_klog_writev(level, iov, 1); +} diff --git a/lib/log.h b/lib/log.h index 3686b37a..8a509f94 100644 --- a/lib/log.h +++ b/lib/log.h @@ -24,10 +24,13 @@ #define ERROR(fmt, ...) fprintf(stderr, "%s: " fmt "\n", mrom_log_tag(), ##__VA_ARGS__) #define INFO(fmt, ...) printf("%s: " fmt "\n", mrom_log_tag(), ##__VA_ARGS__) #else - #include - #define ERROR(fmt, ...) klog_write(3, "<3>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) - #define INFO(fmt, ...) klog_write(6, "<6>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) +void multirom_klog_write(int level, const char* fmt, ...); +void multirom_klog_set_level(int level); + + #define klog_set_level(n) multirom_klog_set_level(n) + #define ERROR(fmt, ...) multirom_klog_write(3, "<3>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) + #define INFO(fmt, ...) multirom_klog_write(6, "<6>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) #endif #endif diff --git a/lib/util.c b/lib/util.c index db8312f1..afa01233 100644 --- a/lib/util.c +++ b/lib/util.c @@ -26,10 +26,12 @@ #include #include #include +#include #ifdef HAVE_SELINUX #include #endif +#include #include #include @@ -37,6 +39,9 @@ #include #include #include +#include +#include +#include #include #include @@ -67,6 +72,7 @@ time_t gettime(void) * android_name_to_id - returns the integer uid/gid associated with the given * name, or -1U on error. */ +#if 0 static unsigned int android_name_to_id(const char *name) { struct android_id_info const *info = android_ids; @@ -79,6 +85,7 @@ static unsigned int android_name_to_id(const char *name) return -1U; } +#endif /* * decode_uid - decodes and returns the given string, which can be either the @@ -88,16 +95,27 @@ static unsigned int android_name_to_id(const char *name) unsigned int decode_uid(const char *s) { unsigned int v; + uid_t uid; + struct passwd *pwd = NULL; - if (!s || *s == '\0') + if (!s || *s == '\0') { return -1U; - if (isalpha(s[0])) - return android_name_to_id(s); + } + if (isalpha(s[0])) { + + pwd = getpwnam(s); + if (!pwd) { + return -errno; + } + uid_t uid = pwd->pw_uid; + return uid; + } errno = 0; v = (unsigned int) strtoul(s, 0, 0); - if (errno) + if (errno) { return -1U; + } return v; } @@ -143,6 +161,7 @@ int mkdir_recursive_with_perms(const char *pathname, mode_t mode, const char *ow int mkdir_with_perms(const char *path, mode_t mode, const char *owner, const char *group) { int ret; + struct passwd *pwd = NULL; ret = mkdir(path, mode); /* chmod in case the directory already exists */ @@ -155,18 +174,55 @@ int mkdir_with_perms(const char *path, mode_t mode, const char *owner, const cha if(owner) { - uid_t uid = decode_uid(owner); - gid_t gid = -1; + pwd = getpwnam(owner); + + if (!pwd) { + return -errno; + } - if(group) - gid = decode_uid(group); + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; - if(chown(path, uid, gid) < 0) + if(chown(path, uid, gid) < 0) { return -errno; + } } return 0; } +int mkdir_with_perms_context(const char *path, mode_t mode, const char *owner, const char *group, char* context) +{ + int ret; + struct passwd *pwd = NULL; + + ret = mkdir(path, mode); + /* chmod in case the directory already exists */ + if (ret == -1 && errno == EEXIST) { + ret = chmod(path, mode); + } + if (ret == -1) { + return -errno; + } + + if(owner) + { + pwd = getpwnam(owner); + + if (!pwd) { + return -errno; + } + + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + + if(chown(path, uid, gid) < 0) { + return -errno; + } + } + setfilecon(path, context); + return 0; +} + /* * replaces any unacceptable characters with '_', the * length of the resulting string is equal to the input string @@ -272,6 +328,136 @@ int copy_file(const char *from, const char *to) return 0; } +int copy_file_with_context(const char *from, const char *to, char* context) +{ + FILE *in = fopen(from, "re"); + if(!in) + return -1; + + FILE *out = fopen(to, "we"); + if(!out) + { + fclose(in); + return -1; + } + + fseek(in, 0, SEEK_END); + int size = ftell(in); + rewind(in); + + char *buff = malloc(size); + fread(buff, 1, size, in); + fwrite(buff, 1, size, out); + + if(setfilecon(to, context)) { + ERROR("couldnt set %s context to %s because %s", to, context, strerror(errno)); + } + + fclose(in); + fclose(out); + free(buff); + return 0; +} + +int getattr(const char *path, struct file_attr *a) { + if (lstat(path, &a->st) == -1) + return -1; + char con[256]; + if (getfilecon(path, &con) == -1) + return -1; + strcpy(a->con, con); + //freecon(con); + return 0; +} + +int setattr(const char *path, struct file_attr *a) { + if (chmod(path, a->st.st_mode & 0777) < 0) + return -1; + if (chown(path, a->st.st_uid, a->st.st_gid) < 0) + return -1; + if (a->con[0] && setfilecon(path, a->con) < 0) + return -1; + return 0; +} + +bool is_in_list(char** stack, char* needle) { + int i = 0; + while (stack[i] != NULL) { + if (!strcmp(stack[i], needle)) { + return true; + } + i++; + } + return false; +} + +void clone_dir(DIR* d, char* dirpath, char* target, bool preserve_context, char** exclude_dir) { + + char in[256]; + char out[256]; + memset(in, 0, 256); + memset(out, 0, 256); + struct dirent *dp = NULL; + char *fstab_name = NULL; + DIR* dir = NULL; + if (access(target, F_OK)) { + mkdir_with_perms(target, 0755, NULL, NULL); + } + ERROR("copying dir %s to %s\n", dirpath, target); + while((dp = readdir(d))) + { + if((dp->d_name[0] == '.' && strlen(dp->d_name) == 1) || (dp->d_name[0] == '.' && dp->d_name[1] == '.') || (exclude_dir && exclude_dir[0] && is_in_list(exclude_dir, dp->d_name))) + continue; + + sprintf(in, "%s/%s", dirpath, dp->d_name); + if (!strcmp(dp->d_name, "init")) { + sprintf(out, "%s/%s", target, "main_init"); + } else { + sprintf(out, "%s/%s", target, dp->d_name); + } + + struct file_attr a; + getattr(in, &a); + + if (dp->d_type == DT_DIR) { + dir = opendir(in); + if (preserve_context) { + char* context = calloc(1, 50); + getfilecon(in, &context); + mkdir_with_perms_context(out, 0755, NULL, NULL, context); + } else { + mkdir_with_perms(out, 0755, NULL, NULL); + } + setattr(out, &a); + copy_dir_contents(dir, in, out, exclude_dir); + continue; + } else if (dp->d_type == DT_LNK) { + ERROR("copying link %s to %s\n", in, out); + char target[256]; + readlink(in, target, sizeof(target)); + symlink(target, out); + setattr(out, &a); + } else if (dp->d_type == DT_REG) { + ERROR("copying file %s to %s\n", in, out); + if (preserve_context) { + char* context = calloc(1, 50); + getfilecon(in, &context); + copy_file_with_context(in, out, context); + } else { + copy_file(in, out); + } + setattr(out, &a); + } + + } + closedir(d); +} + + +void copy_dir_contents(DIR* d, char* dirpath, char* target, char** exclude_dir) { + clone_dir(d, dirpath, target, false, exclude_dir); +} + int write_file(const char *path, const char *value) { int fd, ret, len; @@ -292,6 +478,7 @@ int write_file(const char *path, const char *value) close(fd); if (ret < 0) { + ERROR("Failed to open file %s (%d: %s)\n", path, errno, strerror(errno)); return -errno; } else { return 0; @@ -376,6 +563,25 @@ int run_cmd_with_env(char **cmd, char *const *envp) } +char* read_file(char* file) { + char* buf = calloc(1, 256000); + int nread = 0; + int offset = 0; + char buff[256]; + FILE* fp = fopen(file, "r"); + if (fp) { + while ((nread = fread(buff, 1, 256, fp)) > 0) { + INFO("buf %s\n", buff); + memcpy(buf + offset, buff, nread); + offset += nread; + } + fclose(fp); + } else { + ERROR("cannot open %s %s\n", file, strerror(errno)); + } + return buf; +} + char *run_get_stdout(char **cmd) { int exit_code; @@ -434,6 +640,11 @@ char *run_get_stdout_with_exit_with_env(char **cmd, int *exit_code, char *const waitpid(pid, exit_code, 0); + if (WIFEXITED(*exit_code)) { + INFO("exit code %d", WEXITSTATUS(*exit_code)); + } + + if(written == 0) { free(res); @@ -697,7 +908,7 @@ int create_loop_device(const char *dev_path, const char *img_path, int loop_num, return -1; } - INFO("create_loop_device: loop_num = %d", loop_num); + INFO("create_loop_device: loop_num = %d\n", loop_num); if(mknod(dev_path, S_IFBLK | loop_chmod, makedev(7, loop_num)) < 0) { @@ -761,7 +972,7 @@ int mount_image(const char *src, const char *dst, const char *fs, int flags, con if(loop_num == MAX_LOOP_NUM) { - ERROR("mount_image: failed to find suitable loop device number!"); + ERROR("mount_image: failed to find suitable loop device number!\n"); return -1; } @@ -776,6 +987,79 @@ int mount_image(const char *src, const char *dst, const char *fs, int flags, con return res; } +#define MULTIROM_LOOP_NUM_START 231 +#define MULTIROM_DEV_PATH "/multirom/dev" +int multirom_mount_image(const char *src, const char *dst, const char *fs, int flags, const void *data) +{ + static int next_loop_num = MULTIROM_LOOP_NUM_START; + char path[64]; + int device_fd; + int loop_num = -1; + int res = 0; + struct stat info; + struct loop_info64 lo_info; + + /*for(loop_num = next_loop_num; loop_num < MAX_LOOP_NUM; ++loop_num) + { + sprintf(path, "/dev/block/loop%d", loop_num); + if(stat(path, &info) < 0) + { + if(errno == ENOENT) + break; + } + else if(S_ISBLK(info.st_mode) && (device_fd = open(path, O_RDWR | O_CLOEXEC)) >= 0) + { + int ioctl_res = ioctl(device_fd, LOOP_GET_STATUS64, &lo_info); + close(device_fd); + + if (ioctl_res < 0 && errno == ENXIO) + break; + } + } + + if(loop_num == MAX_LOOP_NUM) + { + ERROR("mount_image: failed to find suitable loop device number!\n"); + return -1; + }*/ + + // now change to /multirom/dev/ + mkdir_recursive_with_perms(MULTIROM_DEV_PATH, 0777, NULL, NULL); + sprintf(path, MULTIROM_DEV_PATH "/%s", dst); + +create_loop: + if(create_loop_device(path, src, loop_num, 0777) < 0) { + res = -1; + } else { + res = 0; + } + + + if (res != -1) { + if(mount(path, dst, fs, flags, data) < 0) { + ERROR("Failed to mount loop (%d: %s)\n", errno, strerror(errno)); + res = -1; + } else { + res = 0; + } + } + + INFO("multirom create loop device %d\n", loop_num); + //multirom_kmsg_logging(BACKUP_LATE_KLOG); + if(res && loop_num < MAX_LOOP_NUM) { + if (loop_num == -1) + loop_num = 0; + else + loop_num = loop_num + 1; + sprintf(path, "/dev/block/loop%d", loop_num); + goto create_loop; + } + + sync(); + + return res; +} + void do_reboot(int type) { sync(); @@ -785,16 +1069,22 @@ void do_reboot(int type) { default: case REBOOT_SYSTEM: - android_reboot(ANDROID_RB_RESTART, 0, 0); + //android_reboot(ANDROID_RB_RESTART, 0, 0); + syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, ""); break; case REBOOT_RECOVERY: - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + //android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, "recovery"); break; case REBOOT_BOOTLOADER: - android_reboot(ANDROID_RB_RESTART2, 0, "bootloader"); + //android_reboot(ANDROID_RB_RESTART2, 0, "bootloader"); + syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, "bootloader"); break; case REBOOT_SHUTDOWN: - android_reboot(ANDROID_RB_POWEROFF, 0, 0); + reboot(RB_POWER_OFF); break; } diff --git a/lib/util.h b/lib/util.h index 5e2936eb..4950f0e7 100644 --- a/lib/util.h +++ b/lib/util.h @@ -17,10 +17,12 @@ #ifndef _INIT_UTIL_H_ #define _INIT_UTIL_H_ +#include #include #include #include #include +#include #define UNUSED __attribute__((unused)) @@ -31,6 +33,11 @@ #define REBOOT_BOOTLOADER 2 #define REBOOT_SHUTDOWN 3 +struct file_attr { + struct stat st; + char con[128]; +}; + time_t gettime(void); unsigned int decode_uid(const char *s); int mkdir_recursive(const char *pathname, mode_t mode); @@ -40,8 +47,12 @@ int make_link(const char *oldpath, const char *newpath); void remove_link(const char *oldpath, const char *newpath); int wait_for_file(const char *filename, int timeout); int copy_file(const char *from, const char *to); +int copy_file_with_context(const char *from, const char *to, char* context); +void copy_dir_contents(DIR* d, char* dirpath, char* target, char** exclude_dir); +void clone_dir(DIR* d, char* dirpath, char* target, bool preserve_context, char** exclude_dir); int copy_dir(const char *from, const char *to); int mkdir_with_perms(const char *path, mode_t mode, const char *owner, const char *group); +int mkdir_with_perms_context(const char *path, mode_t mode, const char *owner, const char *group, char* context); int write_file(const char *path, const char *value); int remove_dir(const char *dir); int run_cmd(char **cmd); @@ -57,8 +68,10 @@ inline int64_t timeval_us_diff(struct timeval now, struct timeval prev); void emergency_remount_ro(void); int create_loop_device(const char *dev_path, const char *img_path, int loop_num, int loop_chmod); int mount_image(const char *src, const char *dst, const char *fs, int flags, const void *data); +int multirom_mount_image(const char *src, const char *dst, const char *fs, int flags, const void *data); void do_reboot(int type); int mr_system(const char *shell_fmt, ...); +char* read_file(char* file); inline int imin(int a, int b); inline int imax(int a, int b); diff --git a/main.c b/main.c index 6c38184a..64face8b 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,7 @@ int main(int argc, const char *argv[]) { int i; const char *rom_to_boot = NULL; + int always_reboot = 0; for(i = 1; i < argc; ++i) { @@ -105,11 +106,12 @@ int main(int argc, const char *argv[]) { rom_to_boot = argv[i] + sizeof("--boot-rom"); } + else if (!strcmp(argv[i], "alwaysreboot")) { + always_reboot = 1; + } } srand(time(0)); - klog_init(); - // output all messages to dmesg, // but it is possible to filter out INFO messages klog_set_level(6); @@ -124,7 +126,7 @@ int main(int argc, const char *argv[]) if(rom_to_boot) mount(NULL, "/", NULL, MS_REMOUNT, NULL); - int exit = multirom(rom_to_boot); + int exit = multirom(rom_to_boot, always_reboot); if(rom_to_boot) mount(NULL, "/", NULL, MS_RDONLY | MS_REMOUNT, NULL); diff --git a/multirom.c b/multirom.c index 456a0884..dfa7c55b 100644 --- a/multirom.c +++ b/multirom.c @@ -22,9 +22,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -32,6 +34,8 @@ #include #include #include +#include +#include // clone libbootimg to /system/extras/ from // https://github.com/Tasssadar/libbootimg.git @@ -70,49 +74,158 @@ #define LAYOUT_VERSION "/data/.layout_version" #define BATTERY_CAP "/sys/class/power_supply/battery/capacity" +#define DT_FSTAB_PATH "/proc/device-tree/firmware/android/fstab/" + +#define EXEC_MASK (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) +#define EXEC_MASK_NEW (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#define EXEC_MASK_RW (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) static char busybox_path[64] = { 0 }; static char kexec_path[64] = { 0 }; static char ntfs_path[64] = { 0 }; static char exfat_path[64] = { 0 }; static char partition_dir[64] = { 0 }; +static char datamedia_dir[64] = { 0 }; static volatile int run_usb_refresh = 0; static pthread_t usb_refresh_thread; static pthread_mutex_t parts_mutex = PTHREAD_MUTEX_INITIALIZER; static void (*usb_refresh_handler)(void) = NULL; +void copy_init_contents(DIR* d, char* dirpath, char* target, bool preserve_contexts, char** exclude_dirs); +bool LoadSplitPolicy(); + + +void disable_dtb_fstab(char* partition) { + //return; + if (access("status", F_OK)) { + DIR* dir = opendir("/proc/device-tree/firmware/android"); + char** exclude_dirs = NULL; + copy_dir_contents(dir, "/proc/device-tree/firmware/android", "/fakefsbat", exclude_dirs); + FILE* fp = fopen("status", "w"); + fprintf(fp, "disabled"); + fclose(fp); + } + char path[256]; + sprintf(path, "/fakefsbat/fstab/%s/status", partition); + copy_file("/status", path); +} + +void remove_dtb_fstab() { + mkdir("/dummy_fw", S_IFDIR); + DIR* dir = opendir("/proc/device-tree/firmware/android"); + char** exclude_dirs = NULL; + copy_dir_contents(dir, "/proc/device-tree/firmware/android", "/fakefsbat", exclude_dirs); + if (!mount("/dummy_fw", "/fakefsbat", "ext4", MS_BIND, "discard,nomblk_io_submit")) { + INFO("dummy dtb node bind mounted in procfs\n"); + } else { + ERROR("dummy dtb node bind mount failed! %s\n", strerror(errno)); + } +} + +int multirom_is_android10() { + if (!multirom_path_exists("/", "apex")) { + INFO("APEX folder found\n"); + return 1; + } + if (!multirom_path_exists("/system", "system/bin/init")) { + INFO("system/bin/init found\n"); + return 1; + } + char* initPath = "/main_init"; + if (!multirom_path_exists("/", "/.backup/init")) { + initPath = "/.backup/init"; + } + + void *addr; + int initfd = open(initPath, O_RDWR); + INFO("open file %s result %d\n", initPath, initfd); + struct stat st; + lstat(initPath, &st); + size_t size = st.st_size; + addr = mmap(NULL, size, PROT_READ, MAP_SHARED, initfd, 0); + if (addr == -1) { + INFO("mmap error! %s\n", strerror(errno)); + } + int contains = memmem(addr, size, "selinux_setup", 13) != NULL; + munmap(addr, size); + close(initfd); + INFO("init contains selinux_setup %d\n", contains); + return contains; +} + + +int mount_dtb_fstab(char* partition) { + int rc = -1; + + char root_path [256] = {'\0'}; + char device[256] = {'\0'}; + char type[256] = {'\0'}; + char mnt_flags[256] = {'\0'}; + + sprintf(root_path, "%s%s", DT_FSTAB_PATH, partition); + sprintf(device, "%s%s", root_path, "/dev"); + sprintf(type, "%s%s", root_path, "/type"); + sprintf(mnt_flags, "%s%s", root_path, "/mnt_flags"); + + if (!strcmp(partition, "system") && multirom_is_android10()) { + partition = "system_root"; + mkdir_with_perms("/system_root", 0755, NULL, NULL); + if (access("/system/bin/init", F_OK)) { + mkdir_with_perms("/system/bin", 0755, NULL, NULL); + copy_file("/init", "/system/bin/init"); + chmod("/system/bin/init", EXEC_MASK_NEW); + } + } + if (!(rc = mount(read_file(device), partition, read_file(type), MS_RDONLY, "barrier=1,discard"))) { + INFO("dtb %s mount successful\n", partition); + } else { + INFO("dtb %s mount failed %s\n", partition, strerror(errno)); + } + + return rc; +} int multirom_find_base_dir(void) { - int i; + int i, j; + char path[64]; struct stat info; - static const char *paths[] = { - REALDATA"/media/0/multirom", // 4.2 - REALDATA"/media/multirom", - "/data/media/0/multirom", - "/data/media/multirom", + static const char *base_dirs[] = { + REALDATA"/media/0", + REALDATA"/media", + "/data/media/0", + "/data/media", + NULL, + }; + static const char *mrom_dirs[] = { + "MultiROM/multirom", + "multirom", NULL, }; - for(i = 0; paths[i]; ++i) - { - if(stat(paths[i], &info) < 0) - continue; + for(i = 0; base_dirs[i]; ++i) { + for (j = 0; mrom_dirs[j]; ++j) { + sprintf(path, "%s/%s", base_dirs[i], mrom_dirs[j]); + if(stat(path, &info) < 0) + continue; - mrom_set_dir(paths[i]); + mrom_set_dir(path); - strncpy(partition_dir, paths[i], strchr(paths[i]+1, '/') - paths[i]); + strcpy(datamedia_dir, path); - sprintf(busybox_path, "%s/%s", paths[i], BUSYBOX_BIN); - sprintf(kexec_path, "%s/%s", paths[i], KEXEC_BIN); - sprintf(ntfs_path, "%s/%s", paths[i], NTFS_BIN); - sprintf(exfat_path, "%s/%s", paths[i], EXFAT_BIN); + strncpy(partition_dir, path, strchr(path, '/') - path); - chmod(kexec_path, 0755); - chmod(ntfs_path, 0755); - chmod(exfat_path, 0755); - return 0; + sprintf(busybox_path, "%s/%s", path, BUSYBOX_BIN); + sprintf(kexec_path, "%s/%s", path, KEXEC_BIN); + sprintf(ntfs_path, "%s/%s", path, NTFS_BIN); + sprintf(exfat_path, "%s/%s", path, EXFAT_BIN); + + chmod(kexec_path, 0755); + chmod(ntfs_path, 0755); + chmod(exfat_path, 0755); + return 0; + } } return -1; } @@ -127,6 +240,15 @@ enum BACKUP_LAST_KEXEC = 3 }; +static void set_mediarw_perms(const char *path) +{ + chmod(path, 0666); + + unsigned int media_rw_id = decode_uid("media_rw"); + if(media_rw_id != -1U) + chown(path, (uid_t)media_rw_id, (gid_t)media_rw_id); +} + void multirom_kmsg_rename_logs(const char *path_logs_dir, const char *base_name, const int max_count) { DIR *dp = opendir(path_logs_dir); @@ -184,7 +306,7 @@ void multirom_kmsg_logging(int kmsg_backup_type) }; // make the logs folder visible outside multirom folder - static const char log_dir_name[] = "../multirom-klogs"; + static const char log_dir_name[] = "multirom-klogs"; static const char ext[] = "txt"; // current date time @@ -210,39 +332,63 @@ void multirom_kmsg_logging(int kmsg_backup_type) else return; + sprintf(path_logs_dir, "%s/%s", datamedia_dir, log_dir_name); - // set path and create if needed - sprintf(path_logs_dir, "%s/%s", mrom_dir(), log_dir_name); - mkdir(path_logs_dir, 0777); + if (access(path_logs_dir, F_OK) < 0) + mkdir(path_logs_dir, 0666); + set_mediarw_perms(path_logs_dir); - if (kmsg_backup_type == BACKUP_LAST_KMSG) - { + if (kmsg_backup_type == BACKUP_LAST_KMSG) { int i; - multirom_kmsg_rename_logs(path_logs_dir, base_name, MAX_LASTKMSG_LOGS); - - // now copy the last kernel msg sprintf(path_log_file, "%s/%s_%i_%s.%s", path_logs_dir, base_name, 0, datetime, ext); - for(i = 0; kmsg_paths[i]; ++i) - { - if (access(kmsg_paths[i], R_OK) == 0) - { + for(i = 0; kmsg_paths[i]; ++i) { + if (access(kmsg_paths[i], R_OK) == 0) { INFO("Backing up last kmsg '%s' to '%s' res=%d\n", kmsg_paths[i], path_log_file, copy_file(kmsg_paths[i], path_log_file)); break; } } } - else - { + else { multirom_kmsg_rename_logs(path_logs_dir, base_name, (kmsg_backup_type == BACKUP_LATE_KLOG) ? MAX_MROMKMSG_LOGS : 0); - - // now copy current klog sprintf(path_log_file, "%s/%s_%i_%s.%s", log_dir_name, base_name, 0, datetime, ext); INFO("Backing up current klog to '%s' res=%d\n", path_log_file, multirom_copy_log(NULL, path_log_file)); } + set_mediarw_perms(path_log_file); +} + +int multirom_get_current_oslevel(struct multirom_status *s) +{ + int res = -1; + struct bootimg primary_img, secondary_img; + + char* secondary_path = "/dev/block/bootdevice/by-name/boot"; + + INFO(NO_KEXEC_LOG_TEXT ": Going to check the bootimg in primary slot for slevel\n"); + + if (libbootimg_init_load(&secondary_img, secondary_path, LIBBOOTIMG_LOAD_ALL) < 0) + { + return -1; + } + + char* secondary_os_version = libbootimg_get_osversion(&secondary_img.hdr, false); + char* secondary_os_level = libbootimg_get_oslevel(&secondary_img.hdr, false); + char* secondary_os_version_raw = libbootimg_get_osversion(&secondary_img.hdr, true); + char* secondary_os_level_raw = libbootimg_get_oslevel(&secondary_img.hdr, true); + + memset(s->os_version, 0, sizeof(s->os_version)); + memset(s->os_level, 0, sizeof(s->os_level)); + memset(s->os_version_raw, 0, sizeof(s->os_version_raw)); + memset(s->os_level_raw, 0, sizeof(s->os_level_raw)); + + memcpy(s->os_version, secondary_os_version, strlen(secondary_os_version)); + memcpy(s->os_level, secondary_os_level, strlen(secondary_os_level)); + memcpy(s->os_version_raw, secondary_os_version_raw, strlen(secondary_os_version_raw)); + memcpy(s->os_level_raw, secondary_os_level_raw, strlen(secondary_os_level_raw)); + return 0; } -int multirom(const char *rom_to_boot) +int multirom(const char *rom_to_boot, int always_reboot) { if(multirom_find_base_dir() == -1) { @@ -255,6 +401,7 @@ int multirom(const char *rom_to_boot) multirom_load_status(&s); multirom_dump_status(&s); + multirom_get_current_oslevel(&s); if (s.enable_kmsg_logging != 0) { @@ -361,7 +508,11 @@ int multirom(const char *rom_to_boot) switch(multirom_ui(&s, &to_boot)) { - case UI_EXIT_BOOT_ROM: break; + case UI_EXIT_BOOT_ROM: + if (always_reboot) { + exit = (EXIT_REBOOT | EXIT_UMOUNT); + } + break; case UI_EXIT_REBOOT: exit = (EXIT_REBOOT | EXIT_UMOUNT); break; @@ -403,7 +554,7 @@ int multirom(const char *rom_to_boot) } else { - if ((to_boot->type != ROM_DEFAULT) && to_boot->has_bootimg) + if ((to_boot->type != ROM_DEFAULT) && to_boot->has_bootimg && !s.use_primary_kernel) { // Flash secondary boot.img, and reboot // note: a secondary boot.img in primary slot will trigger second_boot=1 @@ -421,6 +572,8 @@ int multirom(const char *rom_to_boot) exit = (EXIT_REBOOT | EXIT_UMOUNT); goto finish; + } else if (s.use_primary_kernel) { + exit = 0; } } #endif @@ -428,11 +581,13 @@ int multirom(const char *rom_to_boot) if(rom_to_boot == NULL) multirom_run_scripts("run-on-boot", to_boot); - exit = multirom_prepare_for_boot(&s, to_boot); + exit = multirom_prepare_for_boot(&s, to_boot, always_reboot); + INFO("prepare for boot returned %d\n", exit); // Something went wrong, exit/reboot if(exit == -1) { + INFO("SOMETHING HAS GONE WRONG !!"); if(rom_to_boot == NULL) { multirom_emergency_reboot(); @@ -496,7 +651,7 @@ void multirom_emergency_reboot(void) char *tail; char *last_end; int cur_y; - unsigned int media_rw_id; + char path_log_file[64]; if(multirom_init_fb(0) < 0) { @@ -545,13 +700,11 @@ void multirom_emergency_reboot(void) fb_force_draw(); - multirom_copy_log(klog, "../multirom_log.txt"); + sprintf(path_log_file, "%s/multirom_log.txt", datamedia_dir); + multirom_copy_log(klog, path_log_file); free(klog); - media_rw_id = decode_uid("media_rw"); - if(media_rw_id != -1U) - chown("../multirom_log.txt", (uid_t)media_rw_id, (gid_t)media_rw_id); - chmod("../multirom_log.txt", 0666); + set_mediarw_perms(path_log_file); // Wait for power key start_input_thread(); @@ -622,7 +775,7 @@ int multirom_apk_get_roms(struct multirom_status *s) { if(multirom_find_base_dir() == -1) { - printf("Could not find multirom dir\n"); + INFO("Could not find multirom dir\n"); return -1; } @@ -656,13 +809,13 @@ int multirom_apk_get_roms(struct multirom_status *s) s->curr_rom_part = strdup(arg); } - printf("current_rom='%s' curr_rom_part='%s'\n", current_rom, (s->curr_rom_part ? s->curr_rom_part : "")); + INFO("current_rom='%s' curr_rom_part='%s'\n", current_rom, (s->curr_rom_part ? s->curr_rom_part : "")); fclose(f); } else { - printf("Failed to open config file, setting current_rom to null!\n"); + INFO("Failed to open config file, setting current_rom to null!\n"); } /* Get Internal ROM */ @@ -671,7 +824,7 @@ int multirom_apk_get_roms(struct multirom_status *s) DIR *d = opendir(roms_path); if(!d) { - printf("Failed to open Internal ROM's folder, creating one with ROM from internal memory...\n"); + INFO("Failed to open Internal ROM's folder, creating one with ROM from internal memory...\n"); multirom_import_internal(); } else @@ -682,7 +835,7 @@ int multirom_apk_get_roms(struct multirom_status *s) d = opendir(roms_path); if(!d) { - printf("Failed to open roms dir!\n"); + INFO("Failed to open roms dir!\n"); //return -1; } else @@ -700,11 +853,11 @@ int multirom_apk_get_roms(struct multirom_status *s) if(strlen(dr->d_name) > MAX_ROM_NAME_LEN) { - printf("Skipping ROM %s, name is too long (max %d chars allowed)\n", dr->d_name, MAX_ROM_NAME_LEN); + INFO("Skipping ROM %s, name is too long (max %d chars allowed)\n", dr->d_name, MAX_ROM_NAME_LEN); continue; } - //printf("Adding ROM %s\n", dr->d_name); + //INFO("Adding ROM %s\n", dr->d_name); struct multirom_rom *rom = malloc(sizeof(struct multirom_rom)); memset(rom, 0, sizeof(struct multirom_rom)); @@ -753,7 +906,7 @@ int multirom_apk_get_roms(struct multirom_status *s) s->current_rom = multirom_get_rom(s, current_rom, s->curr_rom_part); if(!s->current_rom) { - printf("Failed to find current rom (%s, part %s)!\n", current_rom, (s->curr_rom_part) ? s->curr_rom_part : ""); + INFO("Failed to find current rom (%s, part %s)!\n", current_rom, (s->curr_rom_part) ? s->curr_rom_part : ""); free(s->curr_rom_part); s->curr_rom_part = NULL; } @@ -775,6 +928,7 @@ int multirom_default_status(struct multirom_status *s) s->enable_kmsg_logging = 0; s->rotation = MULTIROM_DEFAULT_ROTATION; s->anim_duration_coef = 1.f; + s->use_primary_kernel = 0; s->fstab = fstab_auto_load(); if(!s->fstab) @@ -933,6 +1087,8 @@ int multirom_load_status(struct multirom_status *s) s->force_generic_fb = atoi(arg); else if(strstr(name, "anim_duration_coef_pct")) s->anim_duration_coef = ((float)atoi(arg)) / 100; + else if(strstr(name, "use_primary_kernel")) + s->use_primary_kernel = atoi(arg); } fclose(f); @@ -1020,6 +1176,7 @@ int multirom_save_status(struct multirom_status *s) fprintf(f, "rotation=%d\n", s->rotation); fprintf(f, "force_generic_fb=%d\n", s->force_generic_fb); fprintf(f, "anim_duration_coef_pct=%d\n", (int)(s->anim_duration_coef*100)); + fprintf(f, "use_primary_kernel=%d\n", (int)(s->use_primary_kernel)); fclose(f); return 0; @@ -1062,6 +1219,7 @@ void multirom_dump_status(struct multirom_status *s) INFO(" auto_boot_rom=%s\n", s->auto_boot_rom ? s->auto_boot_rom->name : "NULL"); INFO(" auto_boot_type=%d\n", s->auto_boot_type); INFO(" curr_rom_part=%s\n", s->curr_rom_part ? s->curr_rom_part : "NULL"); + INFO(" use_primary_kernel=%d\n", s->use_primary_kernel); INFO("\n"); int i; @@ -1229,12 +1387,19 @@ int multirom_get_rom_type(struct multirom_rom *rom) // Handle android ROMs if(!multirom_path_exists(b, "boot")) { - if (!multirom_path_exists(b, "system") && !multirom_path_exists(b, "data") && + if(!multirom_path_exists(b, "system") && !multirom_path_exists(b, "data") && !multirom_path_exists(b, "cache")) { if(!rom->partition) return ROM_ANDROID_INTERNAL; else return ROM_ANDROID_USB_DIR; } + else if(!multirom_path_exists(b, "system.sparse.img") && + (!multirom_path_exists(b, "data") || !multirom_path_exists(b, "data.sparse.img")) && + (!multirom_path_exists(b, "cache") || !multirom_path_exists(b, "cache.sparse.img"))) + { + if(!rom->partition) return ROM_ANDROID_INTERNAL_HYBRID; + else return ROM_ANDROID_USB_HYBRID; + } else if(!multirom_path_exists(b, "system.img") && !multirom_path_exists(b, "data.img") && !multirom_path_exists(b, "cache.img")) { @@ -1364,7 +1529,7 @@ struct multirom_rom *multirom_get_rom_by_id(struct multirom_status *s, int id) return NULL; } -int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to_boot) +int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to_boot, int always_reboot) { int exit = EXIT_UMOUNT; int type = to_boot->type; @@ -1385,7 +1550,23 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to { case ROM_DEFAULT: { - rom_quirks_on_initrd_finalized(); + if (!access(DT_FSTAB_PATH, F_OK)) { + if (mount_dtb_fstab("system") == 0) { + rom_quirks_on_initrd_finalized(); + umount("/system_root"); + //disable_dtb_fstab("system"); + } + if (always_reboot) { + nokexec_set_skip_mr_flag(); + } + //if (mount_dtb_fstab("vendor") == 0) { + //disable_dtb_fstab("vendor"); + // } + // remove_dtb_fstab(); + } else { + rom_quirks_on_initrd_finalized(); + } + //LoadSplitPolicy(); break; } case ROM_LINUX_INTERNAL: @@ -1394,10 +1575,32 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to case ROM_ANDROID_USB_IMG: case ROM_ANDROID_USB_DIR: case ROM_ANDROID_INTERNAL: + case ROM_ANDROID_INTERNAL_HYBRID: + case ROM_ANDROID_USB_HYBRID: { if(!(exit & (EXIT_REBOOT | EXIT_KEXEC))) { - exit &= ~(EXIT_UMOUNT); + if (!s->use_primary_kernel) { + exit &= ~(EXIT_UMOUNT); + } else { + exit = 0; + struct bootimg img; + char bootimg_path[256]; + sprintf(bootimg_path, "%s/%s", to_boot->base_path, "boot.img"); + libbootimg_init_load(&img, bootimg_path, LIBBOOTIMG_LOAD_ALL); + libbootimg_dump_ramdisk(&img, "/.temprd"); + int type = 0; + decompress_rd("/.temprd", "/.newrd", &type); + if (!access("/.newrd/second", F_OK)) { + DIR* dir = opendir("/.newrd/second"); + char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + copy_init_contents(dir, "/.newrd/second", "/", true, exclude_dirs); + } else { + DIR* dir = opendir("/.newrd"); + char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + copy_init_contents(dir, "/.newrd", "/", true, exclude_dirs); + } + } if(multirom_prep_android_mounts(s, to_boot) == -1) return -1; @@ -1405,7 +1608,8 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to if(multirom_create_media_link(s) == -1) return -1; - rom_quirks_on_initrd_finalized(); + + rom_quirks_change_patch_and_osver(s, to_boot); rcadditions_write_to_files(&s->rc); rcadditions_free(&s->rc); @@ -1423,7 +1627,6 @@ int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to return exit; } -#define EXEC_MASK (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) char *multirom_find_fstab_in_rc(const char *rcfile) { @@ -1505,54 +1708,187 @@ static int multirom_inject_fw_mounter(struct multirom_status *s, struct fstab_pa return 0; } + + +bool is_symlink(const char *filename) +{ + struct stat p_statbuf; + + if (lstat(filename, &p_statbuf) < 0) { /* if error occured */ + ERROR("calling stat()"); + return false; + } + + if (S_ISLNK(p_statbuf.st_mode) == 1) { + INFO("%s is a symbolic link\n", filename); + return true; + } else { + INFO("%s is NOT a symbolic link\n", filename); + return false; + } +} + +void copy_init_contents(DIR* d, char* dirpath, char* target, bool preserve_contexts, char** exclude_dir) { + + char in[256]; + char out[256]; + memset(in, 0, 256); + memset(out, 0, 256); + struct dirent *dp = NULL; + char *fstab_name = NULL; + DIR* dir = NULL; + ERROR("copying dir %s\n", dirpath); + clone_dir(d, dirpath, target, preserve_contexts, exclude_dir); +} + +bool GetVendorMappingVersion(char** plat_vers) { + if (!(*plat_vers = read_file("/vendor/etc/selinux/plat_sepolicy_vers.txt"))) { + //PLOG(ERROR) << "Failed to read /vendor/etc/selinux/plat_sepolicy_vers.txt"; + return false; + } + if (!plat_vers) { + //LOG(ERROR) << "No version present in plat_sepolicy_vers.txt"; + return false; + } + return true; +} + +bool LoadSplitPolicy() { + // IMPLEMENTATION NOTE: Split policy consists of three CIL files: + // * platform -- policy needed due to logic contained in the system image, + // * non-platform -- policy needed due to logic contained in the vendor image, + // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy + // with newer versions of platform policy. + // + // secilc is invoked to compile the above three policy files into a single monolithic policy + // file. This file is then loaded into the kernel. + // Load precompiled policy from vendor image, if a matching policy is found there. The policy + // must match the platform policy on the system image. + // No suitable precompiled policy could be loaded + INFO( "Compiling SELinux policy"); + // Determine the highest policy language version supported by the kernel + set_selinuxmnt("/sys/fs/selinux"); + int max_policy_version = security_policyvers(); + if (max_policy_version == -1) { + //PLOG(ERROR) << "Failed to determine highest policy version supported by kernel"; + return false; + } + // We store the output of the compilation on /dev because this is the most convenient tmpfs + // storage mount available this early in the boot sequence. + char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX"; + int compiled_sepolicy_fd = mkostemp(compiled_sepolicy, O_CLOEXEC); + if (compiled_sepolicy_fd < 0) { + //PLOG(ERROR) << "Failed to create temporary file " << compiled_sepolicy; + return false; + } + // Determine which mapping file to include + char* vend_plat_vers = read_file("/vendor/etc/selinux/plat_sepolicy_vers.txt"); + if (!vend_plat_vers) { + return false; + } + vend_plat_vers[4] = '\0'; + char* mapping_file = NULL; + asprintf(&mapping_file, "/system/etc/selinux/mapping/%s.cil",vend_plat_vers); + // vendor_sepolicy.cil and plat_pub_versioned.cil are the new design to replace + // nonplat_sepolicy.cil. + char* plat_pub_versioned_cil_file = "/vendor/etc/selinux/plat_pub_versioned.cil"; + char* vendor_policy_cil_file = "/vendor/etc/selinux/vendor_sepolicy.cil"; + if (access(vendor_policy_cil_file, F_OK) == -1) { + // For backward compatibility. + // TODO: remove this after no device is using nonplat_sepolicy.cil. + vendor_policy_cil_file = "/vendor/etc/selinux/nonplat_sepolicy.cil"; + plat_pub_versioned_cil_file = NULL; + } else if (access(plat_pub_versioned_cil_file, F_OK) == -1) { + //LOG(ERROR) << "Missing " << plat_pub_versioned_cil_file; + return false; + } + // odm_sepolicy.cil is default but optional. + const char* version_as_string = NULL; + asprintf(&version_as_string, "%d", max_policy_version); + char* plat_policy_cil_file = "/system/etc/selinux/plat_sepolicy.cil"; + char* plat_policy_cil_file_sar = "/system/system/etc/selinux/plat_sepolicy.cil"; + if (!access(plat_policy_cil_file_sar, F_OK)) { + plat_policy_cil_file = plat_policy_cil_file_sar; + } + char mapping_file_sar[] = "/system/system/etc/selinux/mapping/30.0.cil"; + if (!access(mapping_file_sar, F_OK)) { + mapping_file = mapping_file_sar; + } + + char* secilc = "/system/bin/secilc"; + char* secilc_sar = "/system/system/bin/secilc"; + if (!access(secilc_sar, F_OK)) { + secilc = secilc_sar; + } + // clang-format off + char* compile_args[] = { + secilc, + plat_policy_cil_file, + "-m", "-M", "true", "-G", "-N", + // Target the highest policy language version supported by the kernel + "-c", version_as_string, + mapping_file, + "-o", compiled_sepolicy, + // We don't care about file_contexts output by the compiler + "-f", "/sys/fs/selinux/null", "", "", NULL // /dev/null is not yet available + }; + // clang-format on + if (plat_pub_versioned_cil_file) { + compile_args[14] = plat_pub_versioned_cil_file; + } + if (vendor_policy_cil_file) { + compile_args[15] = vendor_policy_cil_file; + } + int exit_code = 0; + for (int i = 0; i < 17; i++) { + INFO("args %s", compile_args[i]); + } + INFO("%s", run_get_stdout_with_exit(compile_args, &exit_code)); + //unlink(compiled_sepolicy); + //return false; + unlink(compiled_sepolicy); + INFO( "Loading compiled SELinux policy"); + if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) { + //LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy; + return false; + } + INFO( "sepolicy loaded successfuly"); + write_file("/sys/fs/selinux/checkreqprot", "0"); + struct stat fileStat; + if(stat("/sys/fs/selinux/checkreqprot",&fileStat) < 0) + return false; + + INFO("File Permissions: \t"); + INFO("read %d\n", fileStat.st_mode & S_IRUSR); + INFO("write %d\n", fileStat.st_mode & S_IWUSR); + INFO("exec %d\n", fileStat.st_mode & S_IXUSR); + INFO("%d\n", fileStat.st_mode & S_IRGRP); + INFO("%d\n", fileStat.st_mode & S_IWGRP); + INFO("%d\n", fileStat.st_mode & S_IXGRP); + INFO("%d\n", fileStat.st_mode & S_IROTH); + INFO("%d\n", fileStat.st_mode & S_IWOTH); + INFO("%d\n", fileStat.st_mode & S_IXOTH); + INFO("\n\n"); + + return true; +} + + int multirom_prep_android_mounts(struct multirom_status *s, struct multirom_rom *rom) { char in[128]; char out[128]; char path[256]; char *fstab_name = NULL; + struct stat stat; int has_fw = 0; + int found_fstab = 0; struct fstab_part *fw_part = NULL; int res = -1; sprintf(path, "%s/firmware.img", rom->base_path); has_fw = (access(path, R_OK) >= 0); - sprintf(path, "%s/boot", rom->base_path); - - DIR *d = opendir(path); - if(!d) - { - ERROR("Failed to open rom path %s\n", path); - return -1; - } - - struct dirent *dp = NULL; - - while((dp = readdir(d))) - { - if(dp->d_name[0] == '.' && (dp->d_name[1] == '.' || dp->d_name[1] == 0)) - continue; - - sprintf(in, "%s/%s", path, dp->d_name); - sprintf(out, "/%s", dp->d_name); - - copy_file(in, out); - - if(strstr(dp->d_name, ".rc")) - { - // set permissions for .rc files - chmod(out, EXEC_MASK); - - if(!fstab_name && strcmp(dp->d_name, "init."TARGET_DEVICE".rc") == 0) - fstab_name = multirom_find_fstab_in_rc(out); - } - } - closedir(d); - - if(multirom_process_android_fstab(fstab_name, has_fw, &fw_part) != 0) - goto exit; - unlink("/cache"); mkdir_with_perms("/system", 0755, NULL, NULL); @@ -1561,59 +1897,221 @@ int multirom_prep_android_mounts(struct multirom_status *s, struct multirom_rom if(has_fw) mkdir_with_perms("/firmware", 0771, "system", "system"); - static const char *folders[2][3] = - { - { "system", "data", "cache" }, - { "system.img", "data.img", "cache.img" }, - }; + /* In case device is encrypted, vendor is renamed to vendor_boot + * Now that decryption is done and partition is mounted, we dont need multirom's vendor folder. + * So we can safely remove it */ - unsigned long flags[2][3] = { - { MS_BIND | MS_RDONLY, MS_BIND, MS_BIND }, - { MS_RDONLY | MS_NOATIME, MS_NOATIME, MS_NOATIME }, - }; + if (lstat("/vendor_boot", &stat) == 0) { + INFO("/vendor_boot found"); + int error = unlink("/vendor"); + if (error == -1) { + INFO("unlink failed!!: %s\n", strerror(errno)); + } + error = rename("/vendor_boot", "/vendor"); + if (error == -1) { + INFO("rename failed!!: %s\n", strerror(errno)); + } + } else { + INFO("/vendor_boot not found"); + unlink("/vendor"); + } + mkdir_with_perms("/vendor", 0755, NULL, NULL); + static const char *folders[4] = { "system" , "vendor" , "data" , "cache"}; + unsigned long flags[4] = { MS_RDONLY , MS_RDONLY, MS_NOSUID | MS_NODEV , MS_NOSUID | MS_NODEV}; uint32_t i; char from[256]; char to[256]; - int img = (int)(rom->type == ROM_ANDROID_USB_IMG); - for(i = 0; i < ARRAY_SIZE(folders[0]); ++i) - { - snprintf(from, sizeof(from), "%s/%s", rom->base_path, folders[img][i]); - snprintf(to, sizeof(to), "/%s", folders[0][i]); - if(img == 0) - { - if(mount(from, to, "ext4", flags[img][i], "discard,nomblk_io_submit") < 0) - { + for (i = 0; i < ARRAY_SIZE(folders); ++i) { + snprintf(to, sizeof(to), "/%s", folders[i]); + snprintf(from, sizeof(from), "%s/%s", rom->base_path, folders[i]); + if (!access(from, R_OK)) { + if (strstr(from, "vendor") && multirom_path_exists(rom->base_path, "vendor/etc")) { + continue; + } + if(mount(from, to, "ext4", MS_BIND | flags[i], "discard,nomblk_io_submit") < 0) { ERROR("Failed to mount %s to %s (%d: %s)\n", from, to, errno, strerror(errno)); goto exit; - } + } else + INFO("Bind mounted %s on %s\n", from, to); + continue; } - else - { - if(mount_image(from, to, "ext4", flags[img][i], NULL) < 0) + + snprintf(from, sizeof(from), "%s/%s.img", rom->base_path, folders[i]); + if (!access(from, R_OK)) { + if(mount_image(from, to, "ext4", flags[i], NULL) < 0) + goto exit; + else + INFO("Loop mounted %s on %s\n", from, to); + continue; + } + + snprintf(from, sizeof(from), "%s/%s.sparse.img", rom->base_path, folders[i]); + if (!access(from, R_OK)) { + if(multirom_mount_image(from, to, "ext4", flags[i], NULL) < 0) goto exit; + else + INFO("MultiROM Loop mounted %s on %s\n", from, to); + continue; + } + + if (strstr(from, "vendor")) { + INFO("vendor not found, skipping\n"); + continue; } + // Neither directory nor .img nor .sparse.img was found, panic + goto exit; } - // make sure /system is ro, otherwise remount it ro - // if it's not ro, then the dir permissions may get changed to disallow 'x' (eg HTC 10) - struct statfs statfs_buf; - snprintf(to, sizeof(to), "/%s", folders[0][0]); // we could just use "/system", but this looks more sophisticated :P - INFO("Checking if system is ro\n"); - if(statfs(to, &statfs_buf) < 0) - { - ERROR("Couldn't statfs %s (%d: %s)\n", to, errno, strerror(errno)); + if((multirom_path_exists("/system", "vendor/etc") == -1) && + (multirom_path_exists(rom->base_path, "vendor/etc") == -1) && + (multirom_path_exists("/", "vendor/etc") == -1)) { + if (!access(DT_FSTAB_PATH, F_OK)) { + mount_dtb_fstab("vendor"); + } + } + if (!access(DT_FSTAB_PATH, F_OK)) { + remove_dtb_fstab(); + } + + //System as root detection + char* system_path = NULL; + bool system_as_root = false; + bool modern_sar = false; + asprintf(&system_path, "%s/system.sparse.img", rom->base_path); + + if (!multirom_path_exists("/system", "init.rc") && !multirom_is_android10()) { + INFO("ROM is not android 10\n"); + umount("/system"); + mkdir_with_perms("/system_root", 0755, NULL, NULL); + multirom_mount_image(system_path, "/system_root", "ext4", MS_RDONLY, NULL); + system_as_root = true; + if(mount("/system_root/system", "/system", "ext4", MS_BIND | MS_RDONLY, "discard,nomblk_io_submit") < 0) { + INFO("mount error\n"); + } else { + INFO("Bind mounted /system_root/system on /system\n"); + } + + rom_quirks_on_initrd_finalized(); + LoadSplitPolicy(); + DIR* dir = opendir("/system_root"); + char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + copy_init_contents(dir, "/system_root", "/", true, exclude_dirs); + } else if (multirom_is_android10()) { + INFO("ROM is android 10+\n"); + umount("/system"); + mkdir_with_perms("/system_root", 0755, NULL, NULL); + multirom_mount_image(system_path, "/system_root", "ext4", MS_RDONLY, NULL); + system_as_root = true; + modern_sar = true; + //DIR* dir = opendir("/system_root"); + //char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + //copy_init_contents(dir, "/system_root", "/", true, exclude_dirs); + /*if(mount("/vendor", "/system_root/vendor", "ext4", MS_BIND | MS_RDONLY, "discard,nomblk_io_submit") < 0) { + INFO("mount error\n"); + } else { + INFO("Bind mounted /vendor on /system_root/vendor\n"); + }*/ + rom_quirks_on_initrd_finalized(); + if (access("/system/bin/init", F_OK)) { + mkdir_with_perms("/system/bin", 0755, NULL, NULL); + copy_file("/init", "/system/bin/init"); + chmod("/system/bin/init", EXEC_MASK_NEW); + } + //LoadSplitPolicy(); + /*char* context = calloc(1, 50); + getfilecon("/system_root/system/bin/init", &context); + mkdir_with_perms("/system/bin", 0755, NULL, NULL); + copy_file_with_context("/system_root/system/bin/init", "/system/bin/init", context);*/ + //DIR* dir = opendir("/system"); + //char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + //copy_init_contents(dir, "/system", "/", true, exclude_dirs); + } + + sprintf(path, "%s/boot", rom->base_path); + DIR* dir = opendir(path); + if (!system_as_root) { + rom_quirks_on_initrd_finalized(); + LoadSplitPolicy(); + } + char* exclude_dirs[] = {"system", "vendor", "product", NULL}; + copy_init_contents(dir, path, "/", false, exclude_dirs); + if (system_as_root && !access("/system/bin/init", F_OK) && is_symlink("/system_root/init") && !modern_sar) { + char* context = calloc(1, 50); + char* initPath = "/main_init"; + getfilecon("/system/bin/init", &context); + if (multirom_path_exists("/", "/.backup/init")) { + copy_file_with_context("/system/bin/init", "/main_init", "u:object_r:rootfs:s0"); + } else { + copy_file_with_context("/system/bin/init", "/.backup/init", "u:object_r:rootfs:s0"); + initPath = "/.backup/init"; + } + + char *addr; + int initfd = open(initPath, O_RDWR); + struct stat st; + lstat(initPath, &st); + size_t size = st.st_size; + addr = mmap(NULL, size, PROT_WRITE, MAP_SHARED, initfd, 0); + for (char *p = addr; p < addr + size; ++p) { + if (memcmp(p, "/system/bin/init", sizeof("/system/bin/init")) == 0) { + // Force execute /init instead of /system/bin/init + INFO("Patch init: [/system/bin/init] -> [/init]\n"); + strcpy(p, "/init"); + p += sizeof("/system/bin/init") - 1; + } + } + munmap(addr, size); + close(initfd); + chmod("/main_init", EXEC_MASK_NEW); + } else if (system_as_root && !is_symlink("/system_root/init") && !access("/system_root/init", F_OK) && !modern_sar) { + char* context = calloc(1, 50); + getfilecon("/system_root/init", &context); + copy_file_with_context("/system_root/init", "/main_init", context); + chmod("/main_init", EXEC_MASK_NEW); } - else if(!(statfs_buf.f_flags & ST_RDONLY)) - { - INFO("system seems rw, attempting ro remount\n"); - if(mount(NULL, to, NULL, MS_REMOUNT | MS_RDONLY | flags[img][0], NULL) < 0) // MS_RDONLY is redundant, but just in case it's changed/not in flags[][] - { - ERROR("Failed to remount ro %s (%d: %s)\n", to, errno, strerror(errno)); - goto exit; + + if(multirom_process_android_fstab(fstab_name, has_fw, &fw_part, 0) != 0) { + INFO("fstab couldnt be found in ramdisk. Rom maybe treble. Retry after vendor mount\n"); + } else { + //found_fstab = 1; + } + if(!found_fstab && multirom_process_android_fstab(NULL, has_fw, &fw_part, 1) != 0) { + INFO("fstab not found even in vendor!\n"); + //goto exit; + } + + + // mount() does not necessarily obey the mount options (eg, ro on system or nosuid on data) + // so attempt a remount on the partitions, but don't abort if the remount in unsuccessful, + // unless MR_PANIC_ON_FAILED_REMOUNT is set: eg on the HTC 10 if system is not ro, then the + // dir permissions may get changed to disallow 'x' + struct statfs statfs_buf; + for (i = 0; i < ARRAY_SIZE(folders); ++i) { + snprintf(to, sizeof(to), "/%s", folders[i]); + if(statfs(to, &statfs_buf) < 0) + ERROR("Couldn't statfs %s (%d: %s)\n", to, errno, strerror(errno)); + else if((flags[i] & ~statfs_buf.f_flags)) { + if (modern_sar && !strcmp(to, "/system")) { + snprintf(to, sizeof(to), "/system_root"); + } + INFO("Mount flags of %s are 0x%08lX but should include 0x%08lX, attempting remount\n", + to, (unsigned long) statfs_buf.f_flags, flags[i]); + + if(mount(NULL, to, NULL, MS_REMOUNT | flags[i], NULL) < 0) { + ERROR("Failed to remount %s (%d: %s)\n", to, errno, strerror(errno)); +#ifdef MR_PANIC_ON_FAILED_REMOUNT + goto exit; +#endif + } + else { + if(statfs(to, &statfs_buf) < 0) + INFO("Remounted %s\n", to); + else + INFO("Remounted %s flags=0x%08lX\n", to, (unsigned long) statfs_buf.f_flags); + } } - INFO("Remounted system as ro\n"); } if(has_fw && fw_part) @@ -1622,7 +2120,8 @@ int multirom_prep_android_mounts(struct multirom_status *s, struct multirom_rom snprintf(from, sizeof(from), "%s/firmware.img", rom->base_path); fw_part->device = realloc(fw_part->device, strlen(from)+1); strcpy(fw_part->device, from); - multirom_inject_fw_mounter(s, fw_part); + multirom_mount_image(from, MR_FIRMWARE_DIR, "vfat", MS_RDONLY, "shortname=lower,uid=0,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0"); + //multirom_inject_fw_mounter(s, fw_part); } #if MR_DEVICE_HOOKS >= 1 @@ -1641,15 +2140,23 @@ int multirom_prep_android_mounts(struct multirom_status *s, struct multirom_rom return res; } -int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_part **fw_part) +int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_part **fw_part, int treble_fstab) { int res = -1; + char* dirname; if(fstab_name != NULL) INFO("Using fstab %s from rc files\n", fstab_name); else { - DIR *d = opendir("/"); + DIR *d; + if (treble_fstab) { + dirname = "/vendor/etc/"; + d = opendir(dirname); + } else { + d = opendir("/"); + } + if(!d) { ERROR("Failed to open root folder!\n"); @@ -1677,6 +2184,12 @@ int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_pa } } + if (treble_fstab) { + char name[strlen(fstab_name) + 1]; + strcpy(name, fstab_name); + fstab_name = realloc(fstab_name, strlen(name) + strlen(dirname) + 1); + sprintf(fstab_name, "%s%s", dirname, name); + } ERROR("Modifying fstab: %s\n", fstab_name); struct fstab *tab = fstab_load(fstab_name, 0); if(!tab) @@ -1685,8 +2198,9 @@ int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_pa int disable_sys = fstab_disable_parts(tab, "/system"); int disable_data = fstab_disable_parts(tab, "/data"); int disable_cache = fstab_disable_parts(tab, "/cache"); + int disable_vendor = fstab_disable_parts(tab, "/vendor"); - if(disable_sys < 0 || disable_data < 0 || disable_cache < 0) + if((!treble_fstab) && disable_sys < 0 || disable_data < 0 || disable_cache < 0) { #if MR_DEVICE_HOOKS >= 4 if(!mrom_hook_allow_incomplete_fstab()) @@ -1698,7 +2212,7 @@ int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_pa if(has_fw) { - struct fstab_part *p = fstab_find_first_by_path(tab, "/firmware"); + struct fstab_part *p = fstab_find_first_by_path(tab, MR_FIRMWARE_DIR); if(p) { *fw_part = fstab_clone_part(p); @@ -1734,9 +2248,20 @@ int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_pa mkdir("/dummy_tmpfs", 0644); } - if(fstab_save(tab, fstab_name) == 0) + char* fstab_save_path = strstr(fstab_name, "fstab"); + if(fstab_save(tab, fstab_save_path) == 0) res = 0; + if (treble_fstab) { + if(!mount(fstab_save_path, fstab_name, "ext4", MS_BIND, "discard,nomblk_io_submit")) { + INFO("fstab bind mounted in vendor\n"); + } else { + ERROR("fstab bind mount failed on %s! %s\n", fstab_name, strerror(errno)); + res = -1; + goto exit; + } + } + exit: if(tab) fstab_destroy(tab); @@ -1747,7 +2272,12 @@ int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_pa int multirom_create_media_link(struct multirom_status *s) { int media_new = 0; - int api_level = multirom_get_api_level("/system/build.prop"); + char* buildprop = "/system/build.prop"; + char* buildprop_sar = "/system_root/system/build.prop"; + if (!access(buildprop_sar, F_OK)) { + buildprop = buildprop_sar; + } + int api_level = multirom_get_api_level(buildprop); if(api_level <= 0) return -1; @@ -1781,7 +2311,7 @@ int multirom_create_media_link(struct multirom_status *s) ERROR("Making media dir: api %d, media_new %d, %s to %s\n", api_level, media_new, paths[from], paths[to]); if(mkdir_recursive(paths[to], 0775) == -1) { - ERROR("Failed to make media dir\n"); + ERROR("Failed to make media dir on %s\n", paths[to]); return -1; } @@ -1791,6 +2321,7 @@ int multirom_create_media_link(struct multirom_status *s) return -1; } +#if 0 if(api_level >= 17) { char buf[16]; @@ -1820,6 +2351,7 @@ int multirom_create_media_link(struct multirom_status *s) // but can't do it here because selinux was not initialized rcadditions_append_trigger(&s->rc, "post-fs-data", " restorecon " LAYOUT_VERSION "\n"); } +#endif return 0; } @@ -2080,6 +2612,8 @@ int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom) case ROM_ANDROID_INTERNAL: case ROM_ANDROID_USB_DIR: case ROM_ANDROID_USB_IMG: + case ROM_ANDROID_INTERNAL_HYBRID: + case ROM_ANDROID_USB_HYBRID: if(multirom_fill_kexec_android(s, rom, &kexec) != 0) goto exit; break; @@ -2699,7 +3233,7 @@ int multirom_update_partitions(struct multirom_status *s) tok = strrchr(line, '/')+1; name = strndup(tok, strchr(tok, ':') - tok); - if(strncmp(name, "mmcblk0", 7) == 0 || strncmp(name, "dm-", 3) == 0) // ignore internal nand + if(strncmp(name, "mmcblk0", 7) == 0 || strncmp(name, "dm-", 3) == 0 || strncmp(name, "sd", 2) == 0) // ignore internal nand { free(name); goto next_itr; @@ -3043,10 +3577,9 @@ int multirom_run_scripts(const char *type, struct multirom_rom *rom) #define IC_TYPE_PREDEF 0 #define IC_TYPE_USER 1 -#define USER_IC_PATH "../Android/data/com.tassadar.multirommgr/files" -#define USER_IC_PATH_LEN 46 -#define DEFAULT_ICON "/icons/romic_default.png" -#define DEFAULT_ICON_LEN 24 +#define USER_IC_PATH "Android/data/com.tassadar.multirommgr/files" +#define DEFAULT_ICON "icons/romic_default.png" +#define DEFAULT_ANDROID_ICON "icons/romic_android_default.png" void multirom_find_rom_icon(struct multirom_rom *rom) { @@ -3089,16 +3622,16 @@ void multirom_find_rom_icon(struct multirom_rom *rom) if(!ic_name) goto fail; - len = strlen(mrom_dir()) + 6 + strlen(ic_name)+4+1; // + /icons + .png + \0 + len = strlen(mrom_dir()) + 6 + strlen(ic_name) + 4 + 1; // + /icons + .png + \0 rom->icon_path = malloc(len); snprintf(rom->icon_path, len, "%s/icons%s.png", mrom_dir(), ic_name); break; } case IC_TYPE_USER: { - len = strlen(mrom_dir()) + 1 + USER_IC_PATH_LEN + 1 + len + 4 + 1; // + / + / + .png + \0 + len = strlen(datamedia_dir) + 1 + sizeof(USER_IC_PATH) + 1 + len + 4; // + / + / + .png + \0 (sizeof() includes trailing null) rom->icon_path = malloc(len); - snprintf(rom->icon_path, len, "%s/%s/%s.png", mrom_dir(), USER_IC_PATH, buff); + snprintf(rom->icon_path, len, "%s/%s/%s.png", datamedia_dir, USER_IC_PATH, buff); break; } } @@ -3111,7 +3644,14 @@ void multirom_find_rom_icon(struct multirom_rom *rom) if(f) fclose(f); - len = strlen(mrom_dir()) + DEFAULT_ICON_LEN + 1; - rom->icon_path = realloc(rom->icon_path, len); - snprintf(rom->icon_path, len, "%s%s", mrom_dir(), DEFAULT_ICON); + if (rom->type & MASK_ANDROID) { + len = strlen(mrom_dir()) + 1 + sizeof(DEFAULT_ANDROID_ICON); // sizeof() includes trailing null + rom->icon_path = realloc(rom->icon_path, len); + snprintf(rom->icon_path, len, "%s/%s", mrom_dir(), DEFAULT_ANDROID_ICON); + } + else { + len = strlen(mrom_dir()) + 1 + sizeof(DEFAULT_ICON); // sizeof() includes trailing null + rom->icon_path = realloc(rom->icon_path, len); + snprintf(rom->icon_path, len, "%s/%s", mrom_dir(), DEFAULT_ICON); + } } diff --git a/multirom.h b/multirom.h index 4469ba27..b1931d27 100644 --- a/multirom.h +++ b/multirom.h @@ -28,24 +28,28 @@ enum { - ROM_DEFAULT = 0, + ROM_DEFAULT = 0, - ROM_ANDROID_INTERNAL = 1, - ROM_ANDROID_USB_IMG = 2, - ROM_ANDROID_USB_DIR = 3, + ROM_ANDROID_INTERNAL = 1, + ROM_ANDROID_USB_IMG = 2, + ROM_ANDROID_USB_DIR = 3, + ROM_ANDROID_INTERNAL_HYBRID = 4, + ROM_ANDROID_USB_HYBRID = 5, - ROM_LINUX_INTERNAL = 4, - ROM_LINUX_USB = 5, + ROM_LINUX_INTERNAL = 6, + ROM_LINUX_USB = 7, - ROM_UNSUPPORTED_INT = 6, - ROM_UNSUPPORTED_USB = 7, - ROM_UNKNOWN = 8 + ROM_UNSUPPORTED_INT = 8, + ROM_UNSUPPORTED_USB = 9, + + ROM_UNKNOWN = 10 }; #define M(x) (1 << x) -#define MASK_INTERNAL (M(ROM_DEFAULT) | M(ROM_ANDROID_INTERNAL) | M(ROM_UNSUPPORTED_INT) | M(ROM_LINUX_INTERNAL)) -#define MASK_USB_ROMS (M(ROM_ANDROID_USB_IMG) | M(ROM_ANDROID_USB_DIR) | M(ROM_UNSUPPORTED_USB) | M(ROM_LINUX_USB)) -#define MASK_ANDROID (M(ROM_ANDROID_USB_DIR) | M(ROM_ANDROID_USB_IMG) | M(ROM_ANDROID_INTERNAL)) +#define MASK_INTERNAL (M(ROM_DEFAULT) | M(ROM_ANDROID_INTERNAL) | M(ROM_ANDROID_INTERNAL_HYBRID) | M(ROM_UNSUPPORTED_INT) | M(ROM_LINUX_INTERNAL)) +#define MASK_USB_ROMS (M(ROM_ANDROID_USB_IMG) | M(ROM_ANDROID_USB_DIR) | M(ROM_ANDROID_USB_HYBRID) | M(ROM_UNSUPPORTED_USB) | M(ROM_LINUX_USB)) +#define MASK_ANDROID (M(ROM_ANDROID_USB_DIR) | M(ROM_ANDROID_USB_HYBRID) | M(ROM_ANDROID_USB_IMG) | M(ROM_ANDROID_INTERNAL) | M(ROM_ANDROID_INTERNAL_HYBRID)) +#define MASK_HYBRID (M(ROM_ANDROID_INTERNAL_HYBRID) | M(ROM_ANDROID_USB_HYBRID)) #define MASK_UNSUPPORTED (M(ROM_UNSUPPORTED_USB) | M(ROM_UNSUPPORTED_INT)) #define MASK_LINUX (M(ROM_LINUX_INTERNAL) | M(ROM_LINUX_USB)) #define MASK_KEXEC (MASK_LINUX) @@ -110,8 +114,13 @@ struct multirom_status int enable_kmsg_logging; int hide_internal; char *int_display_name; + char os_version[20]; + char os_level[20]; + char os_version_raw[20]; + char os_level_raw[20]; int rotation; int force_generic_fb; + int use_primary_kernel; float anim_duration_coef; struct multirom_rom *auto_boot_rom; struct multirom_rom *current_rom; @@ -122,7 +131,7 @@ struct multirom_status struct rcadditions rc; }; -int multirom(const char *rom_to_boot); +int multirom(const char *rom_to_boot, int always_reboot); int multirom_find_base_dir(void); void multirom_emergency_reboot(void); int multirom_default_status(struct multirom_status *s); @@ -136,13 +145,13 @@ void multirom_import_internal(void); void multirom_dump_status(struct multirom_status *s); int multirom_save_status(struct multirom_status *s); void multirom_fixup_rom_name(struct multirom_rom *rom, char *name, const char *def); -int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to_boot); +int multirom_prepare_for_boot(struct multirom_status *s, struct multirom_rom *to_boot, int always_reboot); void multirom_free_status(struct multirom_status *s); void multirom_free_rom(void *rom); int multirom_init_fb(int rotation); int multirom_prep_android_mounts(struct multirom_status *s, struct multirom_rom *rom); int multirom_create_media_link(struct multirom_status *s); -int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_part **fw_part); +int multirom_process_android_fstab(char *fstab_name, int has_fw, struct fstab_part **fw_part, int treble_fstab); int multirom_get_api_level(const char *path); int multirom_get_rom_type(struct multirom_rom *rom); int multirom_get_trampoline_ver(void); diff --git a/no_kexec.c b/no_kexec.c index 10651452..c691481a 100644 --- a/no_kexec.c +++ b/no_kexec.c @@ -34,6 +34,7 @@ #include "lib/inject.h" #include "lib/log.h" #include "lib/util.h" +#include "lib/mrom_data.h" #include "multirom.h" #include "version.h" @@ -75,22 +76,22 @@ char *nokexec_find_boot_mmcblk_path(struct multirom_status *s) INFO(NO_KEXEC_LOG_TEXT ": found boot at '%s'\n", boot->device); else { - INFO(NO_KEXEC_LOG_TEXT ": not found in fstab, try looking at mrom.fstab...\n"); + INFO(NO_KEXEC_LOG_TEXT ": not found in fstab, try looking at mrom_fstab...\n"); struct fstab *mrom_fstab; char path_mrom_fstab[256]; - sprintf(path_mrom_fstab, "%s/%s", mrom_dir(), "mrom.fstab"); + sprintf(path_mrom_fstab, "%s/%s", mrom_dir(), "mrom_fsbat"); mrom_fstab = fstab_load(path_mrom_fstab, 1); if (!mrom_fstab) { - ERROR(NO_KEXEC_LOG_TEXT ": couldn't load mrom.fstab '%s'\n", path_mrom_fstab); + ERROR(NO_KEXEC_LOG_TEXT ": couldn't load mrom_fstab '%s'\n", path_mrom_fstab); return NULL; } boot = fstab_find_first_by_path(mrom_fstab, "/boot"); if (boot) - INFO(NO_KEXEC_LOG_TEXT ": found boot (using mrom.fstab) at '%s'\n", boot->device); + INFO(NO_KEXEC_LOG_TEXT ": found boot (using mrom_fstab) at '%s'\n", boot->device); else return NULL; } @@ -184,6 +185,136 @@ int nokexec_set_secondary_flag(void) return res; } +int nokexec_set_skip_mr_flag(void) +{ + // echo -ne "\x71" | dd of=/dev/nk bs=1 seek=63 count=1 conv=notrunc + int res = -1; + struct bootimg img; + + // make note that the primary slot now contains a secondary boot.img + // by tagging the BOOT_NAME at the very end, even after a null terminated "tr_verNN" string + INFO(NO_KEXEC_LOG_TEXT ": Going to tag the bootimg in primary slot as skip_mr\n"); + + if (libbootimg_init_load(&img, nokexec_s.path_boot_mmcblk, LIBBOOTIMG_LOAD_ALL) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); + return -1; + } + + // Update the boot.img + img.hdr.name[BOOT_NAME_SIZE-1] = 0x72; + + INFO(NO_KEXEC_LOG_TEXT ": Writing boot.img updated with secondary flag set\n"); + if (libbootimg_write_img(&img, nokexec_s.path_boot_mmcblk) < 0) + { + ERROR("Failed to libbootimg_write_img!\n"); + } + else + res = 0; + + libbootimg_destroy(&img); + return res; +} + +int nokexec_unset_skip_mr_flag(void) +{ + // echo -ne "\x71" | dd of=/dev/nk bs=1 seek=63 count=1 conv=notrunc + int res = -1; + struct bootimg img; + + // make note that the primary slot now contains a secondary boot.img + // by tagging the BOOT_NAME at the very end, even after a null terminated "tr_verNN" string + INFO(NO_KEXEC_LOG_TEXT ": Going to tag the bootimg in primary slot as skip_mr\n"); + + if (libbootimg_init_load(&img, "/dev/block/bootdevice/by-name/boot", LIBBOOTIMG_LOAD_ALL) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); + return -1; + } + + // Update the boot.img + img.hdr.name[BOOT_NAME_SIZE-1] = 0x70; + + INFO(NO_KEXEC_LOG_TEXT ": Writing boot.img updated with secondary flag set\n"); + if (libbootimg_write_img(&img, "/dev/block/bootdevice/by-name/boot") < 0) + { + ERROR("Failed to libbootimg_write_img!\n"); + } + else + res = 0; + + libbootimg_destroy(&img); + return res; +} + +int nokexec_set_oslevel(char *secondary_path) +{ + int res = -1; + struct bootimg primary_img, secondary_img; + + INFO(NO_KEXEC_LOG_TEXT ": Going to check the bootimg in primary slot for slevel\n"); + + if (libbootimg_init_load(&primary_img, nokexec_s.path_boot_mmcblk, LIBBOOTIMG_LOAD_ALL) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); + return -1; + } + + if (libbootimg_init_load(&secondary_img, secondary_path, LIBBOOTIMG_LOAD_ALL) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); + return -1; + } + + char* primary_os_version = libbootimg_get_osversion(&primary_img.hdr, true); + char* primary_os_level = libbootimg_get_oslevel(&primary_img.hdr, true); + + char* secondary_os_version = libbootimg_get_osversion(&secondary_img.hdr, true); + char* secondary_os_level = libbootimg_get_oslevel(&secondary_img.hdr, true); + + if (strtol(primary_os_level, NULL, 10) > strtol(secondary_os_level, NULL, 10) || strtol(primary_os_version, NULL, 10) > strtol(secondary_os_version, NULL, 10)) { + secondary_img.hdr.oslevel = primary_img.hdr.oslevel; + } + + INFO(NO_KEXEC_LOG_TEXT ": Writing boot.img updated with new security patch\n"); + if (libbootimg_write_img(&secondary_img, secondary_path) < 0) + { + ERROR("Failed to libbootimg_write_img!\n"); + } + else + res = 0; + + libbootimg_destroy(&primary_img); + libbootimg_destroy(&secondary_img); + return res; +} + +int nokexec_set_cmdline(char *secondary_path) +{ + int res = 0; + struct bootimg image; + char* custom_cmdline = "androidboot.selinux=permissive printk.devkmsg=on androidboot.android_dt_dir=/fakefsbat/"; + + INFO(NO_KEXEC_LOG_TEXT ": Going to check the bootimg in primary slot for slevel\n"); + + if (libbootimg_init_load(&image, secondary_path, LIBBOOTIMG_LOAD_ALL) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); + return -1; + } + + char* cmdline = libbootimg_get_cmdline(&image.hdr); + char* newcmdline = NULL; + asprintf(&newcmdline, "%s %s", cmdline, custom_cmdline); + + libbootimg_set_cmdline(&image.hdr, newcmdline); + free(newcmdline); + + libbootimg_destroy(&image); + return res; +} + + int nokexec_backup_primary(void) { int res; @@ -196,11 +327,13 @@ int nokexec_backup_primary(void) int nokexec_flash_to_primary(const char * source) { int res = 0; + char* temp_boot = "/secondary_boot.img"; // check trampoline no_kexec version and update if needed + copy_file(source, temp_boot); struct boot_img_hdr hdr; - if (libbootimg_load_header(&hdr, source) < 0) + if (libbootimg_load_header(&hdr, temp_boot) < 0) { ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", nokexec_s.path_boot_mmcblk); res = -1; @@ -215,7 +348,7 @@ int nokexec_flash_to_primary(const char * source) { // Trampolines in ROM boot images may get out of sync, so we need to check it and // update if needed. I can't do that during ZIP installation because of USB drives. - if(inject_bootimg(source, 1) < 0) + if(inject_bootimg(temp_boot, 1) < 0) { ERROR(NO_KEXEC_LOG_TEXT ": Failed to inject bootimg!\n"); res = -1; @@ -226,7 +359,7 @@ int nokexec_flash_to_primary(const char * source) } if (res == 0) - INFO(NO_KEXEC_LOG_TEXT ": flashing '%s' to boot partition; res=%d\n", source, res = copy_file(source, nokexec_s.path_boot_mmcblk)); + INFO(NO_KEXEC_LOG_TEXT ": flashing '%s' to boot partition; res=%d\n", temp_boot, res = copy_file(temp_boot, nokexec_s.path_boot_mmcblk)); return res; } @@ -251,6 +384,26 @@ int nokexec_is_secondary_in_primary(const char *path_boot_mmcblk) return res; } +int nokexec_is_skip_mr_flag(const char *path_boot_mmcblk) +{ + int res = 0; + struct boot_img_hdr hdr; + + if (libbootimg_load_header(&hdr, path_boot_mmcblk) < 0) + { + ERROR(NO_KEXEC_LOG_TEXT ": Could not open boot image (%s)!\n", path_boot_mmcblk); + res = -1; + } + else + { + if (hdr.name[BOOT_NAME_SIZE-1] == 0x72) + res = 1; + } + INFO(NO_KEXEC_LOG_TEXT ": Checking the primary slot bootimg for the secondary tag; res=%d\n", res); + + return res; +} + int nokexec_is_new_primary(void) { int is_new = 0; @@ -306,6 +459,40 @@ int nokexec_is_second_boot(void) return is_second_boot; } +int nokexec_is_skip_mr(void) +{ + static int is_second_boot = -1; + if(is_second_boot != -1) { + INFO(NO_KEXEC_LOG_TEXT ": returning cached info is_second_boot=%d\n", is_second_boot); + return is_second_boot; + } + + int res; + INFO(NO_KEXEC_LOG_TEXT ": Checking primary slot...\n"); + char * path_boot_mmcblk = nokexec_find_boot_mmcblk_path(NULL); + if (!path_boot_mmcblk) + return -1; + + res = nokexec_is_skip_mr_flag(path_boot_mmcblk); + free(path_boot_mmcblk); + + if (res < 0) + return -1; + else if (res == 1) + { + // it's a secondary boot.img so set second_boot=1 + INFO(NO_KEXEC_LOG_TEXT ": secondary bootimg, so second_boot=1\n"); + is_second_boot = 1; + } + else + { + INFO(NO_KEXEC_LOG_TEXT ": primary bootimg, so second_boot=0\n"); + is_second_boot = 0; + } + + return is_second_boot; +} + int nokexec_flash_secondary_bootimg(struct multirom_rom *secondary_rom) { @@ -320,6 +507,13 @@ int nokexec_flash_secondary_bootimg(struct multirom_rom *secondary_rom) // now flash the secondary boot.img to primary slot char path_bootimg[256]; sprintf(path_bootimg, "%s/%s", secondary_rom->base_path, "boot.img"); + + if (nokexec_set_oslevel(path_bootimg)) + return -3; + + if (nokexec_set_cmdline(path_bootimg)) + return -3; + if (nokexec_flash_to_primary(path_bootimg)) return -3; @@ -330,6 +524,26 @@ int nokexec_flash_secondary_bootimg(struct multirom_rom *secondary_rom) return 0; } +int nokexec_flash_skip_mr_bootimg(struct multirom_rom *secondary_rom) +{ + // make sure all the paths are set up, otherwise abort + if (!nokexec_s.path_boot_mmcblk || !nokexec_s.path_primary_bootimg) + return -1; + + // now flash the secondary boot.img to primary slot + char path_bootimg[256]; + sprintf(path_bootimg, "%s/%s", secondary_rom->base_path, "boot.img"); + + if (nokexec_flash_to_primary(path_bootimg)) + return -3; + + // make note that the primary slot now contains a secondary boot.img + if (nokexec_set_skip_mr_flag()) + return -4; + + return 0; +} + int nokexec_restore_primary_and_cleanup(void) { // make sure all the paths are set up, otherwise abort diff --git a/no_kexec.h b/no_kexec.h index c45bd91c..b381c38b 100644 --- a/no_kexec.h +++ b/no_kexec.h @@ -82,5 +82,8 @@ int nokexec_restore_primary_and_cleanup(void); int nokexec_flash_secondary_bootimg(struct multirom_rom *secondary_rom); int nokexec_is_second_boot(void); +int nokexec_is_skip_mr(void); +int nokexec_set_skip_mr_flag(void); +int nokexec_unset_skip_mr_flag(void); #endif diff --git a/rom_quirks.c b/rom_quirks.c index 9b94b697..bb400166 100644 --- a/rom_quirks.c +++ b/rom_quirks.c @@ -20,12 +20,20 @@ #include #include #include +#include +#include #include #include +#include +#include +#include +#include #include "rom_quirks.h" +#include "rq_inject_file_contexts.h" #include "lib/log.h" #include "lib/util.h" +#include "libbootimg.h" static void workaround_mount_in_sh(const char *path) { @@ -66,51 +74,6 @@ static void workaround_mount_in_sh(const char *path) free(tmp_name); } -static int inject_file_contexts(const char *path) -{ - FILE *f; - char line[512]; - - f = fopen(path, "re"); - if(!f) - { - ERROR("Failed to open /file_contexts!\n"); - return -1; - } - - while(fgets(line, sizeof(line), f)) - { - if(strstartswith(line, "/data/media/multirom")) - { - INFO("/file_contexts has been already injected.\n"); - fclose(f); - return 0; - } - } - - fclose(f); - - INFO("Injecting /file_contexts\n"); - f = fopen(path, "ae"); - if(!f) - { - ERROR("Failed to open /file_contexts for appending!\n"); - return -1; - } - - 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); - - return 0; -} - // Keep this as a backup function in case the file_contexts binary injection doesn't work static void disable_restorecon_recursive(void) { @@ -148,8 +111,12 @@ static void disable_restorecon_recursive(void) while(fgets(line, sizeof(line), f_in)) { - if(strstr(line, "restorecon_recursive ") && (strstr(line, "/data") || strstr(line, "/system") || strstr(line, "/cache") || strstr(line, "/mnt"))) - fputc('#', f_out); + if (strstr(line, "restorecon_recursive ") || (strstr(line, "restorecon ") && strstr(line, "--recursive"))) { + if (strstr(line, "/data") || strstr(line, "/system") || strstr(line, "/cache") || strstr(line, "/mnt") || + strstr(line, "/vendor")) { + fputc('#', f_out); + } + } fputs(line, f_out); } @@ -165,576 +132,229 @@ static void disable_restorecon_recursive(void) } } -/* ************************************************************************************************************************************************ */ -/* - * Functions to deal with bin formatted file_contexts (ie compiled regex) - * - */ - -#define NUM_OF_REGEXS_EXCLUSIONS 5 - -const char *multirom_exclusion_path[NUM_OF_REGEXS_EXCLUSIONS] = { - "/data/media/multirom", - "/data/media/0/multirom", - "/realdata/media/multirom", - "/realdata/media/0/multirom", - "/mnt/mrom", -}; - -// The structure and content of the compiled regex_info and study_data -// was extrapolated from '/data/media(/.*)?' compiled regex, and then -// hardcoded here, which seems to work fine for now. -// -// Alternatively, we can decompile the existing file_contexts.bin and -// find the '/data/media(/.*)?' compiled regex, and use it to build -// the multirom exclusion regexs; this may actually be a better (if possible) -// solution than hardcoding, but for the time being all the file_contexts.bin -// I've seen are all version 4, and have the same structure: -// -// Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F -// -// 00000000 21 00 00 00 75 3A 6F 62 6A 65 63 74 5F 72 3A 6D !...u:object_r:m -// 00000010 65 64 69 61 5F 72 77 5F 64 61 74 61 5F 66 69 6C edia_rw_data_fil -// 00000020 65 3A 73 30 00 12 00 00 00 2F 64 61 74 61 2F 6D e:s0...../data/m -// 00000030 65 64 69 61 28 2F 2E 2A 29 3F 00 00 00 00 00 03 edia(/.*)?...... -// 00000040 00 00 00 01 00 00 00 0B 00 00 00 62 00 00 00 45 ...........b...E -// 00000050 52 43 50 62 00 00 00 14 00 00 00 01 00 00 00 FF RCPb...........ÿ -// 00000060 FF FF FF FF FF FF FF 00 00 00 00 00 00 01 00 00 ÿÿÿÿÿÿÿ......... -// 00000070 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .@.............. -// 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 ...............Æ’ -// 00000090 00 1E 1B 1D 2F 1D 6D 1D 65 1D 64 1D 69 1D 61 92 ..../.m.e.d.i.a’ -// 000000A0 85 00 09 00 01 1D 2F 55 0D 78 00 09 19 78 00 1E …...../U.x...x.. -// 000000B0 00 2C 00 00 00 2C 00 00 00 02 00 00 00 00 00 00 .,...,.......... -// 000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ -// 000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 ................ -// 000000E0 00 . - -#define COMPILED_ERCP_P1 (char[]) { \ - 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, \ - 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00 \ - } - -#define COMPILED_ERCP_P2 (char[]) { 0x92, 0x85, 0x00, 0x09, 0x00, 0x01, 0x1D, 0x2F, 0x55, 0x0D, 0x78, 0x00, 0x09, 0x19, 0x78, 0x00 } - - -#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a - -/* Version specific changes */ -#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 -#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 -#define SELINUX_COMPILED_FCONTEXT_MODE 3 -#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 -#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5 - -#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \ - SELINUX_COMPILED_FCONTEXT_REGEX_ARCH - -/* A regular expression stem */ -typedef struct { - uint32_t stem_len; - char *stem_string; -} stem_s; - -typedef struct { - uint32_t len_context_string; - char * str_context_string; - - uint32_t len_regex_string; - char * str_regex_string; - - uint32_t mode_bits; - int32_t stem_id; - uint32_t spec_has_meta_chars; - - uint32_t prefix_len; - - uint32_t len_raw_pcre_regex_info; - char * buf_raw_pcre_regex_info; - - uint32_t len_raw_pcre_regex_study_data; - char * buf_raw_pcre_regex_study_data; -} regex_s; - - -uint8_t calc_len_raw_pcre_regex_subpart(const char *exclusion_path) -{ - char *path_less_stem = strchr(exclusion_path + 1, '/'); - return (sizeof(uint8_t) + (strlen(path_less_stem) * 2) + sizeof(COMPILED_ERCP_P2) + sizeof(uint8_t)); -} - -uint32_t calc_len_raw_pcre_regex_info(const char *exclusion_path) -{ - uint32_t r = 0; - char *path_less_stem = strchr(exclusion_path + 1, '/'); - - r += sizeof(uint32_t); // MAGIC - r += sizeof(uint32_t); // len_raw_pcre_regex_info - r += sizeof(COMPILED_ERCP_P1); // - r += sizeof(uint8_t); // len_raw_pcre_regex_subpart - r += sizeof(char); // - r += strlen(path_less_stem) * 2; // length of the unicode string - r += sizeof(COMPILED_ERCP_P2); // - r += sizeof(uint8_t); // len_raw_pcre_regex_subpart - r += sizeof(uint8_t); // null - - return r; -} - -char *construct_raw_pcre_regex_info(char *dest, const char *exclusion_path) +void rom_quirks_on_initrd_finalized(void) { - char *buf = dest; - size_t off = 0; - char *path_less_stem = strchr(exclusion_path + 1, '/'); - - uint32_t len_raw_pcre_regex_info = calc_len_raw_pcre_regex_info(exclusion_path); - uint8_t len_raw_pcre_regex_subpart = calc_len_raw_pcre_regex_subpart(exclusion_path); + int failed_file_contexts_injections = 0; - memcpy(buf + off, "ERCP", 4); - off += 4; - - memcpy(buf + off, &len_raw_pcre_regex_info, sizeof(uint32_t)); - off += sizeof(uint32_t); - - memcpy(buf + off, COMPILED_ERCP_P1, sizeof(COMPILED_ERCP_P1)); - off += sizeof(COMPILED_ERCP_P1); - - memcpy(buf + off, &len_raw_pcre_regex_subpart, sizeof(uint8_t)); - off += sizeof(uint8_t); - - memcpy(buf + off, (char[]){ 0x1B }, 1); - off += 1; - - // copy as unicode string, without trailing null - while (path_less_stem[0]) - { - buf[off++] = 0x1D; - buf[off++] = path_less_stem[0]; - path_less_stem++; + // walk over all _regular_ files in / + char* path = "/system/etc/selinux/plat_file_contexts"; + char* mnt_path = "/system/etc/selinux/plat_file_contexts"; + char* pathsar = "/system_root/system/etc/selinux/plat_file_contexts"; + if (!access(pathsar, F_OK)) { + path = pathsar; } - - memcpy(buf + off, COMPILED_ERCP_P2, sizeof(COMPILED_ERCP_P2)); - off += sizeof(COMPILED_ERCP_P2); - - memcpy(buf + off, &len_raw_pcre_regex_subpart, sizeof(uint8_t)); - off += sizeof(uint8_t); - - memcpy(buf + off, (char[]){ 0x00 }, 1); - off += 1; - - return dest; -} - - -typedef struct { - uint32_t len_raw_pcre_regex_study_data; - uint32_t unknown02; - uint32_t null_1; - uint32_t null_2; - uint32_t null_3; - uint32_t null_4; - uint32_t null_5; - uint32_t null_6; - uint32_t null_7; - uint32_t null_9; - uint32_t len_path_less_stem; -} raw_pcre_regex_study_data_s; - -uint32_t calc_len_raw_pcre_regex_study_data(UNUSED const char *exclusion_path) -{ - return sizeof(raw_pcre_regex_study_data_s); -} - -uint32_t calc_len_path_less_stem(const char *exclusion_path) -{ - return strlen(strchr(exclusion_path + 1, '/')); -} - -char *construct_raw_pcre_regex_study_data(char *dest, const char *exclusion_path) -{ - uint32_t len_raw_pcre_regex_study_data = calc_len_raw_pcre_regex_study_data(exclusion_path); - uint32_t len_path_less_stem = calc_len_path_less_stem(exclusion_path); - - memset(dest, 0, sizeof(raw_pcre_regex_study_data_s)); - - ((raw_pcre_regex_study_data_s *)dest)->len_raw_pcre_regex_study_data = len_raw_pcre_regex_study_data; - ((raw_pcre_regex_study_data_s *)dest)->unknown02 = 2; - ((raw_pcre_regex_study_data_s *)dest)->len_path_less_stem = len_path_less_stem; - - return dest; -} - - -// TODO: add error handling -static int inject_file_contexts_bin(const char *path) -{ - /* - * File Format - * - * u32 - magic number - * u32 - version - * u32 - length of pcre version EXCLUDING nul - * char - pcre version string EXCLUDING nul - * u32 - number of stems - * ** Stems - * u32 - length of stem EXCLUDING nul - * char - stem char array INCLUDING nul - * u32 - number of regexs - * ** Regexes - * u32 - length of upcoming context INCLUDING nul - * char - char array of the raw context - * u32 - length of the upcoming regex_str - * char - char array of the original regex string including the stem. - * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE - * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS - * s32 - stemid associated with the regex - * u32 - spec has meta characters - * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN - * u32 - data length of the pcre regex - * char - a bufer holding the raw pcre regex info - * u32 - data length of the pcre regex study daya - * char - a buffer holding the raw pcre regex study data - */ - - FILE *bin_file_in; - FILE *bin_file_out; - size_t len; - - // header - uint32_t magic; - uint32_t version; - uint32_t reg_version_len; - char *reg_version_string; - uint32_t regex_arch_len; - char *regex_arch_string; - - bin_file_in = fopen(path, "rb"); - if (!bin_file_in) { - ERROR("Failed to open '%s' for reading!\n", path); - return -1; + if (!access(path, F_OK)) { + char buf; + int sourcefile, destfile, n; + sourcefile = open(path, O_RDONLY); + destfile = open("/plat_file_contexts", O_WRONLY | O_CREAT, 0644); + while((n = read(sourcefile, &buf, 1))) + { + write(destfile, &buf, 1 ); + } + close(sourcefile); + close(destfile); } - - /* check if this looks like an fcontext file */ - len = fread(&magic, sizeof(uint32_t), 1, bin_file_in); - if (len != 1 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) + DIR *d = opendir("/"); + if(d) { - fclose(bin_file_in); - return -1; - } + struct dirent *dt; + char buff[128]; + while((dt = readdir(d))) + { + if(dt->d_type != DT_REG) + continue; - /* check if this version is higher than we understand */ - len = fread(&version, sizeof(uint32_t), 1, bin_file_in); - if (len != 1 || version != 4) // if (len != 1 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) - { - // we currently only support version 4, all the ones i have seen are version 4 at the moment - ERROR("Unsupported /file_contexts.bin version %d\n", version); - fclose(bin_file_in); - return -1; - } + // 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. + // Right now, we do that by adding entries into /file_contexts that say + // MultiROM folders don't have any context + // + // Android N is using the binary format of file_contexts, try to inject it + // with MultiROM exclusions, if that fails go back to the old method and remove + // 'restorecon_recursive' from init.rc scripts + // + // Android 8.0 is using text format contexts again, but now has two separate files + // 'nonplat_file_contexts' and 'plat_file_contexts', we need to patch the latter + // https://source.android.com/security/selinux/images/SELinux_Treble.pdf + // + // The possibility of several combinations of file_contexts, file_contexts.bin and + // plat_file_contexts seems to exist, so use a fail counter instead. + if( (strcmp(dt->d_name, "file_contexts") == 0) + || (strcmp(dt->d_name, "file_contexts.bin") == 0) + || (strcmp(dt->d_name, "plat_file_contexts") == 0) + ) { + snprintf(buff, sizeof(buff), "/%s", dt->d_name); - // we can process this, let's open the output file and start - char *tmp_name = NULL; - const int size = strlen(path) + 5; - tmp_name = malloc(size); - snprintf(tmp_name, size, "%s-new", path); + if (inject_file_contexts(buff) != 0) + failed_file_contexts_injections++; + } - bin_file_out = fopen(tmp_name, "w"); - if (!bin_file_out) { - ERROR("Failed to open '%s' for writing!\n", tmp_name); - fclose(bin_file_in); - free(tmp_name); - return -1; + // 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")) + { + snprintf(buff, sizeof(buff), "/%s", dt->d_name); + workaround_mount_in_sh(buff); + } + } + closedir(d); } - /* write some magic number */ - len = fwrite(&magic, sizeof(uint32_t), 1, bin_file_out); - - /* write the version */ - len = fwrite(&version, sizeof(uint32_t), 1, bin_file_out); - - - if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { - /* read version of the regex back-end */ - len = fread(®_version_len, sizeof(uint32_t), 1, bin_file_in); - - reg_version_string = malloc(reg_version_len + 1); - len = fread(reg_version_string, sizeof(char), reg_version_len, bin_file_in); - reg_version_string[reg_version_len] = '\0'; - - /* write version of the regex back-end */ - len = fwrite(®_version_len, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(reg_version_string, sizeof(char), reg_version_len, bin_file_out); - - free(reg_version_string); - - if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) { - /* read regex arch string */ - len = fread(®ex_arch_len, sizeof(uint32_t), 1, bin_file_in); - regex_arch_string = malloc(regex_arch_len + 1); - len = fread(regex_arch_string, sizeof(char), regex_arch_len, bin_file_in); - regex_arch_string[regex_arch_len] = '\0'; - - /* write regex arch string */ - len = fwrite(®ex_arch_len, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(regex_arch_string, sizeof(char), regex_arch_len, bin_file_out); - - free(regex_arch_string); + if (access("/system/etc/selinux/plat_file_contexts", F_OK)) { + mkdir_with_perms("/system/", 0755, "root", "root"); + mkdir_with_perms("/system/etc/", 0755, "root", "root"); + mkdir_with_perms("/system/etc/selinux", 0755, "root", "root"); + copy_file("/plat_file_contexts", "/system/etc/selinux/plat_file_contexts"); + } + if (!access(mnt_path, F_OK)) { + if(!mount("/plat_file_contexts", mnt_path, "ext4", MS_BIND, "discard,nomblk_io_submit")) { + INFO("file_contexts bind mounted in system\n"); + } else { + ERROR("file_contexts bind mount failed! %s\n", strerror(errno)); } + } else { + INFO("No mount point to bind!!"); } + if (failed_file_contexts_injections) + disable_restorecon_recursive(); +} - // read in the stems, check for missing and add - uint32_t i; - uint32_t number_of_stems; - int32_t data_stem_id = -1; - int32_t realdata_stem_id = -1; - int32_t mnt_stem_id = -1; - - /* read the number of stems coming */ - len = fread(&number_of_stems, sizeof(uint32_t), 1, bin_file_in); - stem_s *stem_array; - stem_array = malloc((number_of_stems + 3) * sizeof(stem_s)); // add 3 since mrom additions could use them +char* convert_to_raw(char* str) { + char* temp = malloc(strlen(str)); + char* temp2 = temp; + char* out = calloc(1, strlen(str) + 2); + int i = 0, j = 0; - for (i = 0; i < number_of_stems; i++) - { - /* read the strlen (aka no nul) */ - len = fread(&stem_array[i].stem_len, sizeof(uint32_t), 1, bin_file_in); - - /* include the nul in the file */ - stem_array[i].stem_string = malloc(stem_array[i].stem_len + 1); - len = fread(stem_array[i].stem_string, sizeof(char), stem_array[i].stem_len + 1, bin_file_in); - - if (strcmp(stem_array[i].stem_string, "/data") == 0) - data_stem_id = i; - else if (strcmp(stem_array[i].stem_string, "/realdata") == 0) - realdata_stem_id = i; - else if (strcmp(stem_array[i].stem_string, "/mnt") == 0) - mnt_stem_id = i; + while (str[j] != '\n') { + j++; } - // if 'realdata' already exists assume multirom exclusions are present - // this should be faster than finding 'multirom' in the regexs - if (realdata_stem_id != -1) - { - INFO("/file_contexts.bin has been already injected.\n"); - for (i = 0; i < number_of_stems; i++) - free(stem_array[i].stem_string); - free(stem_array); - goto noerr; + char* token; + strcpy(temp, str); + temp[j] = '\0'; + if (strstr(temp, ".")) { + while (token = strsep(&temp, ".")) { + strcpy(out + i, token); + i += strlen(token); + } + } else if(strstr(temp, "-")) { + while (token = strsep(&temp, "-")) { + strcpy(out + i, token); + i += strlen(token); + } + } else { + strcat(temp, "00"); + strcpy(out, temp); } + free(temp2); + return out; +} - INFO("Injecting /file_contexts.bin\n"); +void rom_quirks_change_patch_and_osver(struct multirom_status *s, struct multirom_rom *to_boot) { - // add new stems here - if (data_stem_id == -1) - { - stem_array[i].stem_string = strdup("/data"); - stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); - data_stem_id = number_of_stems; - number_of_stems += 1; - } - if (realdata_stem_id == -1) - { - stem_array[i].stem_string = strdup("/realdata"); - stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); - realdata_stem_id = number_of_stems; - number_of_stems += 1; - } - if (mnt_stem_id == -1) - { - stem_array[i].stem_string = strdup("/mnt"); - stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); - mnt_stem_id = number_of_stems; - number_of_stems += 1; + char* path = "/system/build.prop"; + char* mnt_path = "/system/build.prop"; + char* pathsar = "/system_root/system/build.prop"; + if (!access(pathsar, F_OK)) { + path = pathsar; } + char* patchstring = NULL, *stringtoappend = NULL; + char* existing_ver = NULL; + char* existing_level = NULL; + int sourcefile, destfile, n; - /* write the number of stems coming */ - len = fwrite(&number_of_stems, sizeof(uint32_t), 1, bin_file_out); + char* primary_os_version = s->os_version; + char* primary_os_level = s->os_level; - for (i = 0; i < number_of_stems; i++) - { - /* write the strlen (aka no nul) */ - len = fwrite(&stem_array[i].stem_len, sizeof(uint32_t), 1, bin_file_out); + char* primary_os_ver_raw = s->os_version_raw; + char* primary_os_level_raw = s->os_level_raw; - /* include the nul in the file */ - len = fwrite(stem_array[i].stem_string, sizeof(char), stem_array[i].stem_len + 1, bin_file_out); + sourcefile = open(path, O_RDONLY, 0644); - free(stem_array[i].stem_string); + if (sourcefile == -1) { + ERROR("open failed! %s\n", strerror(errno)); } - free(stem_array); - - uint32_t number_of_regexs; - /* read the number of regexes coming */ - len = fread(&number_of_regexs, sizeof(uint32_t), 1, bin_file_in); + struct stat stats; + int status; + int size; - /* write the number of regexes coming */ - number_of_regexs += NUM_OF_REGEXS_EXCLUSIONS; // add mrom exclusions count - len = fwrite(&number_of_regexs, sizeof(uint32_t), 1, bin_file_out); - - - //// now write (actually copy/paste) the normal regexs back since we don't want to - //// read and parse them in, do nothing and write them back - #define BUFFER_SIZE 1024*1024 - char *buf = malloc(BUFFER_SIZE); - while ((len = fread(buf, 1, BUFFER_SIZE, bin_file_in)) > 0) - { - len = fwrite(buf, 1, len, bin_file_out); + status = stat(path, &stats); + if(status == 0) { + size = stats.st_size; } - free(buf); + asprintf(&patchstring, "%s=%s\n%s=%s", "ro.build.version.security_patch", primary_os_level, "ro.build.version.release", primary_os_version); + char* filebuf = calloc(1, size + strlen(patchstring)); - // now adjust the stem_id and write the multirom exclusions - for (i = 0; i < NUM_OF_REGEXS_EXCLUSIONS; i++) - { - regex_s regex; - - // build the compiled regex - regex.str_context_string = "<>", - regex.len_context_string = strlen(regex.str_context_string) + 1; - - regex.str_regex_string = malloc(strlen(multirom_exclusion_path[i]) + 7); - strcpy(regex.str_regex_string, multirom_exclusion_path[i]); - strcat(regex.str_regex_string, "(/.*)?"); - - regex.len_regex_string = strlen(regex.str_regex_string) + 1; - regex.prefix_len = strlen(multirom_exclusion_path[i]); - - regex.mode_bits = 0x00000000; - regex.spec_has_meta_chars = 0x00000001; - - if (strncmp(regex.str_regex_string, "/data", sizeof("/data") - 1) == 0) - regex.stem_id = data_stem_id; - else if (strncmp(regex.str_regex_string, "/realdata", sizeof("/realdata") - 1) == 0) - regex.stem_id = realdata_stem_id; - else if (strncmp(regex.str_regex_string, "/mnt", sizeof("/mnt") - 1) == 0) - regex.stem_id = mnt_stem_id; - // else error + n = read(sourcefile, filebuf, size); + if (n == -1) { + ERROR("read failed! %s\n", strerror(errno)); + } + close(sourcefile); - // now write the compiled regex - len = fwrite(®ex.len_context_string, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(regex.str_context_string, sizeof(char), regex.len_context_string, bin_file_out); - - len = fwrite(®ex.len_regex_string, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(regex.str_regex_string, sizeof(char), regex.len_regex_string, bin_file_out); - - len = fwrite(®ex.mode_bits, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(®ex.stem_id, sizeof(int32_t), 1, bin_file_out); - len = fwrite(®ex.spec_has_meta_chars, sizeof(uint32_t), 1, bin_file_out); + existing_level = strstr(filebuf, "ro.build.version.security_patch"); + existing_level += strlen("ro.build.version.security_patch="); - len = fwrite(®ex.prefix_len, sizeof(uint32_t), 1, bin_file_out); - free(regex.str_regex_string); + existing_ver = strstr(filebuf, "ro.build.version.release"); + existing_ver += strlen("ro.build.version.release="); + char* existing_level_raw = convert_to_raw(existing_level); + char* existing_ver_raw = convert_to_raw(existing_ver); - // construct here (ie we're constructing it from extrapolating from '/data/media(/.*)?', not generating a compiled version) - regex.len_raw_pcre_regex_info = (uint32_t)calc_len_raw_pcre_regex_info(multirom_exclusion_path[i]); - regex.buf_raw_pcre_regex_info = malloc(regex.len_raw_pcre_regex_info); - if(regex.buf_raw_pcre_regex_info) - { - construct_raw_pcre_regex_info(regex.buf_raw_pcre_regex_info, multirom_exclusion_path[i]); - len = fwrite(®ex.len_raw_pcre_regex_info, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(regex.buf_raw_pcre_regex_info, sizeof(char), regex.len_raw_pcre_regex_info, bin_file_out); - free(regex.buf_raw_pcre_regex_info); - } - //else error + if (strtol(existing_ver_raw, NULL, 10) >= 1100) { + free(patchstring); + asprintf(&patchstring, "%s=%s\n%s=%s\n%s=%s", "ro.build.version.security_patch", primary_os_level, "ro.build.version.release", primary_os_version, "ro.build.version.release_or_codename", primary_os_version); + free(filebuf); + filebuf = calloc(1, size + strlen(patchstring)); - regex.len_raw_pcre_regex_study_data = (uint32_t)calc_len_raw_pcre_regex_study_data(multirom_exclusion_path[i]); - regex.buf_raw_pcre_regex_study_data = malloc(regex.len_raw_pcre_regex_study_data); - if(regex.buf_raw_pcre_regex_study_data) - { - construct_raw_pcre_regex_study_data(regex.buf_raw_pcre_regex_study_data, multirom_exclusion_path[i]); - len = fwrite(®ex.len_raw_pcre_regex_study_data, sizeof(uint32_t), 1, bin_file_out); - len = fwrite(regex.buf_raw_pcre_regex_study_data, sizeof(char), regex.len_raw_pcre_regex_study_data, bin_file_out); - free(regex.buf_raw_pcre_regex_study_data); - } - //else error } -out: - fclose(bin_file_out); - fclose(bin_file_in); - rename(tmp_name, path); - chmod(path, 0644); - //copy_file(path, "/cache/file_contexts.bin-new"); // in case we need to debug - free(tmp_name); - return 0; -noerr: - fclose(bin_file_out); - fclose(bin_file_in); - remove(tmp_name); - free(tmp_name); - return 0; -err: - fclose(bin_file_out); - fclose(bin_file_in); - remove(tmp_name); - free(tmp_name); - return -2; -} -/* ************************************************************************************************************************************************ */ + INFO("primary %s %s existing %s", primary_os_level_raw, primary_os_ver_raw, existing_level_raw, existing_ver_raw); + if (strtol(primary_os_ver_raw, NULL, 10) != strtol(existing_ver_raw, NULL, 10) || strtol(primary_os_level_raw, NULL, 10) != strtol(existing_level_raw, NULL, 10) || s->use_primary_kernel || !to_boot->has_bootimg) { -void rom_quirks_on_initrd_finalized(void) -{ - // walk over all _regular_ files in / - DIR *d = opendir("/"); - if(d) - { - struct dirent *dt; - char buff[128]; - while((dt = readdir(d))) - { - if(dt->d_type != DT_REG) - continue; + existing_level = strstr(filebuf, "ro.build.version.security_patch"); - // 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. - // Right now, we do that by adding entries into /file_contexts that say - // MultiROM folders don't have any context - // - // Android N is using the binary format of file_contexts, try to inject it - // with MultiROM exclusions, if that fails go back to the old method and remove - // 'restorecon_recursive' from init.rc scripts - if((strcmp(dt->d_name, "file_contexts") == 0) || (strcmp(dt->d_name, "file_contexts.bin") == 0)) - { - FILE *f; - uint32_t magic = 0; - int res = 1; + int i = 0; + while (existing_level[i] != '\n') { + i++; + } + existing_level += i; + asprintf(&stringtoappend, "%s%s", patchstring, existing_level); - snprintf(buff, sizeof(buff), "/%s", dt->d_name); + existing_ver = strstr(filebuf, "ro.build.version.release"); + memcpy(existing_ver, stringtoappend, strlen(stringtoappend)); - f = fopen(buff, "rb"); - if (f) - { - if (fread(&magic, sizeof magic, 1, f) != 1) - ERROR("Could not read magic in '%s'\n", buff); - fclose(f); - - if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) - res = inject_file_contexts_bin(buff); - else - res = inject_file_contexts(buff); - } + destfile = open("/build.prop", O_RDWR | O_CREAT, 0644); + write(destfile, filebuf, strlen(filebuf)); + INFO("build.prop %s\n", filebuf); + close(destfile); - if(res != 0) - disable_restorecon_recursive(); - } - // 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")) - { - snprintf(buff, sizeof(buff), "/%s", dt->d_name); - workaround_mount_in_sh(buff); + if (access("/system/build.prop", F_OK)) { + copy_file("/build.prop", "/system/build.prop"); + } + if (!access(mnt_path, F_OK)) { + if(!mount("/build.prop", mnt_path, "ext4", MS_BIND, "discard,nomblk_io_submit")) { + INFO("build.prop bind mounted in system\n"); + } else { + ERROR("build.prop bind mount failed! %s\n", strerror(errno)); } } - closedir(d); } + free(existing_level_raw); + free(existing_ver_raw); + free(patchstring); + if (stringtoappend) { + free(stringtoappend); + } + free(filebuf); } diff --git a/rom_quirks.h b/rom_quirks.h index 820e6290..5b493548 100644 --- a/rom_quirks.h +++ b/rom_quirks.h @@ -17,8 +17,11 @@ #ifndef ROM_QUIRKS_H #define ROM_QUIRKS_H +#include + struct multirom_rom; void rom_quirks_on_initrd_finalized(void); +void rom_quirks_change_patch_and_osver(struct multirom_status *s, struct multirom_rom *to_boot); #endif diff --git a/rq_inject_file_contexts.c b/rq_inject_file_contexts.c new file mode 100644 index 00000000..7a465981 --- /dev/null +++ b/rq_inject_file_contexts.c @@ -0,0 +1,635 @@ +/* + * This file is part of MultiROM. + * + * MultiROM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MultiROM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MultiROM. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rq_inject_file_contexts.h" + +#ifndef TARGET_RECOVERY_IS_MULTIROM + #include "lib/log.h" +#else + #include "twcommon.h" + #define INFO(...) LOGINFO("MultiROM " __VA_ARGS__) + #define ERROR(...) LOGINFO("MultiROM " __VA_ARGS__) +#endif + +#ifndef UNUSED +#define UNUSED __attribute__((unused)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#endif + + +// NOTE: stems are still hardcoded to 3 possibilities: +// "/data", "/realdata" and "/mnt" + +const char *multirom_exclusion_path[] = { + "/data/media/multirom", + "/data/media/0/multirom", + "/realdata/media/multirom", + "/realdata/media/0/multirom", + "/data/media/MultiROM", + "/data/media/0/MultiROM", + "/realdata/media/MultiROM", + "/realdata/media/0/MultiROM", + "/mnt/mrom", +}; + +#define REGEX_PATTERN "(/.*)?" +#define CONTEXT_STRING "<>" + + +/* Inject text format file_contexts */ +static int inject_file_contexts_text(const char *path) +{ + FILE *f; + char line[512]; + unsigned int i; + + f = fopen(path, "re"); + if (!f) { + ERROR("Failed to open /file_contexts!\n"); + return -1; + } + + while (fgets(line, sizeof(line), f)) { + if (strncmp(line, multirom_exclusion_path[0], strlen(multirom_exclusion_path[0])) == 0) { + INFO("/file_contexts has been already injected.\n"); + fclose(f); + return 0; + } + } + + fclose(f); + + INFO("Injecting /file_contexts\n"); + f = fopen(path, "ae"); + if (!f) { + ERROR("Failed to open /file_contexts for appending!\n"); + return -1; + } + + fputs("\n" + "# MultiROM folders\n", f); + + for (i = 0; i < ARRAY_SIZE(multirom_exclusion_path); ++i) { + fprintf(f, "%s%s %s\n", multirom_exclusion_path[i], REGEX_PATTERN, CONTEXT_STRING); + } + fclose(f); + + return 0; +} + + +/* ************************************************************************************************************************************************ */ +/* + * Functions to deal with bin formatted file_contexts (ie compiled regex) + * + */ + +// The structure and content of the compiled regex_info and study_data +// was extrapolated from '/data/media(/.*)?' compiled regex, and then +// hardcoded here, which seems to work fine for now. +// +// Alternatively, we can decompile the existing file_contexts.bin and +// find the '/data/media(/.*)?' compiled regex, and use it to build +// the multirom exclusion regexs; this may actually be a better (if possible) +// solution than hardcoding, but for the time being all the file_contexts.bin +// I've seen are all version 4, and have the same structure: +// +// Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F +// +// 00000000 21 00 00 00 75 3A 6F 62 6A 65 63 74 5F 72 3A 6D !...u:object_r:m +// 00000010 65 64 69 61 5F 72 77 5F 64 61 74 61 5F 66 69 6C edia_rw_data_fil +// 00000020 65 3A 73 30 00 12 00 00 00 2F 64 61 74 61 2F 6D e:s0...../data/m +// 00000030 65 64 69 61 28 2F 2E 2A 29 3F 00 00 00 00 00 03 edia(/.*)?...... +// 00000040 00 00 00 01 00 00 00 0B 00 00 00 62 00 00 00 45 ...........b...E +// 00000050 52 43 50 62 00 00 00 14 00 00 00 01 00 00 00 FF RCPb...........ÿ +// 00000060 FF FF FF FF FF FF FF 00 00 00 00 00 00 01 00 00 ÿÿÿÿÿÿÿ......... +// 00000070 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .@.............. +// 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 83 ...............Æ’ +// 00000090 00 1E 1B 1D 2F 1D 6D 1D 65 1D 64 1D 69 1D 61 92 ..../.m.e.d.i.a’ +// 000000A0 85 00 09 00 01 1D 2F 55 0D 78 00 09 19 78 00 1E …...../U.x...x.. +// 000000B0 00 2C 00 00 00 2C 00 00 00 02 00 00 00 00 00 00 .,...,.......... +// 000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +// 000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 ................ +// 000000E0 00 . + +#define COMPILED_ERCP_P1 (char[]) { \ + 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, \ + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00 \ + } + +#define COMPILED_ERCP_P2 (char[]) { 0x92, 0x85, 0x00, 0x09, 0x00, 0x01, 0x1D, 0x2F, 0x55, 0x0D, 0x78, 0x00, 0x09, 0x19, 0x78, 0x00 } + + +#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a + +/* Version specific changes */ +#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 +#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 +#define SELINUX_COMPILED_FCONTEXT_MODE 3 +#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 +#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH 5 + +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \ + SELINUX_COMPILED_FCONTEXT_REGEX_ARCH + +/* A regular expression stem */ +typedef struct { + uint32_t stem_len; + char *stem_string; +} stem_s; + +typedef struct { + uint32_t len_context_string; + char * str_context_string; + + uint32_t len_regex_string; + char * str_regex_string; + + uint32_t mode_bits; + int32_t stem_id; + uint32_t spec_has_meta_chars; + + uint32_t prefix_len; + + uint32_t len_raw_pcre_regex_info; + char * buf_raw_pcre_regex_info; + + uint32_t len_raw_pcre_regex_study_data; + char * buf_raw_pcre_regex_study_data; +} regex_s; + + +static uint8_t calc_len_raw_pcre_regex_subpart(const char *exclusion_path) +{ + char *path_less_stem = strchr(exclusion_path + 1, '/'); + return (sizeof(uint8_t) + (strlen(path_less_stem) * 2) + sizeof(COMPILED_ERCP_P2) + sizeof(uint8_t)); +} + +static uint32_t calc_len_raw_pcre_regex_info(const char *exclusion_path) +{ + uint32_t r = 0; + char *path_less_stem = strchr(exclusion_path + 1, '/'); + + r += sizeof(uint32_t); // MAGIC + r += sizeof(uint32_t); // len_raw_pcre_regex_info + r += sizeof(COMPILED_ERCP_P1); // + r += sizeof(uint8_t); // len_raw_pcre_regex_subpart + r += sizeof(char); // + r += strlen(path_less_stem) * 2; // length of the unicode string + r += sizeof(COMPILED_ERCP_P2); // + r += sizeof(uint8_t); // len_raw_pcre_regex_subpart + r += sizeof(uint8_t); // null + + return r; +} + +static char *construct_raw_pcre_regex_info(char *dest, const char *exclusion_path) +{ + char *buf = dest; + size_t off = 0; + char *path_less_stem = strchr(exclusion_path + 1, '/'); + + uint32_t len_raw_pcre_regex_info = calc_len_raw_pcre_regex_info(exclusion_path); + uint8_t len_raw_pcre_regex_subpart = calc_len_raw_pcre_regex_subpart(exclusion_path); + + memcpy(buf + off, "ERCP", 4); + off += 4; + + memcpy(buf + off, &len_raw_pcre_regex_info, sizeof(uint32_t)); + off += sizeof(uint32_t); + + memcpy(buf + off, COMPILED_ERCP_P1, sizeof(COMPILED_ERCP_P1)); + off += sizeof(COMPILED_ERCP_P1); + + memcpy(buf + off, &len_raw_pcre_regex_subpart, sizeof(uint8_t)); + off += sizeof(uint8_t); + + memcpy(buf + off, (char[]){ 0x1B }, 1); + off += 1; + + // copy as unicode string, without trailing null + while (path_less_stem[0]) + { + buf[off++] = 0x1D; + buf[off++] = path_less_stem[0]; + path_less_stem++; + } + + memcpy(buf + off, COMPILED_ERCP_P2, sizeof(COMPILED_ERCP_P2)); + off += sizeof(COMPILED_ERCP_P2); + + memcpy(buf + off, &len_raw_pcre_regex_subpart, sizeof(uint8_t)); + off += sizeof(uint8_t); + + memcpy(buf + off, (char[]){ 0x00 }, 1); + off += 1; + + return dest; +} + + +typedef struct { + uint32_t len_raw_pcre_regex_study_data; + uint32_t unknown02; + uint32_t null_1; + uint32_t null_2; + uint32_t null_3; + uint32_t null_4; + uint32_t null_5; + uint32_t null_6; + uint32_t null_7; + uint32_t null_9; + uint32_t len_path_less_stem; +} raw_pcre_regex_study_data_s; + +static uint32_t calc_len_raw_pcre_regex_study_data(UNUSED const char *exclusion_path) +{ + return sizeof(raw_pcre_regex_study_data_s); +} + +static uint32_t calc_len_path_less_stem(const char *exclusion_path) +{ + return strlen(strchr(exclusion_path + 1, '/')); +} + +static char *construct_raw_pcre_regex_study_data(char *dest, const char *exclusion_path) +{ + uint32_t len_raw_pcre_regex_study_data = calc_len_raw_pcre_regex_study_data(exclusion_path); + uint32_t len_path_less_stem = calc_len_path_less_stem(exclusion_path); + + memset(dest, 0, sizeof(raw_pcre_regex_study_data_s)); + + ((raw_pcre_regex_study_data_s *)dest)->len_raw_pcre_regex_study_data = len_raw_pcre_regex_study_data; + ((raw_pcre_regex_study_data_s *)dest)->unknown02 = 2; + ((raw_pcre_regex_study_data_s *)dest)->len_path_less_stem = len_path_less_stem; + + return dest; +} + + +/* Inject binary format file_contexts */ +// TODO: add error handling +static int inject_file_contexts_bin(const char *path) +{ + /* + * File Format + * + * u32 - magic number + * u32 - version + * u32 - length of pcre version EXCLUDING nul + * char - pcre version string EXCLUDING nul + * u32 - number of stems + * ** Stems + * u32 - length of stem EXCLUDING nul + * char - stem char array INCLUDING nul + * u32 - number of regexs + * ** Regexes + * u32 - length of upcoming context INCLUDING nul + * char - char array of the raw context + * u32 - length of the upcoming regex_str + * char - char array of the original regex string including the stem. + * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE + * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS + * s32 - stemid associated with the regex + * u32 - spec has meta characters + * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN + * u32 - data length of the pcre regex + * char - a bufer holding the raw pcre regex info + * u32 - data length of the pcre regex study daya + * char - a buffer holding the raw pcre regex study data + */ + + FILE *bin_file_in; + FILE *bin_file_out; + size_t len; + + // header + uint32_t magic; + uint32_t version; + uint32_t reg_version_len; + char *reg_version_string; + uint32_t regex_arch_len; + char *regex_arch_string; + + bin_file_in = fopen(path, "rb"); + if (!bin_file_in) { + ERROR("Failed to open '%s' for reading!\n", path); + return -1; + } + + /* check if this looks like an fcontext file */ + len = fread(&magic, sizeof(uint32_t), 1, bin_file_in); + if (len != 1 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) + { + fclose(bin_file_in); + return -1; + } + + /* check if this version is higher than we understand */ + len = fread(&version, sizeof(uint32_t), 1, bin_file_in); + if (len != 1 || version != 4) // if (len != 1 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) + { + // we currently only support version 4, all the ones i have seen are version 4 at the moment + ERROR("Unsupported /file_contexts.bin version %d\n", version); + fclose(bin_file_in); + return -1; + } + + + // we can process this, let's open the output file and start + char *tmp_name = NULL; + const int size = strlen(path) + 5; + tmp_name = malloc(size); + snprintf(tmp_name, size, "%s-new", path); + + bin_file_out = fopen(tmp_name, "w"); + if (!bin_file_out) { + ERROR("Failed to open '%s' for writing!\n", tmp_name); + fclose(bin_file_in); + free(tmp_name); + return -1; + } + + /* write some magic number */ + len = fwrite(&magic, sizeof(uint32_t), 1, bin_file_out); + + /* write the version */ + len = fwrite(&version, sizeof(uint32_t), 1, bin_file_out); + + + if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { + /* read version of the regex back-end */ + len = fread(®_version_len, sizeof(uint32_t), 1, bin_file_in); + + reg_version_string = malloc(reg_version_len + 1); + len = fread(reg_version_string, sizeof(char), reg_version_len, bin_file_in); + reg_version_string[reg_version_len] = '\0'; + + /* write version of the regex back-end */ + len = fwrite(®_version_len, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(reg_version_string, sizeof(char), reg_version_len, bin_file_out); + + free(reg_version_string); + + if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) { + /* read regex arch string */ + len = fread(®ex_arch_len, sizeof(uint32_t), 1, bin_file_in); + regex_arch_string = malloc(regex_arch_len + 1); + len = fread(regex_arch_string, sizeof(char), regex_arch_len, bin_file_in); + regex_arch_string[regex_arch_len] = '\0'; + + /* write regex arch string */ + len = fwrite(®ex_arch_len, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(regex_arch_string, sizeof(char), regex_arch_len, bin_file_out); + + free(regex_arch_string); + } + } + + + // read in the stems, check for missing and add + uint32_t i; + uint32_t number_of_stems; + int32_t data_stem_id = -1; + int32_t realdata_stem_id = -1; + int32_t mnt_stem_id = -1; + + /* read the number of stems coming */ + len = fread(&number_of_stems, sizeof(uint32_t), 1, bin_file_in); + stem_s *stem_array; + stem_array = malloc((number_of_stems + 3) * sizeof(stem_s)); // add 3 since mrom additions could use them + + for (i = 0; i < number_of_stems; i++) + { + /* read the strlen (aka no nul) */ + len = fread(&stem_array[i].stem_len, sizeof(uint32_t), 1, bin_file_in); + + /* include the nul in the file */ + stem_array[i].stem_string = malloc(stem_array[i].stem_len + 1); + len = fread(stem_array[i].stem_string, sizeof(char), stem_array[i].stem_len + 1, bin_file_in); + + if (strcmp(stem_array[i].stem_string, "/data") == 0) + data_stem_id = i; + else if (strcmp(stem_array[i].stem_string, "/realdata") == 0) + realdata_stem_id = i; + else if (strcmp(stem_array[i].stem_string, "/mnt") == 0) + mnt_stem_id = i; + } + + // if 'realdata' already exists assume multirom exclusions are present + // this should be faster than finding 'multirom' in the regexs + if (realdata_stem_id != -1) + { + INFO("/file_contexts.bin has been already injected.\n"); + for (i = 0; i < number_of_stems; i++) + free(stem_array[i].stem_string); + free(stem_array); + goto noerr; + } + + INFO("Injecting /file_contexts.bin\n"); + + // add new stems here + if (data_stem_id == -1) + { + stem_array[i].stem_string = strdup("/data"); + stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); + data_stem_id = number_of_stems; + number_of_stems += 1; + } + if (realdata_stem_id == -1) + { + stem_array[i].stem_string = strdup("/realdata"); + stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); + realdata_stem_id = number_of_stems; + number_of_stems += 1; + } + if (mnt_stem_id == -1) + { + stem_array[i].stem_string = strdup("/mnt"); + stem_array[number_of_stems].stem_len = strlen(stem_array[i].stem_string); + mnt_stem_id = number_of_stems; + number_of_stems += 1; + } + + /* write the number of stems coming */ + len = fwrite(&number_of_stems, sizeof(uint32_t), 1, bin_file_out); + + for (i = 0; i < number_of_stems; i++) + { + /* write the strlen (aka no nul) */ + len = fwrite(&stem_array[i].stem_len, sizeof(uint32_t), 1, bin_file_out); + + /* include the nul in the file */ + len = fwrite(stem_array[i].stem_string, sizeof(char), stem_array[i].stem_len + 1, bin_file_out); + + free(stem_array[i].stem_string); + } + free(stem_array); + + + uint32_t number_of_regexs; + /* read the number of regexes coming */ + len = fread(&number_of_regexs, sizeof(uint32_t), 1, bin_file_in); + + /* write the number of regexes coming */ + number_of_regexs += ARRAY_SIZE(multirom_exclusion_path); // add mrom exclusions count + len = fwrite(&number_of_regexs, sizeof(uint32_t), 1, bin_file_out); + + + //// now write (actually copy/paste) the normal regexs back since we don't want to + //// read and parse them in, do nothing and write them back + #define BUFFER_SIZE 1024*1024 + char *buf = malloc(BUFFER_SIZE); + while ((len = fread(buf, 1, BUFFER_SIZE, bin_file_in)) > 0) + { + len = fwrite(buf, 1, len, bin_file_out); + } + free(buf); + + + // now adjust the stem_id and write the multirom exclusions + for (i = 0; i < ARRAY_SIZE(multirom_exclusion_path); ++i) + { + regex_s regex; + + // build the compiled regex + regex.str_context_string = CONTEXT_STRING, + regex.len_context_string = strlen(regex.str_context_string) + 1; + + regex.str_regex_string = malloc(strlen(multirom_exclusion_path[i]) + strlen(REGEX_PATTERN) + 1); + strcpy(regex.str_regex_string, multirom_exclusion_path[i]); + strcat(regex.str_regex_string, REGEX_PATTERN); + + regex.len_regex_string = strlen(regex.str_regex_string) + 1; + regex.prefix_len = strlen(multirom_exclusion_path[i]); + + regex.mode_bits = 0x00000000; + regex.spec_has_meta_chars = 0x00000001; + + if (strncmp(regex.str_regex_string, "/data", sizeof("/data") - 1) == 0) + regex.stem_id = data_stem_id; + else if (strncmp(regex.str_regex_string, "/realdata", sizeof("/realdata") - 1) == 0) + regex.stem_id = realdata_stem_id; + else if (strncmp(regex.str_regex_string, "/mnt", sizeof("/mnt") - 1) == 0) + regex.stem_id = mnt_stem_id; + // else error + + + // now write the compiled regex + len = fwrite(®ex.len_context_string, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(regex.str_context_string, sizeof(char), regex.len_context_string, bin_file_out); + + len = fwrite(®ex.len_regex_string, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(regex.str_regex_string, sizeof(char), regex.len_regex_string, bin_file_out); + + len = fwrite(®ex.mode_bits, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(®ex.stem_id, sizeof(int32_t), 1, bin_file_out); + len = fwrite(®ex.spec_has_meta_chars, sizeof(uint32_t), 1, bin_file_out); + + len = fwrite(®ex.prefix_len, sizeof(uint32_t), 1, bin_file_out); + free(regex.str_regex_string); + + + // construct here (ie we're constructing it from extrapolating from '/data/media(/.*)?', not generating a compiled version) + regex.len_raw_pcre_regex_info = (uint32_t)calc_len_raw_pcre_regex_info(multirom_exclusion_path[i]); + regex.buf_raw_pcre_regex_info = malloc(regex.len_raw_pcre_regex_info); + if(regex.buf_raw_pcre_regex_info) + { + construct_raw_pcre_regex_info(regex.buf_raw_pcre_regex_info, multirom_exclusion_path[i]); + len = fwrite(®ex.len_raw_pcre_regex_info, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(regex.buf_raw_pcre_regex_info, sizeof(char), regex.len_raw_pcre_regex_info, bin_file_out); + free(regex.buf_raw_pcre_regex_info); + } + //else error + + regex.len_raw_pcre_regex_study_data = (uint32_t)calc_len_raw_pcre_regex_study_data(multirom_exclusion_path[i]); + regex.buf_raw_pcre_regex_study_data = malloc(regex.len_raw_pcre_regex_study_data); + if(regex.buf_raw_pcre_regex_study_data) + { + construct_raw_pcre_regex_study_data(regex.buf_raw_pcre_regex_study_data, multirom_exclusion_path[i]); + len = fwrite(®ex.len_raw_pcre_regex_study_data, sizeof(uint32_t), 1, bin_file_out); + len = fwrite(regex.buf_raw_pcre_regex_study_data, sizeof(char), regex.len_raw_pcre_regex_study_data, bin_file_out); + free(regex.buf_raw_pcre_regex_study_data); + } + //else error + } + +out: + fclose(bin_file_out); + fclose(bin_file_in); + rename(tmp_name, path); + chmod(path, 0644); +#if 0 + // in case we need to debug + copy_file(path, "/cache/file_contexts.bin-new"); +#endif + free(tmp_name); + return 0; +noerr: + fclose(bin_file_out); + fclose(bin_file_in); + remove(tmp_name); + free(tmp_name); + return 0; +err: + fclose(bin_file_out); + fclose(bin_file_in); + remove(tmp_name); + free(tmp_name); + return -2; +} +/* ************************************************************************************************************************************************ */ + +/* + * Main inject_file_contexts() function will determine + * if the file is a compiled binary format or text format + * and act accordingly. + */ +int inject_file_contexts(const char *path) +{ + FILE *f; + uint32_t magic = 0; + int res = 1; + + f = fopen(path, "rb"); + if (f) { + if (fread(&magic, sizeof magic, 1, f) != 1) + ERROR("Could not read magic in '%s'\n", path); + fclose(f); + + if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) + res = inject_file_contexts_bin(path); + else + res = inject_file_contexts_text(path); + } + return res; +} diff --git a/rq_inject_file_contexts.h b/rq_inject_file_contexts.h new file mode 100644 index 00000000..88183ca2 --- /dev/null +++ b/rq_inject_file_contexts.h @@ -0,0 +1,28 @@ +/* + * This file is part of MultiROM. + * + * MultiROM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MultiROM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MultiROM. If not, see . + */ + +#ifndef _RQ_INJECT_FILE_CONTEXTS_H +#define _RQ_INJECT_FILE_CONTEXTS_H + +/* + * Main inject_file_contexts() function will determine + * if the file is a compiled binary format or text format + * and act accordingly. + */ +int inject_file_contexts(const char *path); + +#endif //_RQ_INJECT_FILE_CONTEXTS_H diff --git a/trampoline/Android.mk b/trampoline/Android.mk index 8e5cab14..5203b74f 100644 --- a/trampoline/Android.mk +++ b/trampoline/Android.mk @@ -3,16 +3,17 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES += $(multirom_local_path) $(multirom_local_path)/lib LOCAL_SRC_FILES:= \ - trampoline.c \ + trampoline.cpp \ devices.c \ adb.c \ LOCAL_MODULE:= trampoline -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libcutils libc libmultirom_static libbootimg +LOCAL_STATIC_LIBRARIES := libcutils libc libmultirom_static libbootimg libselinux libext4_utils libkeyutils libbase liblog +LOCAL_C_INCLUDES += system/extras/libbootimg/include LOCAL_FORCE_STATIC_EXECUTABLE := true ifeq ($(MR_INIT_DEVICES),) @@ -20,6 +21,10 @@ ifeq ($(MR_INIT_DEVICES),) endif LOCAL_SRC_FILES += ../../../../$(MR_INIT_DEVICES) +ifneq ($(MR_EXTRA_FIRMWARE_DIR),) + LOCAL_CFLAGS += -DMR_EXTRA_FIRMWARE_DIR="\"$(MR_EXTRA_FIRMWARE_DIR)\"" +endif + # for adb LOCAL_CFLAGS += -DPRODUCT_MODEL="\"$(PRODUCT_MODEL)\"" -DPRODUCT_MANUFACTURER="\"$(PRODUCT_MANUFACTURER)\"" @@ -63,4 +68,10 @@ ifeq ($(MR_USE_DEBUGFS_MOUNT),true) LOCAL_CFLAGS += -DMR_USE_DEBUGFS_MOUNT endif +ifeq ($(MR_DEVICE_HAS_DRM_GRAPHICS),true) + LOCAL_CFLAGS += -DMR_DEVICE_HAS_DRM_GRAPHICS +endif + +LOCAL_CPPFLAGS += $(LOCAL_CFLAGS) + include $(BUILD_EXECUTABLE) diff --git a/trampoline/devices.c b/trampoline/devices.c index 066ec79c..64e970c3 100644 --- a/trampoline/devices.c +++ b/trampoline/devices.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,9 @@ static const char *firmware_dirs[] = { "/etc/firmware", "/vendor/firmware", +#ifdef MR_EXTRA_FIRMWARE_DIR + MR_EXTRA_FIRMWARE_DIR, +#endif "/firmware/image" }; #ifdef HAVE_SELINUX @@ -799,6 +803,9 @@ static void handle_generic_device_event(struct uevent *uevent) } else if (!strncmp(uevent->subsystem, "graphics", 8)) { base = "/dev/graphics/"; make_dir(base, 0755); + } else if (!strncmp(uevent->subsystem, "drm", 3)) { + base = "/dev/dri/"; + make_dir(base, 0755); } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) { base = "/dev/oncrpc/"; make_dir(base, 0755); diff --git a/trampoline/encryption.c b/trampoline/encryption.c index e1d7e020..22ed29a5 100644 --- a/trampoline/encryption.c +++ b/trampoline/encryption.c @@ -32,41 +32,42 @@ #include "../trampoline_encmnt/encmnt_defines.h" #include "../hooks.h" +extern int e4crypt_install_keyring(); + static char encmnt_cmd_arg[64] = { 0 }; static char *const encmnt_cmd[] = { "/mrom_enc/trampoline_encmnt", encmnt_cmd_arg, NULL }; #ifdef MR_ENCRYPTION_FAKE_PROPERTIES -static char *const encmnt_envp[] = { "LD_LIBRARY_PATH=/mrom_enc/", "LD_PRELOAD=/mrom_enc/libmultirom_fake_properties.so", NULL }; +static char *const encmnt_envp[] = { "LD_CONFIG_FILE='/mrom_enc/ld.config.txt'", "LD_LIBRARY_PATH=/mrom_enc/", "LD_PRELOAD=/mrom_enc/libmultirom_fake_properties.so /mrom_enc/libmultirom_fake_propertywait.so /mrom_enc/libmultirom_fake_logger.so", NULL }; #else -static char *const encmnt_envp[] = { "LD_LIBRARY_PATH=/mrom_enc/", NULL }; +static char *const encmnt_envp[] = { "LD_CONFIG_FILE='/mrom_enc/ld.config.txt'", "LD_LIBRARY_PATH=/mrom_enc/", NULL }; #endif static int g_decrypted = 0; -#ifdef __LP64__ -#define LINKER_PATH "/system/bin/linker64" -#else -#define LINKER_PATH "/system/bin/linker" -#endif - -int encryption_before_mount(struct fstab *fstab) +int encryption_before_mount(struct fstab *fstab, bool isFbe) { int exit_code = -1; char *output = NULL, *itr; int res = ENC_RES_ERR; + struct stat stat; - mkdir_recursive("/system/bin", 0755); - remove(LINKER_PATH); - symlink("/mrom_enc/linker", LINKER_PATH); +#ifdef __LP64__ + chmod("/mrom_enc/linker64", 0775); +#else chmod("/mrom_enc/linker", 0775); +#endif chmod("/mrom_enc/trampoline_encmnt", 0775); // some fonts not in ramdisk to save space, so use regular instead symlink("/mrom_enc/res/Roboto-Regular.ttf", "/mrom_enc/res/Roboto-Italic.ttf"); symlink("/mrom_enc/res/Roboto-Regular.ttf", "/mrom_enc/res/Roboto-Medium.ttf"); - if (access("/vendor", F_OK) >= 0) { + if (lstat("/vendor", &stat) == 0) { rename("/vendor", "/vendor_boot"); } symlink("/mrom_enc/vendor", "/vendor"); + if (access("/firmware", F_OK) >= 0) { + rename("/firmware", "/firmware_boot"); + } mkdir("/firmware", 0775); struct fstab_part *fwpart = fstab_find_first_by_path(fstab, "/firmware"); if(fwpart && (strcmp(fwpart->type, "emmc") != 0 || strcmp(fwpart->type, "vfat") != 0)) @@ -81,53 +82,71 @@ int encryption_before_mount(struct fstab *fstab) INFO("Running trampoline_encmnt\n"); - strcpy(encmnt_cmd_arg, "decrypt"); + if (isFbe) { + //rename("/realdata", "/data"); + int err = mount("/realdata", "/data", NULL, MS_MOVE, NULL); + INFO("err %d %s\n", err, strerror(errno)); + int ret = e4crypt_install_keyring(); + strcpy(encmnt_cmd_arg, "decryptfbe"); + } else { + strcpy(encmnt_cmd_arg, "decrypt"); + } output = run_get_stdout_with_exit_with_env(encmnt_cmd, &exit_code, encmnt_envp); - if(exit_code != 0 || !output) + if(exit_code != 0 || (!isFbe && !output)) { ERROR("Failed to run trampoline_encmnt, exit code %d: %s\n", exit_code, output); goto exit; } - itr = output + strlen(output) - 1; - while(itr >= output && isspace(*itr)) - *itr-- = 0; - - if(strcmp(output, ENCMNT_BOOT_INTERNAL_OUTPUT) == 0) - { - INFO("trampoline_encmnt requested to boot internal ROM.\n"); - res = ENC_RES_BOOT_INTERNAL; - goto exit; + if (output != NULL) { + itr = output + strlen(output) - 1; + while(itr >= output && isspace(*itr)) + *itr-- = 0; + + if(strcmp(output, ENCMNT_BOOT_INTERNAL_OUTPUT) == 0) + { + INFO("trampoline_encmnt requested to boot internal ROM.\n"); + res = ENC_RES_BOOT_INTERNAL; + goto exit; + } + + if(strcmp(output, ENCMNT_BOOT_RECOVERY_OUTPUT) == 0) + { + INFO("trampoline_encmnt requested to boot recovery.\n"); + res = ENC_RES_BOOT_RECOVERY; + goto exit; + } } - if(strcmp(output, ENCMNT_BOOT_RECOVERY_OUTPUT) == 0) - { - INFO("trampoline_encmnt requested to boot recovery.\n"); - res = ENC_RES_BOOT_RECOVERY; - goto exit; - } + if (!isFbe) { - if(!strstartswith(output, "/dev")) - { - ERROR("Invalid trampoline_encmnt output: %s\n", output); - goto exit; - } + if(!strstartswith(output, "/dev")) + { + ERROR("Invalid trampoline_encmnt output: %s\n", output); + goto exit; + } - g_decrypted = 1; + g_decrypted = 1; - struct fstab_part *datap = fstab_find_first_by_path(fstab, "/data"); - if(!datap) - { - ERROR("Failed to find /data in fstab!\n"); - goto exit; - } + struct fstab_part *datap = fstab_find_first_by_path(fstab, "/data"); + if(!datap) + { + ERROR("Failed to find /data in fstab!\n"); + goto exit; + } - INFO("Updating device %s to %s in fstab due to encryption.\n", datap->device, output); - fstab_update_device(fstab, datap->device, output); + INFO("Updating device %s to %s in fstab due to encryption.\n", datap->device, output); + fstab_update_device(fstab, datap->device, output); + } res = ENC_RES_OK; exit: - free(output); + if (isFbe) { + //rename("/data", "/realdata"); + mount("/data", "/realdata", NULL, MS_MOVE, NULL); + mkdir("/data", 0755); + } + //free(output); return res; } @@ -147,19 +166,16 @@ void encryption_destroy(void) g_decrypted = 0; free(output); } - - // Make sure we're removing our symlink and not ROM's linker - if(lstat(LINKER_PATH, &info) >= 0 && S_ISLNK(info.st_mode)) - remove(LINKER_PATH); } int encryption_cleanup(void) { + struct stat stat; #if MR_DEVICE_HOOKS >= 6 tramp_hook_encryption_cleanup(); #endif - remove("/vendor"); - if (access("/vendor_boot", F_OK) >= 0) { + if (lstat("/vendor_boot", &stat) == 0) { + unlink("/vendor"); rename("/vendor_boot", "/vendor"); } @@ -167,5 +183,8 @@ int encryption_cleanup(void) ERROR("encryption_cleanup: failed to unmount /firmware: %s\n", strerror(errno)); rmdir("/firmware"); + if (access("/firmware_boot", F_OK) >= 0) { + rename("/firmware_boot", "/firmware"); + } return 0; } diff --git a/trampoline/encryption.h b/trampoline/encryption.h index 068833c5..d40b94a9 100644 --- a/trampoline/encryption.h +++ b/trampoline/encryption.h @@ -24,11 +24,11 @@ #define ENC_RES_BOOT_RECOVERY 2 #ifdef MR_ENCRYPTION -int encryption_before_mount(struct fstab *fstab); +int encryption_before_mount(struct fstab *fstab, bool isFbe); void encryption_destroy(void); int encryption_cleanup(void); #else -int encryption_before_mount(struct fstab *fstab) { return ENC_RES_OK; } +int encryption_before_mount(struct fstab *fstab, bool isFbe) { return ENC_RES_OK; } void encryption_destroy(void) { } int encryption_cleanup(void) { return 0; } #endif diff --git a/trampoline/trampoline.c b/trampoline/trampoline.c deleted file mode 100644 index 90507535..00000000 --- a/trampoline/trampoline.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * This file is part of MultiROM. - * - * MultiROM is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MultiROM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with MultiROM. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "devices.h" -#include "../lib/log.h" -#include "../lib/util.h" -#include "../lib/fstab.h" -#include "../lib/inject.h" -#include "../version.h" -#include "adb.h" -#include "../hooks.h" -#include "encryption.h" - -#ifdef MR_POPULATE_BY_NAME_PATH - #include "Populate_ByName_using_emmc.c" -#endif - -#define EXEC_MASK (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) -#define REALDATA "/realdata" -#define MULTIROM_BIN "multirom" -#define BUSYBOX_BIN "busybox" -#define KEEP_REALDATA "/dev/.keep_realdata" - -// Not defined in android includes? -#define MS_RELATIME (1<<21) - -static char path_multirom[64] = { 0 }; - -static int find_multirom(void) -{ - int i; - struct stat info; - - static const char *paths[] = { - REALDATA"/media/0/multirom", // 4.2 - REALDATA"/media/multirom", - NULL, - }; - - for(i = 0; paths[i]; ++i) - { - if(stat(paths[i], &info) < 0) - continue; - - strcpy(path_multirom, paths[i]); - return 0; - } - return -1; -} - -static void run_multirom(void) -{ - char path[256]; - struct stat info; - - // busybox - sprintf(path, "%s/%s", path_multirom, BUSYBOX_BIN); - if (stat(path, &info) < 0) - { - ERROR("Could not find busybox: %s\n", path); - return; - } - chmod(path, EXEC_MASK); - - // restart after crash - sprintf(path, "%s/restart_after_crash", path_multirom); - int restart = (stat(path, &info) >= 0); - - // multirom - sprintf(path, "%s/%s", path_multirom, MULTIROM_BIN); - if (stat(path, &info) < 0) - { - ERROR("Could not find multirom: %s\n", path); - return; - } - chmod(path, EXEC_MASK); - - char *cmd[] = { path, NULL }; - do - { - ERROR("Running multirom\n"); - int res = run_cmd(cmd); - if(res == 0) - break; - else - ERROR("MultiROM exited with status code %d!\n", res); - } - while(restart); -} - -static int try_mount_all_entries(struct fstab *fstab, struct fstab_part *first_data_p) -{ - size_t i; - struct fstab_part *p_itr = first_data_p; - - do - { - // Remove nosuid flag, because secondary ROMs have - // su binaries on /data - p_itr->mountflags &= ~(MS_NOSUID); - - if(mount(p_itr->device, REALDATA, p_itr->type, p_itr->mountflags, p_itr->options) >= 0) - return 0; - } - while((p_itr = fstab_find_next_by_path(fstab, "/data", p_itr))); - - ERROR("Failed to mount /realdata with data from fstab, trying all filesystems\n"); - - const char *fs_types[] = { "ext4", "f2fs", "ext3", "ext2" }; - const char *fs_opts [] = { - "barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc,errors=panic", // ext4 - "inline_xattr,flush_merge", // f2fs - "", // ext3 - "" // ext2 - }; - - for(i = 0; i < ARRAY_SIZE(fs_types); ++i) - { - if(mount(first_data_p->device, REALDATA, fs_types[i], first_data_p->mountflags, fs_opts[i]) >= 0) - { - INFO("/realdata successfuly mounted with fs %s\n", fs_types[i]); - return 0; - } - } - - return -1; -} - -static int mount_and_run(struct fstab *fstab) -{ - struct fstab_part *datap = fstab_find_first_by_path(fstab, "/data"); - if(!datap) - { - ERROR("Failed to find /data partition in fstab\n"); - return -1; - } - - if(access(datap->device, R_OK) < 0) - { - INFO("Waiting for %s\n", datap->device); - if(wait_for_file(datap->device, 5) < 0) - { - ERROR("Waiting too long for dev %s\n", datap->device); - return -1; - } - } - - mkdir(REALDATA, 0755); - - if(try_mount_all_entries(fstab, datap) < 0) - { -#ifndef MR_ENCRYPTION - ERROR("Failed to mount /data with all possible filesystems!\n"); - return -1; -#else - INFO("Failed to mount /data, trying encryption...\n"); - switch(encryption_before_mount(fstab)) - { - case ENC_RES_ERR: - ERROR("/data decryption failed!\n"); - return -1; - case ENC_RES_BOOT_INTERNAL: - return 0; - case ENC_RES_BOOT_RECOVERY: - sync(); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); // REBOOT_RECOVERY - while (1) - sleep(1); - // we're never returning - return 0; - default: - case ENC_RES_OK: - { - if(try_mount_all_entries(fstab, datap) < 0) - { - ERROR("Failed to mount decrypted /data with all possible filesystems!\n"); - return -1; - } - break; - } - } -#endif - } - - if(find_multirom() == -1) - { - ERROR("Could not find multirom folder!\n"); - return -1; - } - - adb_init(path_multirom); - run_multirom(); - adb_quit(); - return 0; -} - -static int is_charger_mode(void) -{ - char buff[2048] = { 0 }; - int charger_mode = 0; - - FILE *f = fopen("/proc/cmdline", "re"); - if(!f) - return 0; - - while (fgets(buff, sizeof(buff), f) != NULL) - { - if (strstr(buff, "androidboot.mode=charger") != NULL) - { - charger_mode = 1; - break; - } - } - - fclose(f); - - return charger_mode; -} - -static void fixup_symlinks(void) -{ - static const char *init_links[] = { "/sbin/ueventd", "/sbin/watchdogd" }; - - size_t i; - ssize_t len; - char buff[64]; - struct stat info; - - for(i = 0; i < ARRAY_SIZE(init_links); ++i) - { - if(lstat(init_links[i], &info) < 0 || !S_ISLNK(info.st_mode)) - continue; - - if (info.st_size < sizeof(buff)-1) - { - len = readlink(init_links[i], buff, sizeof(buff)-1); - if(len >= 0) - { - buff[len] = 0; - // if the symlink already points to ../init, skip it. - if(strcmp(buff, "../init") == 0) - continue; - } - } - - ERROR("Fixing up symlink '%s' -> '%s' to '%s' -> '../init')\n", init_links[i], buff, init_links[i]); - unlink(init_links[i]); - symlink("../init", init_links[i]); - } -} - -int main(int argc, char *argv[]) -{ - int i, res; - static char *const cmd[] = { "/init", NULL }; - struct fstab *fstab = NULL; - char *inject_path = NULL; - char *mrom_dir = NULL; - int force_inject = 0; - - for(i = 1; i < argc; ++i) - { - if(strcmp(argv[i], "-v") == 0) - { - printf("%d\n", VERSION_TRAMPOLINE); - fflush(stdout); - return 0; - } - else if(strstartswith(argv[i], "--inject=")) - inject_path = argv[i] + strlen("--inject="); - else if(strstartswith(argv[i], "--mrom_dir=")) - mrom_dir = argv[i] + strlen("--mrom_dir="); - else if(strcmp(argv[i], "-f") == 0) - force_inject = 1; - } - - if(inject_path) - { - if(!mrom_dir) - { - printf("--mrom_dir=[path to multirom's data dir] needs to be specified!\n"); - fflush(stdout); - return 1; - } - - mrom_set_dir(mrom_dir); - mrom_set_log_tag("trampoline_inject"); - return inject_bootimg(inject_path, force_inject); - } - - umask(000); - - // Init only the little we need, leave the rest for real init - mkdir("/dev", 0755); - mkdir("/dev/pts", 0755); - mkdir("/dev/socket", 0755); - mkdir("/proc", 0755); - mkdir("/sys", 0755); - - mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); - mount("devpts", "/dev/pts", "devpts", 0, NULL); - mount("proc", "/proc", "proc", 0, NULL); - mount("sysfs", "/sys", "sysfs", 0, NULL); - mount("pstore", "/sys/fs/pstore", "pstore", 0, NULL); - -#if MR_USE_DEBUGFS_MOUNT - // Mount the debugfs kernel sysfs - mkdir("/sys/kernel/debug", 0755); - mount("debugfs", "/sys/kernel/debug", "debugfs", 0, NULL); -#endif - - klog_init(); - // output all messages to dmesg, - // but it is possible to filter out INFO messages - klog_set_level(6); - - mrom_set_log_tag("trampoline"); - INFO("Running trampoline v%d\n", VERSION_TRAMPOLINE); - - if(is_charger_mode()) - { - INFO("Charger mode detected, skipping multirom\n"); - goto run_main_init; - } - -#if MR_DEVICE_HOOKS >= 3 - tramp_hook_before_device_init(); -#endif - - INFO("Initializing devices...\n"); - devices_init(); - INFO("Done initializing\n"); - - if(wait_for_file("/dev/graphics/fb0", 5) < 0) - { - ERROR("Waiting too long for fb0"); - goto exit; - } - -#ifdef MR_POPULATE_BY_NAME_PATH - //nkk71 M7 hack - Populate_ByName_using_emmc(); -#endif - - fstab = fstab_auto_load(); - if(!fstab) - goto exit; - -#if 0 - fstab_dump(fstab); //debug -#endif - - // mount and run multirom from sdcard - if(mount_and_run(fstab) < 0 && mrom_is_second_boot()) - { - ERROR("This is second boot and we couldn't mount /data, reboot!\n"); - sync(); - //android_reboot(ANDROID_RB_RESTART, 0, 0); - android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); // favour reboot to recovery, to avoid possible bootlooping - while(1) - sleep(1); - } - -exit: - if(fstab) - fstab_destroy(fstab); - - // close and destroy everything - devices_close(); - -run_main_init: - umount("/dev/pts"); - rmdir("/dev/pts"); - rmdir("/dev/socket"); - - if(access(KEEP_REALDATA, F_OK) < 0) - { - umount(REALDATA); - umount("/dev"); - rmdir(REALDATA); - encryption_destroy(); - } - - encryption_cleanup(); - -#if MR_USE_DEBUGFS_MOUNT - umount("/sys/kernel/debug"); -#endif - - umount("/proc"); - umount("/sys/fs/pstore"); - umount("/sys"); - - INFO("Running main_init\n"); - - fixup_symlinks(); - - chmod("/main_init", EXEC_MASK); - rename("/main_init", "/init"); - - res = execve(cmd[0], cmd, NULL); - ERROR("execve returned %d %d %s\n", res, errno, strerror(errno)); - return 0; -} diff --git a/trampoline/trampoline.cpp b/trampoline/trampoline.cpp new file mode 100644 index 00000000..c95be0c1 --- /dev/null +++ b/trampoline/trampoline.cpp @@ -0,0 +1,774 @@ +/* + * This file is part of MultiROM. + * + * MultiROM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MultiROM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MultiROM. If not, see . + */ + +extern "C" { +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" +#include "../lib/log.h" +#include "../lib/util.h" +#include "../lib/fstab.h" +#include "../lib/inject.h" +#include "../version.h" +#include "adb.h" +#include "../hooks.h" +#include "encryption.h" +#include "../no_kexec.h" + +#ifdef MR_POPULATE_BY_NAME_PATH + #include "Populate_ByName_using_emmc.c" +#endif + +#include "trampoline.h" +} + +#include +#include +#include + +static char path_multirom[64] = { 0 }; + +int fork_and_exec_with_stdout(char *cmd, char *const *envp) +{ + int fd[2]; + int exit_code = -1; + char* command[] = {cmd, NULL}; + if(pipe2(fd, O_CLOEXEC) < 0) + return -1; + + pid_t pid = fork(); + if (pid < 0) + { + close(fd[0]); + close(fd[1]); + return pid; + } + + if(pid == 0) // child + { + close(fd[0]); + dup2(fd[1], 1); // send stdout to the pipe + dup2(fd[1], 2); // send stderr to the pipe + close(fd[1]); + + if (execve(command[0], command, envp) == -1) { + ERROR("execve failed %s\n", strerror(errno)); + } + _exit(127); + } + else + { + close(fd[1]); + + char *res = (char*)malloc(512); + char buffer[512]; + int size = 512, written = 0, len; + while ((len = read(fd[0], buffer, sizeof(buffer))) > 0) + { + if(written + len + 1 > size) + { + size = written + len + 256; + res = (char*)realloc(res, size); + } + memcpy(res+written, buffer, len); + written += len; + } + res[written] = 0; + + close(fd[0]); + + waitpid(pid, &exit_code, 0); + ERROR("%s\n", res); + + if(written == 0) + { + free(res); + return pid; + } + return pid; + } + return pid; +} + +static int fork_and_exec_with_strace(char *cmd, char** env) +{ + pid_t pID = fork(); + if(pID == 0) + { + char* args[] = {"/mrom_enc/strace", "-o", NULL, "-f", NULL, NULL}; + char strace_arg1[100]; + sprintf(strace_arg1, "strace-%s", (cmd + 10)); + args[2] = strace_arg1; + args[4] = cmd; + INFO("running %s %s %s %s %s\n", args[0], args[1], args[2], args[3], args[4]); + stdio_to_null(); + setpgid(0, getpid()); + execve(args[0], args, env); + ERROR("Failed to exec %s: %s\n", args[0], strerror(errno)); + _exit(127); + } + return pID; +} + +static int find_multirom(void) +{ + int i; + struct stat info; + + static const char *paths[] = { + REALDATA"/media/0/MultiROM/multirom", + REALDATA"/media/MultiROM/multirom", + REALDATA"/media/0/multirom", // 4.2 + REALDATA"/media/multirom", + NULL, + }; + + for(i = 0; paths[i]; ++i) { + if(stat(paths[i], &info) < 0) + continue; + + strcpy(path_multirom, paths[i]); + + if (i < 2) { + // Make sure to set the container dir to immutable + char main_path[64]; + strncpy(main_path, path_multirom, strlen(path_multirom) - (sizeof("/multirom") - 1)); + main_path[strlen(path_multirom) - (sizeof("/multirom") - 1)] = '\0'; + + int fd = open(main_path, O_RDONLY | O_NONBLOCK); + if (fd >= 0) { + long flags; + if (ioctl(fd, FS_IOC_GETFLAGS, &flags) >= 0) { + flags |= FS_IMMUTABLE_FL; + if (ioctl(fd, FS_IOC_SETFLAGS, &flags) < 0) + ERROR("Failed FS_IOC_SETFLAGS: %s!\n", strerror(errno)); + else + INFO("Set FS_IMMUTABLE_FL on %s.\n", main_path); + } + else + ERROR("Failed FS_IOC_GETFLAGS: %s!\n", strerror(errno)); + close(fd); + } + else + ERROR("Failed to open %s: %s!\n", main_path, strerror(errno)); + } + return 0; + } + return -1; +} + +static void run_multirom(int isFbe) +{ + char path[256]; + struct stat info; + + // busybox + sprintf(path, "%s/%s", path_multirom, BUSYBOX_BIN); + if (stat(path, &info) < 0) + { + ERROR("Could not find busybox: %s\n", path); + return; + } + chmod(path, EXEC_MASK); + + // restart after crash + sprintf(path, "%s/restart_after_crash", path_multirom); + int restart = (stat(path, &info) >= 0); + + // multirom + sprintf(path, "%s/%s", path_multirom, MULTIROM_BIN); + if (stat(path, &info) < 0) + { + ERROR("Could not find multirom: %s\n", path); + return; + } + chmod(path, EXEC_MASK); + + const char *cmd[] = { path, isFbe ? "alwaysreboot" : NULL, NULL }; + do + { + ERROR("Running multirom\n"); + int res = run_cmd((char**)cmd); + if(res == 0) + break; + else + ERROR("MultiROM exited with status code %d!\n", res); + } + while(restart); +} + +static int try_mount_all_entries(struct fstab *fstab, struct fstab_part *first_data_p) +{ + size_t i; + struct fstab_part *p_itr = first_data_p; + + do + { + // Remove nosuid flag, because secondary ROMs have + // su binaries on /data + p_itr->mountflags &= ~(MS_NOSUID); + + if(mount(p_itr->device, REALDATA, p_itr->type, p_itr->mountflags, p_itr->options) >= 0) { + struct stat info; + if(stat("/realdata/unencrypted/key/version", &info) < 0) { + return 0; + } else { + if (!mrom_is_second_boot() && stat("/realdata/media/MultiROM/multirom", &info) >= 0) { + INFO("Multirom found"); + return 0; + } else { + INFO("File system is FBE encrypted"); + return -2; + } + } + } + } + while((p_itr = fstab_find_next_by_path(fstab, "/data", p_itr))); + + ERROR("Failed to mount /realdata with data from fstab, trying all filesystems\n"); + + const char *fs_types[] = { "ext4", "f2fs", "ext3", "ext2" }; + const char *fs_opts [] = { + "barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc,errors=panic", // ext4 + "inline_xattr,flush_merge", // f2fs + "", // ext3 + "" // ext2 + }; + + for(i = 0; i < ARRAY_SIZE(fs_types); ++i) + { + if(mount(first_data_p->device, REALDATA, fs_types[i], first_data_p->mountflags, fs_opts[i]) >= 0) + { + INFO("/realdata successfuly mounted with fs %s\n", fs_types[i]); + struct stat info; + if(stat("/realdata/unencrypted/key/version", &info) < 0) { + return 0; + } else { + if (!mrom_is_second_boot() && stat("/realdata/media/MultiROM/multirom", &info) >= 0) { + INFO("Multirom found"); + return 0; + } else { + INFO("File system is FBE encrypted\n"); + return -2; + } + } + return 0; + } + } + + return -1; +} + +static int mount_and_run(struct fstab *fstab) +{ + struct fstab_part *datap = fstab_find_first_by_path(fstab, "/data"); + if(!datap) + { + ERROR("Failed to find /data partition in fstab\n"); + return -1; + } + + if(access(datap->device, R_OK) < 0) + { + INFO("Waiting for %s because error %s\n", datap->device, strerror(errno)); + if(wait_for_file(datap->device, 5) < 0) + { + ERROR("Waiting too long for dev %s\n", datap->device); + return -1; + } + } + + mkdir(REALDATA, 0755); + mkdir("/data", 0755); + + int ret = try_mount_all_entries(fstab, datap); + if(ret < 0) + { +#ifndef MR_ENCRYPTION + ERROR("Failed to mount /data with all possible filesystems!\n"); + return -1; +#else + INFO("Failed to mount /realdata, trying encryption...\n"); + switch(encryption_before_mount(fstab, ret == -2)) + { + case ENC_RES_ERR: + ERROR("/data decryption failed!\n"); + return -1; + case ENC_RES_BOOT_INTERNAL: + return 0; + case ENC_RES_BOOT_RECOVERY: + sync(); + do_reboot(REBOOT_RECOVERY); // REBOOT_RECOVERY + while (1) + sleep(1); + // we're never returning + return 0; + default: + case ENC_RES_OK: + { + if(ret != -2 && try_mount_all_entries(fstab, datap) < 0) + { + ERROR("Failed to mount decrypted /data with all possible filesystems!\n"); + return -1; + } + break; + } + } +#endif + } + + if (ret == -2 && !nokexec_is_skip_mr() || ret != -2) { + INFO("skip mr flag false.. running multirom"); + if(find_multirom() == -1) + { + ERROR("Could not find multirom folder!\n"); + return -1; + } + + adb_init(path_multirom); + run_multirom(ret == -2); + adb_quit(); + } + return 0; +} + +static int is_charger_mode(void) +{ + char buff[2048] = { 0 }; + int charger_mode = 0; + + FILE *f = fopen("/proc/cmdline", "re"); + if(!f) + return 0; + + while (fgets(buff, sizeof(buff), f) != NULL) + { + if (strstr(buff, "androidboot.mode=charger") != NULL) + { + charger_mode = 1; + break; + } + } + + fclose(f); + + return charger_mode; +} + +static void fixup_symlinks(void) +{ + static const char *init_links[] = { "/sbin/ueventd", "/sbin/watchdogd" }; + + size_t i; + ssize_t len; + char buff[64]; + struct stat info; + + for(i = 0; i < ARRAY_SIZE(init_links); ++i) + { + if(lstat(init_links[i], &info) < 0 || !S_ISLNK(info.st_mode)) + continue; + + if (info.st_size < sizeof(buff)-1) + { + len = readlink(init_links[i], buff, sizeof(buff)-1); + if(len >= 0) + { + buff[len] = 0; + // if the symlink already points to ../init, skip it. + if(strcmp(buff, "../init") == 0) + continue; + } + } + + ERROR("Fixing up symlink '%s' -> '%s' to '%s' -> '../init')\n", init_links[i], buff, init_links[i]); + unlink(init_links[i]); + symlink("../init", init_links[i]); + } +} + +static void switch_root(const char* path) { + INFO("Switch root to %s\n", path); + FILE *fp = setmntent("/proc/mounts", "re"); + if (fp) { + struct mntent mentry; + char buf[4096]; + std::vector v; + bool add = true; + while (getmntent_r(fp, &mentry, buf, sizeof(buf))) { + if (!strcmp(mentry.mnt_dir, "/") || !strcmp(mentry.mnt_dir, path)) { + INFO("skip %s\n", mentry.mnt_dir); + continue; + } + + for (auto i : v) { + if (!strcmp(mentry.mnt_dir, i.data())) { + INFO("%s %s %d not adding to vector\n", mentry.mnt_dir, i.data(), i.length()); + add = false; + break; + } else { + add = true; + } + } + + if (add) { + v.emplace_back(mentry.mnt_dir); + INFO("%s added to vector\n", mentry.mnt_dir); + } else { + INFO("%s not added to vector\n", mentry.mnt_dir); + } + } + endmntent(fp); + + for (auto i : v) { + char* new_path = NULL; + asprintf(&new_path, "%s%s", path, i.data()); + INFO("move mount point %s to %s\n", i.data(), new_path); + mkdir(new_path, 0755); + mount(i.data(), new_path, NULL, MS_MOVE, NULL); + } + } +} + +static int do_cmdline(int argc, char *argv[]) +{ + int i; + char *inject_path = NULL; + char *mrom_dir = NULL; + int force_inject = 0; + + if (argc > 1 && !strcmp(argv[1], "selinux_setup")) { + INFO("multirom second stage init\n"); + //remove_dir("/system"); + switch_root("/system_root"); + int error = chdir("/system_root"); + if (error == -1) { + INFO("chdir failed!!: %s\n", strerror(errno)); + } else { + INFO("chdir returned %d\n", error); + } + error = mount("/system_root", "/", NULL, MS_MOVE, NULL); + if (error == -1) { + INFO("mount failed!!: %s\n", strerror(errno)); + } else { + INFO("mount returned %d\n", error); + } + error = chroot("."); + if (error == -1) { + INFO("chroot failed!!: %s\n", strerror(errno)); + } else { + INFO("chroot returned %d\n", error); + } + struct stat info; + if(stat("/system/etc/selinux", &info) < 0) { + INFO("/system/etc/selinux does not exist!\n"); + } else { + INFO("/system/etc/selinux exists\n"); + } + if (stat("/vendor/etc/selinux", &info) < 0) { + INFO("/vendor/etc/selinux does not exist!\n"); + } else { + INFO("/vendor/etc/selinux exists\n"); + } + int res; + static char *const cmd[] = { "/init", "selinux_setup", NULL }; + res = execv(cmd[0], cmd); + return 0; + } + + + for(i = 1; i < argc; ++i) + { + if(strcmp(argv[i], "-v") == 0) + { + printf("%d\n", VERSION_TRAMPOLINE); + fflush(stdout); + return 0; + } + else if(strstartswith(argv[i], "--inject=")) + inject_path = argv[i] + strlen("--inject="); + else if(strstartswith(argv[i], "--mrom_dir=")) + mrom_dir = argv[i] + strlen("--mrom_dir="); + else if(strcmp(argv[i], "-f") == 0) + force_inject = 1; + } + + if(inject_path) + { + if(!mrom_dir) + { + printf("--mrom_dir=[path to multirom's data dir] needs to be specified!\n"); + fflush(stdout); + return 1; + } + + mrom_set_dir(mrom_dir); + mrom_set_log_tag("trampoline_inject"); + return inject_bootimg(inject_path, force_inject); + } + + printf("Usage: trampoline -v\n"); + printf(" trampoline --inject= --mrom_dir= [-f]\n"); + return 1; +} + +static int run_core(void) +{ + int res = -1; + struct fstab *fstab = NULL; + +#ifndef MR_DEVICE_HAS_DRM_GRAPHICS + if(wait_for_file("/dev/graphics/fb0", 5) < 0) + { + ERROR("Waiting too long for fb0"); + goto exit; + } +#endif + +#ifdef MR_POPULATE_BY_NAME_PATH + Populate_ByName_using_emmc(); +#endif + + fstab = fstab_auto_load(); + if(!fstab) + goto exit; + +#if 0 + fstab_dump(fstab); //debug +#endif + + // mount and run multirom from sdcard + res = mount_and_run(fstab); + if(res < 0 && mrom_is_second_boot()) + { + ERROR("This is second boot and we couldn't mount /data, reboot!\n"); + sync(); + //android_reboot(ANDROID_RB_RESTART, 0, 0); + do_reboot(REBOOT_RECOVERY); // favour reboot to recovery, to avoid possible bootlooping + while(1) + sleep(1); + } + + if(access(KEEP_REALDATA, F_OK) < 0) { + umount(REALDATA); + rmdir(REALDATA); + encryption_destroy(); + } + + encryption_cleanup(); + +exit: + if(fstab) + fstab_destroy(fstab); + + return res; +} + +char *trampoline_get_klog(void) +{ + int len = klogctl(10, NULL, 0); + if (len < 16*1024) len = 16*1024; + else if (len > 16*1024*1024) len = 16*1024*1024; + + char *buff = (char*)malloc(len + 1); + len = klogctl(3, buff, len); + if(len <= 0) + { + ERROR("Could not get klog!\n"); + free(buff); + return NULL; + } + buff[len] = 0; + return buff; +} + +int trampoline_copy_log(char *klog, const char *dest_path_relative) +{ + int res = 0; + int freeLog = (klog == NULL); + + if(!klog) + klog = trampoline_get_klog(); + + if(klog) + { + char path[256]; + snprintf(path, sizeof(path), "%s", dest_path_relative); + FILE *f = fopen(path, "we"); + + if(f) + { + fwrite(klog, 1, strlen(klog), f); + fclose(f); + chmod(path, 0777); + } + else + { + ERROR("Failed to open %s!\n", path); + res = -1; + } + } + else + { + ERROR("Could not get klog!\n"); + res = -1; + } + + if(freeLog) + free(klog); + return res; +} + +void klog_periodic(void* ptr) { + while(1) { + usleep(2000000); + trampoline_copy_log(NULL, "/data/last_kmsg"); + } +} + +int main(int argc, char *argv[]) +{ + if (argc > 1) + return do_cmdline(argc, argv); + + int res; + static char *const cmd[] = { "/init", NULL }; + + umask(000); + + // Init only the little we need, leave the rest for real init + mkdir("/dev", 0755); + mkdir("/dev/pts", 0755); + mkdir("/dev/socket", 0755); + mkdir("/proc", 0755); + mkdir("/sys", 0755); + mkdir("/tmp", 0755); + + mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); + mount("devpts", "/dev/pts", "devpts", 0, NULL); + mount("proc", "/proc", "proc", 0, NULL); + mount("sysfs", "/sys", "sysfs", 0, NULL); + mount("pstore", "/sys/fs/pstore", "pstore", 0, NULL); + mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL); + +#if MR_USE_DEBUGFS_MOUNT + // Mount the debugfs kernel sysfs + mkdir("/sys/kernel/debug", 0755); + mount("debugfs", "/sys/kernel/debug", "debugfs", 0, NULL); +#endif + + // output all messages to dmesg, + // but it is possible to filter out INFO messages + klog_set_level(6); + + mrom_set_log_tag("trampoline"); + INFO("Running trampoline v%d\n", VERSION_TRAMPOLINE); + + if(is_charger_mode()) + { + INFO("Charger mode detected, skipping multirom\n"); + goto run_main_init; + } + +#if MR_DEVICE_HOOKS >= 3 + tramp_hook_before_device_init(); +#endif + + INFO("Initializing devices...\n"); + devices_init(); + INFO("Done initializing\n"); + + if (nokexec_is_skip_mr()) { + INFO("skip mr flag true.. setting it to false for next boot\n"); + nokexec_unset_skip_mr_flag(); + } else { + run_core(); + } + + // close and destroy everything + devices_close(); + +run_main_init: + umount("/dev/pts"); + rmdir("/dev/pts"); + rmdir("/dev/socket"); + rmdir("/tmp"); + + if(access(KEEP_REALDATA, F_OK) < 0) { + umount("/dev"); + } + +#if MR_USE_DEBUGFS_MOUNT + umount("/sys/kernel/debug"); +#endif + + if (access("/fakefsbat/", F_OK)) { + DIR* dir = opendir("/proc/device-tree/firmware/android"); + copy_dir_contents(dir, "/proc/device-tree/firmware/android", "/fakefsbat", NULL); + //remove("/fakefstab/fstab/system/mnt_point"); + closedir(dir); + //remove("/fakefstab/fstab/vendor/mnt_point"); + } + umount("/proc"); + umount("/sys/fs/pstore"); + umount("/sys/fs/selinux"); + if(umount("/sys")) { + ERROR("sysfs unmount failed :%s\n", strerror(errno)); + } + + INFO("Running main_init\n"); + + fixup_symlinks(); + + //INFO("%s\n", read_file("strace-qseecomd")); + + char* context = (char*)calloc(1, 50); + getfilecon("/main_init", &context); + INFO("context of main_init is %s", context); + chmod("/main_init", EXEC_MASK); + rename("/main_init", "/init"); + getfilecon("/init", &context); + INFO("context of init is %s", context); + + //setexeccon("u:object_r:kernel:s0"); + + //trampoline_copy_log(NULL, "/data/last_kmsg"); + res = execve(cmd[0], cmd, NULL); + //trampoline_copy_log(NULL, "/data/last_kmsg"); + ERROR("execve returned %d %d %s\n", res, errno, strerror(errno)); + return 0; +} diff --git a/trampoline/trampoline.h b/trampoline/trampoline.h new file mode 100644 index 00000000..ed007e2d --- /dev/null +++ b/trampoline/trampoline.h @@ -0,0 +1,34 @@ +/* + * This file is part of MultiROM. + * + * MultiROM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MultiROM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MultiROM. If not, see . + */ + +#ifndef _TRAMPOLINE_H +#define _TRAMPOLINE_H + +#include + +#define EXEC_MASK (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +#define REALDATA "/realdata" +#define MULTIROM_BIN "multirom" +#define BUSYBOX_BIN "busybox" +#define KEEP_REALDATA "/dev/.keep_realdata" + +// Not defined in android includes? +#ifndef MS_RELATIME +#define MS_RELATIME (1<<21) +#endif + +#endif // _TRAMPOLINE_H diff --git a/trampoline_encmnt/Android.mk b/trampoline_encmnt/Android.mk index 21f22717..4cfecc75 100644 --- a/trampoline_encmnt/Android.mk +++ b/trampoline_encmnt/Android.mk @@ -2,11 +2,17 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= trampoline_encmnt -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) -LOCAL_SHARED_LIBRARIES := libcryptfslollipop libcutils -LOCAL_STATIC_LIBRARIES := libmultirom_static +LOCAL_SHARED_LIBRARIES := libcryptfslollipop libcutils libe4crypt libwifikeystorehal libsoftkeymasterdevice android.system.wifi.keystore@1.0 +LOCAL_STATIC_LIBRARIES := libmultirom_static libext4_utils + +LOCAL_ADDITIONAL_DEPENDENCIES += libstdc++ + +ifeq ($(TARGET_HW_DISK_ENCRYPTION),true) + LOCAL_ADDITIONAL_DEPENDENCIES += libcryptfs_hw +endif MR_NO_KEXEC_MK_OPTIONS := true 1 allowed 2 enabled 3 ui_confirm 4 ui_choice 5 forced ifneq (,$(filter $(MR_NO_KEXEC), $(MR_NO_KEXEC_MK_OPTIONS))) @@ -23,12 +29,15 @@ else $(error Failed to find path to TWRP, which is required to build MultiROM with encryption support) endif -LOCAL_C_INCLUDES += $(multirom_local_path) $(mr_twrp_path) $(mr_twrp_path)/crypto/scrypt/lib/crypto external/openssl/include external/boringssl/include +LOCAL_C_INCLUDES += $(multirom_local_path) $(mr_twrp_path) $(mr_twrp_path)/crypto/scrypt/lib/crypto $(mr_twrp_path)/crypto/ext4crypt external/openssl/include external/boringssl/include +LOCAL_C_INCLUDES += system/extras/libbootimg/include +LOCAL_C_INCLUDES += system/extras/ext4_utils/include/ext4_utils LOCAL_SRC_FILES := \ - encmnt.c \ - pw_ui.c \ + encmnt.cpp \ + pw_ui.cpp \ ../rom_quirks.c \ + ../rq_inject_file_contexts.c \ include $(multirom_local_path)/device_defines.mk @@ -39,10 +48,12 @@ ifeq ($(MR_ENCRYPTION_FAKE_PROPERTIES),true) include $(CLEAR_VARS) LOCAL_MODULE := libmultirom_fake_properties - LOCAL_MODULE_TAGS := eng + LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES += $(multirom_local_path) + LOCAL_C_INCLUDES += system/extras/libbootimg/include LOCAL_SRC_FILES := fake_properties.c + LOCAL_SHARED_LIBRARIES := liblog ifneq ($(MR_ENCRYPTION_FAKE_PROPERTIES_EXTRAS),) LOCAL_CFLAGS += -DMR_ENCRYPTION_FAKE_PROPERTIES_EXTRAS @@ -52,4 +63,16 @@ ifeq ($(MR_ENCRYPTION_FAKE_PROPERTIES),true) include $(multirom_local_path)/device_defines.mk include $(BUILD_SHARED_LIBRARY) + + include $(CLEAR_VARS) + + LOCAL_MODULE := libmultirom_fake_propertywait + LOCAL_MODULE_TAGS := optional + LOCAL_C_INCLUDES += $(multirom_local_path) + + LOCAL_SRC_FILES := property_wait.cpp + + include $(multirom_local_path)/device_defines.mk + + include $(BUILD_SHARED_LIBRARY) endif diff --git a/trampoline_encmnt/encmnt.c b/trampoline_encmnt/encmnt.cpp similarity index 61% rename from trampoline_encmnt/encmnt.c rename to trampoline_encmnt/encmnt.cpp index d841afea..f0bbc852 100644 --- a/trampoline_encmnt/encmnt.c +++ b/trampoline_encmnt/encmnt.cpp @@ -22,20 +22,24 @@ #include #include +extern "C" { #include "../lib/log.h" #include "../lib/fstab.h" #include "../lib/framebuffer.h" #include "../lib/util.h" +} #include "crypto/lollipop/cryptfs.h" +#include "crypto/ext4crypt/Decrypt.h" #include "pw_ui.h" #include "encmnt_defines.h" #define CMD_NONE 0 #define CMD_DECRYPT 1 -#define CMD_REMOVE 2 -#define CMD_PWTYPE 3 +#define CMD_DECRYPTFBE 2 +#define CMD_REMOVE 3 +#define CMD_PWTYPE 4 #define FSTAB_FLAGS "flags=" @@ -113,7 +117,65 @@ static int handle_pwtype(int stdout_fd) return 0; } -static int handle_decrypt(int stdout_fd, const char *password) +static int handle_decryptfbe(int stdout_fd, char *password) +{ + int retry_count = 3; + static const char *default_password = "!"; + int pwtype = -1; + //property_set("ro.crypto.state", "encrypted"); + //property_set("ro.crypto.type", "file"); + //INFO("return %d\n", ret); + while (!Decrypt_DE() && --retry_count) + usleep(2000); + if (retry_count > 0) { + std::string filename; + pwtype = Get_Password_Type(0, filename); + ERROR("Password type is %d %s\n", pwtype, filename.c_str()); + if (pwtype < 0) { + ERROR("This TWRP does not have synthetic password decrypt support\n"); + pwtype = 0; // default password + } + } + + if(pwtype < 0) + { + ERROR("get_password_type failed!"); + return -1; + } + else if (pwtype == CRYPT_TYPE_DEFAULT) + password = (char*)default_password; + + if (password) { + if (Decrypt_User(0, password)) { + return 0; + } + } else + { + switch(pw_ui_run(pwtype, true)) + { + default: + case ENCMNT_UIRES_ERROR: + ERROR("pw_ui_run() failed!\n"); + return -1; + case ENCMNT_UIRES_BOOT_INTERNAL: + INFO("Wants to boot internal!\n"); + write(stdout_fd, ENCMNT_BOOT_INTERNAL_OUTPUT, strlen(ENCMNT_BOOT_INTERNAL_OUTPUT)); + fsync(stdout_fd); + return 0; + case ENCMNT_UIRES_BOOT_RECOVERY: + INFO("Wants to boot recoveryl!\n"); + write(stdout_fd, ENCMNT_BOOT_RECOVERY_OUTPUT, strlen(ENCMNT_BOOT_RECOVERY_OUTPUT)); + fsync(stdout_fd); + return 0; + case ENCMNT_UIRES_PASS_OK: + return 0; + } + } + + return -1; +} + +static int handle_decrypt(int stdout_fd, char *password) { DIR *d; struct dirent *de; @@ -134,7 +196,7 @@ static int handle_decrypt(int stdout_fd, const char *password) return -1; } else if (pwtype == CRYPT_TYPE_DEFAULT) - password = default_password; + password = (char*)default_password; if(password) { @@ -146,7 +208,7 @@ static int handle_decrypt(int stdout_fd, const char *password) } else { - switch(pw_ui_run(pwtype)) + switch(pw_ui_run(pwtype, false)) { default: case ENCMNT_UIRES_ERROR: @@ -167,6 +229,7 @@ static int handle_decrypt(int stdout_fd, const char *password) } } + INFO("open block device\n"); d = opendir("/dev/block/"); if(!d) { @@ -174,19 +237,33 @@ static int handle_decrypt(int stdout_fd, const char *password) return -1; } + INFO("finding block device\n"); + if (access("/dev/block/dm-0", R_OK)) { + INFO("/dev/block/dm-0 nhi hai\n"); + } else { + INFO("/dev/block/dm-0 hai\n"); + } // find the block device while((de = readdir(d))) { - if(de->d_type == DT_BLK && strncmp(de->d_name, "dm-", 3) == 0) + INFO("finding block device %d %s\n", de->d_type, de->d_name); + if(de->d_type == DT_BLK && !strncmp(de->d_name, "dm-", 3)) { snprintf(buff, sizeof(buff), "/dev/block/%s\n", de->d_name); INFO("Found block device %s\n", buff); + char temp[512]; + read(stdout_fd, temp, 512); + INFO("ye tha stdout me %s\n", temp); write(stdout_fd, buff, strlen(buff)); fsync(stdout_fd); res = 0; break; } } + /*snprintf(buff, sizeof(buff), "/dev/block/dm-0\n"); + write(stdout_fd, buff, strlen(buff)); + fsync(stdout_fd); + res = 0;*/ closedir(d); return res; @@ -214,8 +291,6 @@ int main(int argc, char *argv[]) struct fstab_part *p; char *argument = NULL; - klog_init(); - // output all messages to dmesg, // but it is possible to filter out INFO messages klog_set_level(6); @@ -232,7 +307,9 @@ int main(int argc, char *argv[]) } else if(cmd == CMD_NONE) { - if(strcmp(argv[i], "decrypt") == 0) + if(strcmp(argv[i], "decryptfbe") == 0) + cmd = CMD_DECRYPTFBE; + else if(strcmp(argv[i], "decrypt") == 0) cmd = CMD_DECRYPT; else if(strcmp(argv[i], "remove") == 0) cmd = CMD_REMOVE; @@ -251,40 +328,44 @@ int main(int argc, char *argv[]) return 0; } - fstab = fstab_auto_load(); - if(!fstab) - { - ERROR("Failed to load fstab!"); - return 1; - } + if (cmd == CMD_DECRYPT) { + fstab = fstab_auto_load(); + if(!fstab) + { + ERROR("Failed to load fstab!"); + return 1; + } - p = fstab_find_first_by_path(fstab, "/data"); - if(!p) - { - ERROR("Failed to find /data partition in fstab\n"); - goto exit; - } + p = fstab_find_first_by_path(fstab, "/data"); + if(!p) + { + ERROR("Failed to find /data partition in fstab\n"); + goto exit; + } - found_footer_location = 0; + found_footer_location = 0; - if(p->options) - found_footer_location = get_footer_from_opts(footer_location, sizeof(footer_location), p->options) == 0; + if(p->options) + found_footer_location = get_footer_from_opts(footer_location, sizeof(footer_location), p->options) == 0; - if(!found_footer_location && p->options2) - found_footer_location = get_footer_from_opts(footer_location, sizeof(footer_location), p->options2) == 0; + if(!found_footer_location && p->options2) + found_footer_location = get_footer_from_opts(footer_location, sizeof(footer_location), p->options2) == 0; - if(!found_footer_location) - { - ERROR("Failed to find footer location\n"); - goto exit; - } + if(!found_footer_location) + { + ERROR("Failed to find footer location\n"); + goto exit; + } - INFO("Setting encrypted partition data to %s %s %s\n", p->device, footer_location, p->type); - set_partition_data(p->device, footer_location, p->type); + INFO("Setting encrypted partition data to %s %s %s\n", p->device, footer_location, p->type); + set_partition_data(p->device, footer_location, p->type); - // cryptfs prints informations, we don't want that + fstab_destroy(fstab); + } + //cryptfs prints informations, we don't want that stdout_fd = dup(1); freopen("/dev/null", "ae", stdout); + freopen("/dev/null", "ae", stderr); switch(cmd) { @@ -296,6 +377,10 @@ int main(int argc, char *argv[]) if(handle_decrypt(stdout_fd, argument) < 0) goto exit; break; + case CMD_DECRYPTFBE: + if(handle_decryptfbe(stdout_fd, argument) < 0) + goto exit; + break; case CMD_REMOVE: if(handle_remove() < 0) goto exit; @@ -304,6 +389,5 @@ int main(int argc, char *argv[]) res = 0; exit: - fstab_destroy(fstab); return res; } diff --git a/trampoline_encmnt/fake_properties.c b/trampoline_encmnt/fake_properties.c index 1ea8f0a9..52c324bb 100644 --- a/trampoline_encmnt/fake_properties.c +++ b/trampoline_encmnt/fake_properties.c @@ -17,7 +17,18 @@ #include #include #include +#include +#include +#include +#include +#include +//#include "log.h" +#include +#include +#define PROPERTY_SOCKET "/property_socket" +char* os_version = NULL; +char* os_level = NULL; /* MultiROM doesn't initialize the property service, * but decryption on Nexus 6P waits for one property to become true * so we hardcode it here @@ -32,13 +43,33 @@ int property_get(const char *key, char *value, const char *default_value) if (!strcmp(key, "sys.listeners.registered")) default_value = "true"; + /* For Keymaster 3 HAL, we need security patch and build version + * to match with the one in bootimg header. Pass the OS version + * and security patch version as environment variable OSVER and OSPATCH + * respectively to keymaster and qseecom (Make sure they LD_PRELOAD this lib) + * process after reading from bootimg in tramp_hook_encryption_setup() function */ + + if (!strcmp(key, "ro.build.version.release")) { + if (getenv("OSVER")) { + strcpy(value, getenv("OSVER")); + return strlen(value); + } + } + + if (!strcmp(key, "ro.build.version.security_patch")) { + if (getenv("OSPATCH")) { + strcpy(value, getenv("OSPATCH")); + return strlen(value); + } + } + #ifdef MR_ENCRYPTION_FAKE_PROPERTIES_EXTRAS int i; for(i = 0; mr_fake_properties[i][0]; ++i) { if (!strcmp(key, mr_fake_properties[i][0])) { - default_value = mr_fake_properties[i][1]; - break; + strncpy(value, mr_fake_properties[i][1], PROP_VALUE_MAX); + return strlen(value); } } #endif @@ -47,3 +78,99 @@ int property_get(const char *key, char *value, const char *default_value) strncpy(value, default_value, PROP_VALUE_MAX); return strlen(value); } + +void stdio_to_null(void) +{ + int fd = open("/dev/null", O_RDWR|O_CLOEXEC); + if(fd >= 0) + { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + } +} + +static int fork_and_exec(char *cmd, char** env, char** argv) +{ + pid_t pID = fork(); + if(pID == 0) + { + stdio_to_null(); + setpgid(0, getpid()); + if (strstr(cmd, "keystore_auth")) { + setuid(1000); + } else if (strstr(cmd, "keymaster") || strstr(cmd, "qsee")) { + } + setenv("LD_LIBRARY_PATH", "/mrom_enc", 1); + setenv("LD_PRELOAD", "/mrom_enc/libmultirom_fake_properties.so /mrom_enc/libmultirom_fake_propertywait.so", 1); + execve(cmd, argv, environ); + _exit(127); + } + return pID; +} + +int keystore_pid = -1; +int keystore_auth_pid; + +int property_set(char* property, char* value) { + + char* property_value; + int i, s, len; + struct sockaddr_un saun; + + char* env[] = {"LD_CONFIG_FILE=/mron_enc/ld.config.txt", "LD_LIBRARY_PATH=/mrom_enc", "LD_PRELOAD=/mrom_enc/libmultirom_fake_properties.so /mrom_enc/libmultirom_fake_propertywait.so /mrom_enc/libmultirom_fake_logger.so", NULL}; + if (property && value && strstr(property, "ctl.start") && !strcmp(value, "keystore")) { + char* args[] = {"keystore", "/tmp/misc/keystore", NULL}; + keystore_pid = fork_and_exec("/mrom_enc/keystore", env, args); + if (keystore_pid != -1) { + ALOGE("keystore running %d", keystore_pid); + } else { + ALOGE("keystore failed %d", keystore_pid); + } + return 0; + } + + if (property && value && strstr(property, "ctl.start") && !strcmp(value, "keystore_auth")) { + char* args[] = {"keystore_auth", NULL}; + keystore_auth_pid = fork_and_exec("/mrom_enc/keystore_auth", env, args); + } + + if (property && value && strstr(property, "ctl.stop") && !strcmp(value, "keystore")) { + if (keystore_pid != -1) + { + kill(-keystore_pid, SIGTERM); // kill the entire process group + waitpid(keystore_pid, NULL, 0); + } + return 0; + } + + ALOGE("property_set called for %s:%s\n", property, value); + property_value = calloc(strlen(property) + strlen(value) + 1, 1); + + sprintf(property_value, "%s:%s", property, value); + /* + * Get a socket to work with. This socket will + * be in the UNIX domain, and will be a + * datagram socket. + */ + if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + ALOGE("client: socket"); + } + + /* + * Create the address we will be connecting to. + */ + saun.sun_family = AF_UNIX; + strcpy(saun.sun_path, PROPERTY_SOCKET); + len = sizeof(saun.sun_family) + strlen(saun.sun_path); + + if (sendto(s, property_value, strlen(property_value), 0, &saun, sizeof(struct sockaddr_un)) < 0) { + ALOGE("sendto failed %s\n", strerror(errno)); + } + + free(property_value); + + close(s); + return 0; +} diff --git a/trampoline_encmnt/property_wait.cpp b/trampoline_encmnt/property_wait.cpp new file mode 100644 index 00000000..49304d2a --- /dev/null +++ b/trampoline_encmnt/property_wait.cpp @@ -0,0 +1,13 @@ +#include +#include + +namespace android { +namespace base { + + bool WaitForProperty(const std::string& key, const std::string& expected_value, + std::chrono::milliseconds relative_timeout) { + return true; + } + +} +} diff --git a/trampoline_encmnt/pw_ui.c b/trampoline_encmnt/pw_ui.cpp similarity index 86% rename from trampoline_encmnt/pw_ui.c rename to trampoline_encmnt/pw_ui.cpp index c67ef7c1..8c3c6547 100644 --- a/trampoline_encmnt/pw_ui.c +++ b/trampoline_encmnt/pw_ui.cpp @@ -23,6 +23,7 @@ #include "pw_ui.h" #include "encmnt_defines.h" +extern "C" { #include "../lib/framebuffer.h" #include "../lib/colors.h" #include "../lib/log.h" @@ -34,8 +35,10 @@ #include "../lib/workers.h" #include "../lib/containers.h" #include "../rom_quirks.h" +} #include "crypto/lollipop/cryptfs.h" +#include "crypto/ext4crypt/Decrypt.h" #define HEADER_HEIGHT (110*DPI_MUL) #define PWUI_DOT_R (15*DPI_MUL) @@ -51,6 +54,7 @@ struct pwui_type_pass_data { char *pass_buf; char *pass_buf_stars; size_t pass_buf_cap; + bool isFbe; }; struct pwui_type_pattern_data { @@ -61,6 +65,7 @@ struct pwui_type_pattern_data { int connected_dots[PWUI_DOTS_CNT]; size_t connected_dots_len; int touch_id; + bool isFbe; }; static pthread_mutex_t exit_code_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -78,7 +83,7 @@ static void boot_internal_clicked(UNUSED void *data) // We need to run quirks for primary ROM to prevent // restorecon breaking everything - rom_quirks_on_initrd_finalized(); + //rom_quirks_on_initrd_finalized(); pthread_mutex_lock(&exit_code_mutex); exit_code = ENCMNT_UIRES_BOOT_INTERNAL; @@ -105,20 +110,20 @@ static void boot_reboot_to_recovery(UNUSED void *data) static void fade_rect_alpha_step(void *data, float interpolated) { - fb_rect *r = data; + fb_rect *r = (fb_rect*)data; r->color = (((int)(0xFF*interpolated)) << 24); fb_request_draw(); } static void reveal_rect_alpha_step(void *data, float interpolated) { - fb_rect *r = data; + fb_rect *r = (fb_rect*)data; interpolated = 1.f - interpolated; r->color = (r->color & ~(0xFF << 24)) | (((int)(0xFF*interpolated)) << 24); fb_request_draw(); } -static int try_password(const char *pass) +static int try_password(char *pass, bool isFbe) { fb_text_set_content(invalid_pass_text, ""); @@ -127,7 +132,12 @@ static int try_password(const char *pass) ncard_set_text(b, "Verifying password..."); ncard_show(b, 1); - if(cryptfs_check_passwd(pass) != 0) + if (isFbe && Decrypt_User(0, pass) == false) { + ncard_hide(); + fb_text_set_content(invalid_pass_text, "Invalid password!"); + center_text(invalid_pass_text, 0, -1, fb_width, -1); + return -1; + } else if(!isFbe && cryptfs_check_passwd(pass) != 0) { ncard_hide(); fb_text_set_content(invalid_pass_text, "Invalid password!"); @@ -154,7 +164,7 @@ static int try_password(const char *pass) static void type_pass_key_pressed(void *data, uint8_t code) { - struct pwui_type_pass_data *d = data; + struct pwui_type_pass_data *d = (pwui_type_pass_data*)data; if(code < 128) { @@ -162,8 +172,8 @@ static void type_pass_key_pressed(void *data, uint8_t code) while(d->pass_buf_cap < pass_len + 2) { d->pass_buf_cap *= 2; - d->pass_buf = realloc(d->pass_buf, d->pass_buf_cap); - d->pass_buf_stars = realloc(d->pass_buf_stars, d->pass_buf_cap); + d->pass_buf = (char*)realloc(d->pass_buf, d->pass_buf_cap); + d->pass_buf_stars = (char*)realloc(d->pass_buf_stars, d->pass_buf_cap); } if(pass_len > 0) @@ -204,31 +214,32 @@ static void type_pass_key_pressed(void *data, uint8_t code) fb_request_draw(); break; case OSK_ENTER: - try_password(d->pass_buf); + try_password(d->pass_buf, d->isFbe); break; } } -static void type_pass_init(int pwtype) +static void type_pass_init(int pwtype, bool isFbe) { - struct pwui_type_pass_data *d = mzalloc(sizeof(struct pwui_type_pass_data)); + struct pwui_type_pass_data *d = (pwui_type_pass_data*)mzalloc(sizeof(struct pwui_type_pass_data)); d->keyboard = keyboard_create(pwtype == CRYPT_TYPE_PIN ? KEYBOARD_PIN : KEYBOARD_NORMAL, 0, fb_height*0.65, fb_width, fb_height*0.35); + d->isFbe = isFbe; keyboard_set_callback(d->keyboard, type_pass_key_pressed, d); d->passwd_text = fb_add_text(0, 0, C_TEXT, SIZE_BIG, ""); center_text(d->passwd_text, 0, 0, fb_width, fb_height); d->pass_buf_cap = 12; - d->pass_buf = mzalloc(d->pass_buf_cap); - d->pass_buf_stars = mzalloc(d->pass_buf_cap); + d->pass_buf = (char*)mzalloc(d->pass_buf_cap); + d->pass_buf_stars = (char*)mzalloc(d->pass_buf_cap); pwui_type_data = d; } static void type_pass_destroy(void) { - struct pwui_type_pass_data *d = pwui_type_data; + struct pwui_type_pass_data *d = (pwui_type_pass_data*)pwui_type_data; keyboard_destroy(d->keyboard); free(d->pass_buf); @@ -276,7 +287,7 @@ static inline void type_pattern_connect_dot(struct pwui_type_pattern_data *d, i static int type_pattern_touch_handler(touch_event *ev, void *data) { - struct pwui_type_pattern_data *d = data; + struct pwui_type_pattern_data *d = (pwui_type_pattern_data*)data; if(d->touch_id == -1 && (ev->changed & TCHNG_ADDED) && !ev->consumed) { @@ -343,16 +354,16 @@ static int type_pattern_touch_handler(touch_event *ev, void *data) d->cur_line = NULL; fb_request_draw(); - char *passwd = malloc(d->connected_dots_len+1); + char *passwd = (char*)malloc(d->connected_dots_len+1); size_t i; for(i = 0; i < d->connected_dots_len; ++i) passwd[i] = '1' + d->connected_dots[i]; passwd[i] = 0; - if(try_password(passwd) < 0) + if(try_password(passwd, d->isFbe) < 0) { - list_clear(&d->active_dots, fb_remove_item); - list_clear(&d->complete_lines, fb_remove_item); + list_clear(&d->active_dots, (callback)fb_remove_item); + list_clear(&d->complete_lines, (callback)fb_remove_item); fb_request_draw(); } @@ -362,9 +373,9 @@ static int type_pattern_touch_handler(touch_event *ev, void *data) return 0; } -static void type_pattern_init(void) +static void type_pattern_init(bool isFbe) { - struct pwui_type_pattern_data *d = mzalloc(sizeof(struct pwui_type_pattern_data)); + struct pwui_type_pattern_data *d = (pwui_type_pattern_data*)mzalloc(sizeof(struct pwui_type_pattern_data)); int cx, cy; const int start_x = fb_width*0.2; @@ -386,6 +397,7 @@ static void type_pattern_init(void) } d->touch_id = -1; + d->isFbe = isFbe; add_touch_handler(type_pattern_touch_handler, d); pwui_type_data = d; @@ -393,17 +405,17 @@ static void type_pattern_init(void) static void type_pattern_destroy(void) { - struct pwui_type_pattern_data *d = pwui_type_data; - list_clear(&d->dots, fb_remove_item); - list_clear(&d->active_dots, fb_remove_item); - list_clear(&d->complete_lines, fb_remove_item); + struct pwui_type_pattern_data *d = (pwui_type_pattern_data*)pwui_type_data; + list_clear(&d->dots, (callback)fb_remove_item); + list_clear(&d->active_dots, (callback)fb_remove_item); + list_clear(&d->complete_lines, (callback)fb_remove_item); fb_rm_line(d->cur_line); free(d); pwui_type_data = NULL; } -static void init_ui(int pwtype) +static void init_ui(int pwtype, bool isFbe) { fb_add_rect_lvl(100, 0, 0, fb_width, HEADER_HEIGHT, C_HIGHLIGHT_BG); @@ -423,7 +435,7 @@ static void init_ui(int pwtype) if(!mrom_is_second_boot()) { - boot_primary_btn = mzalloc(sizeof(button)); + boot_primary_btn = (button*)mzalloc(sizeof(button)); boot_primary_btn->w = fb_width*0.30; boot_primary_btn->h = HEADER_HEIGHT; boot_primary_btn->x = fb_width - boot_primary_btn->w; @@ -434,7 +446,7 @@ static void init_ui(int pwtype) } else { - boot_primary_btn = mzalloc(sizeof(button)); + boot_primary_btn = (button*)mzalloc(sizeof(button)); boot_primary_btn->w = fb_width*0.30; boot_primary_btn->h = HEADER_HEIGHT; boot_primary_btn->x = fb_width - boot_primary_btn->w; @@ -448,10 +460,10 @@ static void init_ui(int pwtype) { case CRYPT_TYPE_PASSWORD: case CRYPT_TYPE_PIN: - type_pass_init(pwtype); + type_pass_init(pwtype, isFbe); break; case CRYPT_TYPE_PATTERN: - type_pattern_init(); + type_pattern_init(isFbe); break; default: t = fb_add_text(0, 0, C_TEXT, SIZE_NORMAL, "Error: unknown password type %d", pwtype); @@ -479,7 +491,7 @@ static void destroy_ui(int pwtype) static int pw_ui_shutdown_counter_touch_handler(UNUSED touch_event *ev, void *data) { - int *shutdown_counter = data; + int *shutdown_counter = (int*)data; if(*shutdown_counter == 0) return -1; @@ -489,7 +501,7 @@ static int pw_ui_shutdown_counter_touch_handler(UNUSED touch_event *ev, void *da return -1; } -int pw_ui_run(int pwtype) +int pw_ui_run(int pwtype, bool isFbe) { int shutdown_counter = 0; @@ -505,7 +517,7 @@ int pw_ui_run(int pwtype) workers_start(); anim_init(1.f); - init_ui(pwtype); + init_ui(pwtype, isFbe); start_input_thread(); add_touch_handler(pw_ui_shutdown_counter_touch_handler, &shutdown_counter); diff --git a/trampoline_encmnt/pw_ui.h b/trampoline_encmnt/pw_ui.h index 1a869509..64f86d29 100644 --- a/trampoline_encmnt/pw_ui.h +++ b/trampoline_encmnt/pw_ui.h @@ -18,6 +18,6 @@ #ifndef PW_UI_H #define PW_UI_H -int pw_ui_run(int pwtype); +int pw_ui_run(int pwtype, bool isFbe); #endif