diff options
Diffstat (limited to '')
-rw-r--r-- | crypto/vold_decrypt/Android.mk | 26 | ||||
-rwxr-xr-x | crypto/vold_decrypt/init.recovery.vold_decrypt.hwservicemanager.rc | 18 | ||||
-rwxr-xr-x | crypto/vold_decrypt/init.recovery.vold_decrypt.keymaster-3-0.rc | 17 | ||||
-rwxr-xr-x | crypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc | 12 | ||||
-rw-r--r-- | crypto/vold_decrypt/vold_decrypt.cpp | 1108 | ||||
-rw-r--r-- | crypto/vold_decrypt/vold_decrypt.h | 18 |
6 files changed, 901 insertions, 298 deletions
diff --git a/crypto/vold_decrypt/Android.mk b/crypto/vold_decrypt/Android.mk index e371c24e7..ddfad0327 100644 --- a/crypto/vold_decrypt/Android.mk +++ b/crypto/vold_decrypt/Android.mk @@ -16,7 +16,6 @@ LOCAL_PATH := $(call my-dir) ifeq ($(TW_INCLUDE_CRYPTO), true) ifneq ($(TW_CRYPTO_USE_SYSTEM_VOLD),) - ifneq ($(TW_CRYPTO_USE_SYSTEM_VOLD),false) # Parse TW_CRYPTO_USE_SYSTEM_VOLD @@ -54,6 +53,17 @@ ifeq ($(TW_INCLUDE_CRYPTO), true) cp -f "$(LOCAL_PATH)/$(item)" "$(TARGET_ROOT_OUT)"/; \ fi; \ ) + + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 26; echo $$?),0) + # Truncate service_name to max 16 characters + LOCAL_POST_INSTALL_CMD += \ + $(foreach item, $(rc_files), \ + if [ -f "$(TARGET_ROOT_OUT)/$(item)" ]; then \ + sed -i 's/\([ \t]*service[ \t]*\)\(.\{16\}\).*\([ \t].*\)/\1\2\3/' "$(TARGET_ROOT_OUT)/$(item)"; \ + fi; \ + ) + endif + include $(BUILD_PREBUILT) @@ -66,7 +76,14 @@ ifeq ($(TW_INCLUDE_CRYPTO), true) endif ifneq ($(services),) - LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_SERVICES='"$(services)"' + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 26; echo $$?),0) + # Truncate service_name to max 12 characters due to the 4 character prefix + truncated_services := $(foreach item,$(services),$(shell echo -n "$(item)" | sed 's/\(.\{12\}\).*/\1/')) + LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_SERVICES='"$(truncated_services)"' + LOCAL_CFLAGS += -D_USING_SHORT_SERVICE_NAMES + else + LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_SERVICES='"$(services)"' + endif endif ifeq ($(TW_CRYPTO_SYSTEM_VOLD_DEBUG),true) @@ -74,14 +91,9 @@ ifeq ($(TW_INCLUDE_CRYPTO), true) LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_DEBUG endif - ifeq ($(TW_CRYPTO_SYSTEM_VOLD_DISABLE_TIMEOUT),true) - LOCAL_CFLAGS += -DTW_CRYPTO_SYSTEM_VOLD_DISABLE_TIMEOUT - endif - LOCAL_SRC_FILES = vold_decrypt.cpp LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_STATIC_LIBRARY) endif - endif endif diff --git a/crypto/vold_decrypt/init.recovery.vold_decrypt.hwservicemanager.rc b/crypto/vold_decrypt/init.recovery.vold_decrypt.hwservicemanager.rc new file mode 100755 index 000000000..ab8b4ac4d --- /dev/null +++ b/crypto/vold_decrypt/init.recovery.vold_decrypt.hwservicemanager.rc @@ -0,0 +1,18 @@ +# Service names must be less than 16 characters in android-7.1 and +# below. The makefile will truncate service names if needed in any +# init.recovery.vold_decryp.*.rc file found in the vold_decrypt +# directory. +# It cannot however do this for any .rc file(s) that may be +# overridden by the device tree files! + +# The seclabels are not needed when built in Android 8.0 tree +# in 7.1 however the below do not exist, so run them under vold +service sys_hwservicemanager /system/bin/hwservicemanager + user root + group root + setenv PATH /system/bin + setenv LD_LIBRARY_PATH /system/lib64:/system/lib + onrestart setprop hwservicemanager.ready false + disabled + oneshot + seclabel u:r:vold:s0 diff --git a/crypto/vold_decrypt/init.recovery.vold_decrypt.keymaster-3-0.rc b/crypto/vold_decrypt/init.recovery.vold_decrypt.keymaster-3-0.rc new file mode 100755 index 000000000..e9f0b0241 --- /dev/null +++ b/crypto/vold_decrypt/init.recovery.vold_decrypt.keymaster-3-0.rc @@ -0,0 +1,17 @@ +# Service names must be less than 16 characters in android-7.1 and +# below. The makefile will truncate service names if needed in any +# init.recovery.vold_decryp.*.rc file found in the vold_decrypt +# directory. +# It cannot however do this for any .rc file(s) that may be +# overridden by the device tree files! + +# The seclabels are not needed when built in Android 8.0 tree +# in 7.1 however the below do not exist, so run them under vold +service ven_keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service + user root + group root + setenv PATH /vendor/bin:/system/bin + setenv LD_LIBRARY_PATH /vendor/lib64:/system/lib64:/vendor/lib:/system/lib + disabled + oneshot + seclabel u:r:vold:s0 diff --git a/crypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc b/crypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc index 06bdebcd3..08666085d 100755 --- a/crypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc +++ b/crypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc @@ -5,6 +5,10 @@ on fs chmod 0664 /dev/ion chown system system /dev/ion + +# Oreo has qseecomd in /vendor/bin so add the additional +# service. Only an existing binary will be started, never both. + service sys_qseecomd /system/bin/qseecomd user root group root @@ -12,3 +16,11 @@ service sys_qseecomd /system/bin/qseecomd setenv LD_LIBRARY_PATH /system/lib64:/system/lib disabled oneshot + +service ven_qseecomd /vendor/bin/qseecomd + user root + group root + setenv PATH /vendor/bin:/system/bin + setenv LD_LIBRARY_PATH /vendor/lib64:/system/lib64:/vendor/lib:/system/lib + disabled + oneshot diff --git a/crypto/vold_decrypt/vold_decrypt.cpp b/crypto/vold_decrypt/vold_decrypt.cpp index d535a2514..f6e6e3482 100644 --- a/crypto/vold_decrypt/vold_decrypt.cpp +++ b/crypto/vold_decrypt/vold_decrypt.cpp @@ -16,28 +16,32 @@ along with TWRP. If not, see <http://www.gnu.org/licenses/>. */ - #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> +#include <fcntl.h> +#include <sys/mount.h> #include <sys/time.h> +#include <dirent.h> +#include <fnmatch.h> -#ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG #include <signal.h> #include <sys/types.h> #include <sys/wait.h> -#endif +#include <fstream> #include <string> #include <vector> #include <sstream> -#include "../../twcommon.h" +#ifdef _USING_SHORT_SERVICE_NAMES +#include <map> +#endif + #include "../../partitions.hpp" #include "../../twrp-functions.hpp" -#include "../../gui/gui.hpp" using namespace std; @@ -45,6 +49,10 @@ extern "C" { #include <cutils/properties.h> } +#include "vold_decrypt.h" + +namespace { + /* Timeouts as defined by ServiceManager */ /* The maximum amount of time to wait for a service to start or stop, @@ -55,51 +63,90 @@ extern "C" { #define SLEEP_MIN_USEC 200000 /* 200 msec */ -#define LOGDECRYPT(...) do { printf(__VA_ARGS__); if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]" __VA_ARGS__); fflush(fp_kmsg); } } while (0) -#define LOGDECRYPT_KMSG(...) do { if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]" __VA_ARGS__); fflush(fp_kmsg); } } while (0) +/* vold response codes defined in ResponseCode.h */ +// 200 series - Requested action has been successfully completed +#define COMMAND_OKAY 200 +#define PASSWORD_TYPE_RESULT 213 -#ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES -typedef struct { - string service_name; - string twrp_svc_name; - bool is_running; - bool resume; -} AdditionalService; -#endif + +#define LOGINFO(...) do { printf(__VA_ARGS__); if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]I:" __VA_ARGS__); fflush(fp_kmsg); } } while (0) +#define LOGKMSG(...) do { if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]K:" __VA_ARGS__); fflush(fp_kmsg); } } while (0) +#define LOGERROR(...) do { printf(__VA_ARGS__); if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]E:" __VA_ARGS__); fflush(fp_kmsg); } } while (0) FILE *fp_kmsg = NULL; -bool has_timeout = false; + +/* Debugging Functions */ #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG + +#ifndef VD_STRACE_BIN +#define VD_STRACE_BIN "/sbin/strace" +#endif + bool has_strace = false; +pid_t pid_strace = 0; -pid_t strace_init(void) { - if (!has_strace) - return -1; +void Strace_init_Start(void) { + has_strace = TWFunc::Path_Exists(VD_STRACE_BIN); + if (!has_strace) { + LOGINFO("strace binary (%s) not found, disabling strace in vold_decrypt!\n", VD_STRACE_BIN); + return; + } pid_t pid; switch(pid = fork()) { case -1: - LOGDECRYPT_KMSG("forking strace_init failed: %d!\n", errno); - return -1; + LOGKMSG("forking strace_init failed: %d (%s)!\n", errno, strerror(errno)); + return; case 0: // child - execl("/sbin/strace", "strace", "-q", "-tt", "-ff", "-v", "-y", "-s", "1000", "-o", "/tmp/strace_init.log", "-p", "1" , NULL); - LOGDECRYPT_KMSG("strace_init fork failed: %d!\n", errno); + execl(VD_STRACE_BIN, "strace", "-q", "-tt", "-ff", "-v", "-y", "-s", "1000", "-o", "/tmp/strace_init.log", "-p", "1" , NULL); + LOGKMSG("strace_init fork failed: %d (%s)!\n", errno, strerror(errno)); exit(-1); default: - LOGDECRYPT_KMSG("Starting strace_init (pid=%d)\n", pid); - return pid; + LOGKMSG("Starting strace_init (pid=%d)\n", pid); + pid_strace = pid; + return; } } -#endif + +void Strace_init_Stop(void) { + if (pid_strace > 0) { + LOGKMSG("Stopping strace_init (pid=%d)\n", pid_strace); + int timeout; + int status; + pid_t retpid = waitpid(pid_strace, &status, WNOHANG); + + kill(pid_strace, SIGTERM); + for (timeout = 5; retpid == 0 && timeout; --timeout) { + sleep(1); + retpid = waitpid(pid_strace, &status, WNOHANG); + } + if (retpid) + LOGKMSG("strace_init terminated successfully\n"); + else { + // SIGTERM didn't work, kill it instead + kill(pid_strace, SIGKILL); + for (timeout = 5; retpid == 0 && timeout; --timeout) { + sleep(1); + retpid = waitpid(pid_strace, &status, WNOHANG); + } + if (retpid) + LOGKMSG("strace_init killed successfully\n"); + else + LOGKMSG("strace_init took too long to kill, may be a zombie process\n"); + } + } +} +#endif // TW_CRYPTO_SYSTEM_VOLD_DEBUG + /* Convert a binary key of specified length into an ascii hex string equivalent, * without the leading 0x and with null termination * * Original code from cryptfs.c */ -string convert_key_to_hex_ascii(string master_key) { +string convert_key_to_hex_ascii(const string& master_key) { size_t i; unsigned char nibble; string master_key_ascii = ""; @@ -117,7 +164,46 @@ string convert_key_to_hex_ascii(string master_key) { return master_key_ascii; } -string wait_for_property(string property_name, int utimeout = SLEEP_MAX_USEC, string expected_value = "not_empty") { +/* Helper Functions */ +#define PATH_EXISTS(path) (access(path, F_OK) >= 0) + +int vrename(const string& oldname, const string& newname, bool verbose = false) { + const char *old_name = oldname.c_str(); + const char *new_name = newname.c_str(); + + if (!PATH_EXISTS(old_name)) + return 0; + + if (rename(old_name, new_name) < 0) { + LOGERROR("Moving %s to %s failed: %d (%s)\n", old_name, new_name, errno, strerror(errno)); + return -1; + } else if (verbose) + LOGINFO("Renamed %s to %s\n", old_name, new_name); + else + LOGKMSG("Renamed %s to %s\n", old_name, new_name); + return 0; +} + +int vsymlink(const string& oldname, const string& newname, bool verbose = false) { + const char *old_name = oldname.c_str(); + const char *new_name = newname.c_str(); + + if (!PATH_EXISTS(old_name)) + return 0; + + if (symlink(old_name, new_name) < 0) { + LOGERROR("Symlink %s -> %s failed: %d (%s)\n", new_name, old_name, errno, strerror(errno)); + return -1; + } else if (verbose) + LOGINFO("Symlinked %s -> %s\n", new_name, old_name); + else + LOGKMSG("Symlinked %s -> %s\n", new_name, old_name); + return 0; +} + + +/* Properties and Services Functions */ +string Wait_For_Property(const string& property_name, int utimeout = SLEEP_MAX_USEC, const string& expected_value = "not_empty") { char prop_value[PROPERTY_VALUE_MAX]; if (expected_value == "not_empty") { @@ -125,7 +211,7 @@ string wait_for_property(string property_name, int utimeout = SLEEP_MAX_USEC, st property_get(property_name.c_str(), prop_value, "error"); if (strcmp(prop_value, "error") != 0) break; - LOGDECRYPT_KMSG("waiting for %s to get set\n", property_name.c_str()); + LOGKMSG("waiting for %s to get set\n", property_name.c_str()); utimeout -= SLEEP_MIN_USEC; usleep(SLEEP_MIN_USEC);; } @@ -135,7 +221,7 @@ string wait_for_property(string property_name, int utimeout = SLEEP_MAX_USEC, st property_get(property_name.c_str(), prop_value, "error"); if (strcmp(prop_value, expected_value.c_str()) == 0) break; - LOGDECRYPT_KMSG("waiting for %s to change from '%s' to '%s'\n", property_name.c_str(), prop_value, expected_value.c_str()); + LOGKMSG("waiting for %s to change from '%s' to '%s'\n", property_name.c_str(), prop_value, expected_value.c_str()); utimeout -= SLEEP_MIN_USEC; usleep(SLEEP_MIN_USEC);; } @@ -145,179 +231,84 @@ string wait_for_property(string property_name, int utimeout = SLEEP_MAX_USEC, st return prop_value; } -bool Service_Exists(string initrc_svc) { +string Get_Service_State(const string& initrc_svc) { char prop_value[PROPERTY_VALUE_MAX]; string init_svc = "init.svc." + initrc_svc; property_get(init_svc.c_str(), prop_value, "error"); - return (strcmp(prop_value, "error") != 0); + return prop_value; } -bool Is_Service_Running(string initrc_svc) { - char prop_value[PROPERTY_VALUE_MAX]; - string init_svc = "init.svc." + initrc_svc; - property_get(init_svc.c_str(), prop_value, "error"); - return (strcmp(prop_value, "running") == 0); +bool Service_Exists(const string& initrc_svc) { + return (Get_Service_State(initrc_svc) != "error"); } -bool Is_Service_Stopped(string initrc_svc) { - char prop_value[PROPERTY_VALUE_MAX]; - string init_svc = "init.svc." + initrc_svc; - property_get(init_svc.c_str(), prop_value, "error"); - return (strcmp(prop_value, "stopped") == 0); +bool Is_Service_Running(const string& initrc_svc) { + return (Get_Service_State(initrc_svc) == "running"); } -bool Start_Service(string initrc_svc, int utimeout = SLEEP_MAX_USEC) { +bool Is_Service_Stopped(const string& initrc_svc) { + return (Get_Service_State(initrc_svc) == "stopped"); +} + +bool Start_Service(const string& initrc_svc, int utimeout = SLEEP_MAX_USEC) { string res = "error"; string init_svc = "init.svc." + initrc_svc; property_set("ctl.start", initrc_svc.c_str()); - res = wait_for_property(init_svc, utimeout, "running"); + res = Wait_For_Property(init_svc, utimeout, "running"); - LOGDECRYPT("Start service %s: %s.\n", initrc_svc.c_str(), res.c_str()); + LOGINFO("Start service %s: %s.\n", initrc_svc.c_str(), res.c_str()); return (res == "running"); } -bool Stop_Service(string initrc_svc, int utimeout = SLEEP_MAX_USEC) { +bool Stop_Service(const string& initrc_svc, int utimeout = SLEEP_MAX_USEC) { string res = "error"; if (Service_Exists(initrc_svc)) { string init_svc = "init.svc." + initrc_svc; property_set("ctl.stop", initrc_svc.c_str()); - res = wait_for_property(init_svc, utimeout, "stopped"); - LOGDECRYPT("Stop service %s: %s.\n", initrc_svc.c_str(), res.c_str()); + res = Wait_For_Property(init_svc, utimeout, "stopped"); + LOGINFO("Stop service %s: %s.\n", initrc_svc.c_str(), res.c_str()); } return (res == "stopped"); } -void output_dmesg_to_recoverylog(void) { - TWFunc::Exec_Cmd( - "echo \"---- DMESG LOG FOLLOWS ----\";" - "dmesg | grep 'DECRYPT\\|vold\\|qseecom\\|QSEECOM\\|keymaste\\|keystore\\|cmnlib';" - "echo \"---- DMESG LOG ENDS ----\"" - ); -} -void set_needed_props(void) { - // vold won't start without ro.storage_structure on Kitkat - string sdkverstr = TWFunc::System_Property_Get("ro.build.version.sdk"); - int sdkver = 20; - if (!sdkverstr.empty()) { - sdkver = atoi(sdkverstr.c_str()); - } - if (sdkver <= 19) { - string ro_storage_structure = TWFunc::System_Property_Get("ro.storage_structure"); - if (!ro_storage_structure.empty()) - property_set("ro.storage_structure", ro_storage_structure.c_str()); - } +/* Vendor, Firmware and fstab symlink Functions */ +bool is_Vendor_Mounted(void) { + static int is_mounted = -1; + if (is_mounted < 0) + is_mounted = PartitionManager.Is_Mounted_By_Path("/vendor") ? 1 : 0; + return is_mounted; } -string vdc_cryptfs_cmd(string log_name) { - string cmd = "LD_LIBRARY_PATH=/system/lib64:/system/lib /system/bin/vdc cryptfs"; - -#ifndef TW_CRYPTO_SYSTEM_VOLD_DEBUG - (void)log_name; // do nothing, but get rid of compiler warning in non debug builds -#else - if (has_timeout && has_strace) - cmd = "/sbin/strace -q -tt -ff -v -y -s 1000 -o /tmp/strace_vdc_" + log_name + " /sbin/timeout -t 30 -s KILL env " + cmd; - else if (has_strace) - cmd = "/sbin/strace -q -tt -ff -v -y -s 1000 -o /tmp/strace_vdc_" + log_name + " -E " + cmd; - else -#endif - if (has_timeout) - cmd = "/sbin/timeout -t 30 -s KILL env " + cmd; - - return cmd; +bool is_Firmware_Mounted(void) { + static int is_mounted = -1; + if (is_mounted < 0) + is_mounted = PartitionManager.Is_Mounted_By_Path("/firmware") ? 1 : 0; + return is_mounted; } -int run_vdc(string Password) { - int res = -1; - struct timeval t1, t2; - string vdc_res; - int vdc_r1, vdc_r2, vdc_r3; - - LOGDECRYPT("About to run vdc...\n"); - - // Wait for vold connection - gettimeofday(&t1, NULL); - t2 = t1; - while ((t2.tv_sec - t1.tv_sec) < 5) { - vdc_res.clear(); - // cryptfs getpwtype returns: R1=213(PasswordTypeResult) R2=? R3="password", "pattern", "pin", "default" - res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("connect") + " getpwtype", vdc_res); - std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) - vdc_r1 = vdc_r2 = vdc_r3 = -1; - sscanf(vdc_res.c_str(), "%d", &vdc_r1); - if (vdc_r1 == 213) { - char str_res[sizeof(int) + 1]; - snprintf(str_res, sizeof(str_res), "%d", res); - vdc_res += "ret="; - vdc_res += str_res; - res = 0; - break; - } - LOGDECRYPT("Retrying connection to vold\n"); - usleep(SLEEP_MIN_USEC); // vdc usually usleep(10000), but that causes too many unnecessary attempts - gettimeofday(&t2, NULL); - } - - if (res != 0) - return res; - - LOGDECRYPT("Connected to vold (%s)\n", vdc_res.c_str()); - - // Input password from GUI, or default password - vdc_res.clear(); - res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("passwd") + " checkpw '" + Password + "'", vdc_res); - std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) - LOGDECRYPT("vdc cryptfs result (passwd): %s (ret=%d)\n", vdc_res.c_str(), res); - vdc_r1 = vdc_r2 = vdc_r3 = -1; - sscanf(vdc_res.c_str(), "%d %d %d", &vdc_r1, &vdc_r2, &vdc_r3); - - if (vdc_r3 != 0) { - // try falling back to Lollipop hex passwords - string hexPassword = convert_key_to_hex_ascii(Password); - vdc_res.clear(); - res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("hex_pw") + " checkpw '" + hexPassword + "'", vdc_res); - std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) - LOGDECRYPT("vdc cryptfs result (hex_pw): %s (ret=%d)\n", vdc_res.c_str(), res); - vdc_r1 = vdc_r2 = vdc_r3 = -1; - sscanf(vdc_res.c_str(), "%d %d %d", &vdc_r1, &vdc_r2, &vdc_r3); - } - - // vdc's return value is dependant upon source origin, it will either - // return 0 or vdc_r1, so disregard and focus on decryption instead - if (vdc_r3 == 0) { - // Decryption successful wait for crypto blk dev - wait_for_property("ro.crypto.fs_crypto_blkdev"); - res = 0; - } else { - res = -1; - } - - return res; +bool will_VendorBin_Be_Symlinked(void) { + return (!is_Vendor_Mounted() && TWFunc::Path_Exists("/system/vendor")); } bool Symlink_Vendor_Folder(void) { bool is_vendor_symlinked = false; - if (PartitionManager.Is_Mounted_By_Path("/vendor")) { - LOGDECRYPT("vendor partition mounted, skipping /vendor substitution\n"); + if (is_Vendor_Mounted()) { + LOGINFO("vendor partition mounted, skipping /vendor substitution\n"); } else if (TWFunc::Path_Exists("/system/vendor")) { - LOGDECRYPT("Symlinking vendor folder...\n"); - if (TWFunc::Path_Exists("/vendor") && rename("/vendor", "/vendor-orig") != 0) { - LOGDECRYPT("Failed to rename original /vendor folder: %s\n", strerror(errno)); - } else { + LOGINFO("Symlinking vendor folder...\n"); + if (!TWFunc::Path_Exists("/vendor") || vrename("/vendor", "/vendor-orig") == 0) { TWFunc::Recursive_Mkdir("/vendor/firmware/keymaster"); - LOGDECRYPT_KMSG("Symlinking /system/vendor/lib64 to /vendor/lib64 (res=%d)\n", - symlink("/system/vendor/lib64", "/vendor/lib64") - ); - LOGDECRYPT_KMSG("Symlinking /system/vendor/lib to /vendor/lib (res=%d)\n", - symlink("/system/vendor/lib", "/vendor/lib") - ); + vsymlink("/system/vendor/lib64", "/vendor/lib64"); + vsymlink("/system/vendor/lib", "/vendor/lib"); + vsymlink("/system/vendor/bin", "/vendor/bin"); is_vendor_symlinked = true; property_set("vold_decrypt.symlinked_vendor", "1"); } @@ -328,19 +319,18 @@ bool Symlink_Vendor_Folder(void) { void Restore_Vendor_Folder(void) { property_set("vold_decrypt.symlinked_vendor", "0"); TWFunc::removeDir("/vendor", false); - rename("/vendor-orig", "/vendor"); + vrename("/vendor-orig", "/vendor"); } bool Symlink_Firmware_Folder(void) { bool is_firmware_symlinked = false; - if (PartitionManager.Is_Mounted_By_Path("/firmware")) { - LOGDECRYPT("firmware partition mounted, skipping /firmware substitution\n"); - } else { - LOGDECRYPT("Symlinking firmware folder...\n"); - if (TWFunc::Path_Exists("/firmware") && rename("/firmware", "/firmware-orig") != 0) { - LOGDECRYPT("Failed to rename original /firmware folder: %s\n", strerror(errno)); - } else { + if (is_Firmware_Mounted()) { + LOGINFO("firmware partition mounted, skipping /firmware substitution\n"); + } + else { + LOGINFO("Symlinking firmware folder...\n"); + if (!TWFunc::Path_Exists("/firmware") || vrename("/firmware", "/firmware-orig") == 0) { TWFunc::Recursive_Mkdir("/firmware/image"); is_firmware_symlinked = true; property_set("vold_decrypt.symlinked_firmware", "1"); @@ -352,103 +342,674 @@ bool Symlink_Firmware_Folder(void) { void Restore_Firmware_Folder(void) { property_set("vold_decrypt.symlinked_firmware", "0"); TWFunc::removeDir("/firmware", false); - rename("/firmware-orig", "/firmware"); + vrename("/firmware-orig", "/firmware"); +} + +int Find_Firmware_Files(const string& Path, vector<string> *FileList) { + int ret; + DIR* d; + struct dirent* de; + string FileName; + + d = opendir(Path.c_str()); + if (d == NULL) { + closedir(d); + return -1; + } + while ((de = readdir(d)) != NULL) { + if (de->d_type == DT_DIR) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + FileName = Path + "/" + de->d_name; + ret = Find_Firmware_Files(FileName, FileList); + if (ret < 0) + return -1; + } else if (de->d_type == DT_REG) { + if (fnmatch("keymaste*.*", de->d_name, 0) == 0 || fnmatch("cmnlib.*", de->d_name, 0) == 0) { + FileName = Path + "/" + de->d_name; + FileList->push_back(FileName); + } + } + } + closedir(d); + return 0; } void Symlink_Firmware_Files(bool is_vendor_symlinked, bool is_firmware_symlinked) { if (!is_vendor_symlinked && !is_firmware_symlinked) return; - LOGDECRYPT("Symlinking firmware files...\n"); - string result_of_find; - TWFunc::Exec_Cmd("find /system -name keymaste*.* -type f -o -name cmnlib.* -type f 2>/dev/null", result_of_find); + LOGINFO("Symlinking firmware files...\n"); - stringstream ss(result_of_find); - string line; - int count = 0; + vector<string> FirmwareFiles; + Find_Firmware_Files("/system", &FirmwareFiles); - while(getline(ss, line)) { - const char *fwfile = line.c_str(); - string base_name = TWFunc::Get_Filename(line); - count++; + for (size_t i = 0; i < FirmwareFiles.size(); ++i) { + string base_name = TWFunc::Get_Filename(FirmwareFiles[i]); - if (is_firmware_symlinked) { - LOGDECRYPT_KMSG("Symlinking %s to /firmware/image/ (res=%d)\n", fwfile, - symlink(fwfile, ("/firmware/image/" + base_name).c_str()) - ); - } + if (is_firmware_symlinked) + vsymlink(FirmwareFiles[i], "/firmware/image/" + base_name); if (is_vendor_symlinked) { - LOGDECRYPT_KMSG("Symlinking %s to /vendor/firmware/ (res=%d)\n", fwfile, - symlink(fwfile, ("/vendor/firmware/" + base_name).c_str()) - ); + vsymlink(FirmwareFiles[i], "/vendor/firmware/" + base_name); + vsymlink(FirmwareFiles[i], "/vendor/firmware/keymaster/" + base_name); + } + } + LOGINFO("%d file(s) symlinked.\n", (int)FirmwareFiles.size()); +} - LOGDECRYPT_KMSG("Symlinking %s to /vendor/firmware/keymaster/ (res=%d)\n", fwfile, - symlink(fwfile, ("/vendor/firmware/keymaster/" + base_name).c_str()) - ); +// Android 8.0 fs_mgr checks for "/sbin/recovery", in which case it will +// use /etc/recovery.fstab -> symlink it temporarily. Reference: +// https://android.googlesource.com/platform/system/core/+/android-8.0.0_r17/fs_mgr/fs_mgr_fstab.cpp#693 +bool Symlink_Recovery_Fstab(void) { + bool is_fstab_symlinked = false; + + if (vrename("/etc/recovery.fstab", "/etc/recovery-fstab-orig") == 0) { + is_fstab_symlinked = true; + + // now attempt to symlink to /fstab.{ro.hardware}, but even if that + // fails, keep TWRP's fstab hidden since it cannot be parsed by fs_mgr + char prop_value[PROPERTY_VALUE_MAX]; + property_get("ro.hardware", prop_value, "error"); + if (strcmp(prop_value, "error")) { + string fstab_device = "/fstab."; fstab_device += prop_value; + vsymlink(fstab_device, "/etc/recovery.fstab"); } } - LOGDECRYPT("%d file(s) symlinked.\n", count); + return is_fstab_symlinked; } +void Restore_Recovery_Fstab(void) { + unlink("/etc/recovery.fstab"); + vrename("/etc/recovery-fstab-orig", "/etc/recovery.fstab"); +} + + +/* Additional Services Functions */ #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES -vector<AdditionalService> Get_List_Of_Additional_Services (void) { +typedef struct { + string Service_Name; + string Service_Path; + string Service_Binary; + + string VOLD_Service_Name; + string TWRP_Service_Name; + bool is_running; + bool resume; + bool exists; +} AdditionalService; + +typedef struct { + string Service_Name; + string Service_Path; + string Service_Binary; +} RC_Service; + +// expand_props() courtesy of platform_system_core_init_util.cpp +bool expand_props(const std::string& src, std::string* dst) { + const char* src_ptr = src.c_str(); + + if (!dst) { + return false; + } + + /* - variables can either be $x.y or ${x.y}, in case they are only part + * of the string. + * - will accept $$ as a literal $. + * - no nested property expansion, i.e. ${foo.${bar}} is not supported, + * bad things will happen + * - ${x.y:-default} will return default value if property empty. + */ + while (*src_ptr) { + const char* c; + + c = strchr(src_ptr, '$'); + if (!c) { + dst->append(src_ptr); + return true; + } + + dst->append(src_ptr, c); + c++; + + if (*c == '$') { + dst->push_back(*(c++)); + src_ptr = c; + continue; + } else if (*c == '\0') { + return true; + } + + std::string prop_name; + std::string def_val; + if (*c == '{') { + c++; + const char* end = strchr(c, '}'); + if (!end) { + // failed to find closing brace, abort. + return false; + } + prop_name = std::string(c, end); + c = end + 1; + size_t def = prop_name.find(":-"); + if (def < prop_name.size()) { + def_val = prop_name.substr(def + 2); + prop_name = prop_name.substr(0, def); + } + } else { + prop_name = c; + c += prop_name.size(); + } + + if (prop_name.empty()) { + return false; + } + + char prop_value[PROPERTY_VALUE_MAX]; + property_get(prop_name.c_str(), prop_value, ""); + std::string prop_val = prop_value; + if (prop_val.empty()) { + if (def_val.empty()) { + return false; + } + prop_val = def_val; + } + + dst->append(prop_val); + src_ptr = c; + } + + return true; +} + +string GetArgument(const string& line, size_t argument_number, bool expand_properties) { + size_t beg; + size_t end; + string argument; + + beg = line.find_first_not_of(" \t\r"); + if (beg == string::npos) + return ""; + + for (size_t i = 0; i < argument_number; ++i) { + end = line.find_first_of(" \t\r", beg); + if (end == string::npos) + return ""; + + beg = line.find_first_not_of(" \t\r", end); + if (beg == string::npos) + return ""; + } + + end = line.find_first_of(" \t\r", beg); + if (end == string::npos) + argument = line.substr(beg); + else + argument = line.substr(beg, end - beg); // exclude trailing whitespace + + if (expand_properties) { + string expanded_property_argument; + if (expand_props(argument, &expanded_property_argument)) + return expanded_property_argument; + else + return ""; + } else { + return argument; + } +} + +// Very simplified .rc parser to get services +void Parse_RC_File(const string& rc_file, vector<RC_Service>& RC_Services) { + ifstream file; + + file.open(rc_file.c_str(), ios::in); + if (!file.is_open()) + return; + + size_t beg; // left trim + size_t end; // right trim + bool continuation = false; // backslash continuation + string line; // line + string real_line; // trimmed line with backslash continuation removal + vector<string> imports; // file names of imports (we don't want to recursively do while the file is open) + + while (getline(file, line)) { + beg = line.find_first_not_of(" \t\r"); + end = line.find_last_not_of(" \t\r"); + if (end == string::npos) + end = line.length(); + + if (beg == string::npos) { + if (continuation) + continuation = false; + else + continue; + } else if (line[end] == '\\') { + continuation = true; + real_line += line.substr(beg, end - beg); // excluding backslash + continue; + } else if (continuation) { + continuation = false; + real_line += line.substr(beg, end - beg + 1); + } else { + real_line = line.substr(beg, end - beg + 1); + } + + if (GetArgument(real_line, 0, false) == "import") { + // handle: import <file> + string file_name = GetArgument(real_line, 1, true); + if (file_name.empty()) { + // INVALID IMPORT + } else + imports.push_back(file_name); + } else if (GetArgument(real_line, 0, false) == "service") { + // handle: service <name> <path> + RC_Service svc; + + svc.Service_Name = GetArgument(real_line, 1, false); + svc.Service_Path = GetArgument(real_line, 2, true); + + if (svc.Service_Name.empty() || svc.Service_Path.empty()) { + // INVALID SERVICE ENTRY + } else { + beg = svc.Service_Path.find_last_of("/"); + if (beg == string::npos) + svc.Service_Binary = svc.Service_Path; + else + svc.Service_Binary = svc.Service_Path.substr(beg + 1); + +/* +#ifdef _USING_SHORT_SERVICE_NAMES + if (svc.Service_Name.length() > 16) { + LOGERROR("WARNING: Ignoring service %s (-> %s)\n" + " defined in %s is greater than 16 characters and will\n" + " not be able to be run by init on android-7.1 or below!\n", + svc.Service_Name.c_str(), svc.Service_Path.c_str(), rc_file.c_str() + ); + } + else +#endif +*/ + RC_Services.push_back(svc); + } + } + real_line.clear(); + } + file.close(); + + for (size_t i = 0; i < imports.size(); ++i) { + Parse_RC_File(imports[i], RC_Services); + } +} + +vector<AdditionalService> Get_List_Of_Additional_Services(void) { vector<AdditionalService> services; + // Additional Services needed by vold_decrypt (eg qseecomd, hwservicemanager, etc) vector<string> service_names = TWFunc::Split_String(TW_CRYPTO_SYSTEM_VOLD_SERVICES, " "); - for (size_t i = 0; i < service_names.size(); ++i) { AdditionalService svc; - svc.service_name = service_names[i]; + svc.Service_Name = service_names[i]; + svc.exists = false; services.push_back(svc); + +#ifdef _USING_SHORT_SERVICE_NAMES + // Fallback code for >16 character service names which + // allows for multiple definitions in custom .rc files + if (service_names[i].length() > 12) { + svc.Service_Name = service_names[i].substr(0, 12); // 16-4(prefix)=12 + svc.exists = false; + services.push_back(svc); + } +#endif } + // Read list of all services defined in all .rc files + vector<RC_Service> RC_Services; + Parse_RC_File("/init.rc", RC_Services); + + + // Cross reference Additional Services against the .rc Services and establish + // availability of the binaries, otherwise disable it to avoid unnecessary + // delays and log spam. + // Also check for duplicate entries between TWRP and vold_decrypt so we can + // stop and restart any conflicting services. + for (size_t i = 0; i < RC_Services.size(); ++i) { + string prefix = RC_Services[i].Service_Name.substr(0, 4); + +#ifdef _USING_SHORT_SERVICE_NAMES + map<string,size_t> rc_indeces; +#endif + + if (prefix != "sys_" && prefix != "ven_") { +#ifdef _USING_SHORT_SERVICE_NAMES + if (RC_Services[i].Service_Name.length() > 12) { + // save this entry for potential binary name match + rc_indeces.insert(pair<string,size_t>(RC_Services[i].Service_Binary, i)); + } +#endif + continue; + } + + for (size_t j = 0; j < services.size(); ++j) { + string path = RC_Services[i].Service_Path; + if (prefix == "ven_" && will_VendorBin_Be_Symlinked()) { + path = "/system" + path; // vendor is going to get symlinked to /system/vendor + } + + if (RC_Services[i].Service_Name == prefix + services[j].Service_Name) { + if (!services[j].VOLD_Service_Name.empty() && TWFunc::Path_Exists(path)) { + // Duplicate match, log but use previous definition + LOGERROR("Service %s: VOLD_Service_Name already defined as %s\n", RC_Services[i].Service_Name.c_str(), services[j].VOLD_Service_Name.c_str()); + } + else if (TWFunc::Path_Exists(path)) { + services[j].exists = true; + services[j].VOLD_Service_Name = RC_Services[i].Service_Name; // prefix + service_name + services[j].Service_Path = RC_Services[i].Service_Path; + services[j].Service_Binary = RC_Services[i].Service_Binary; + + if (Service_Exists(services[j].Service_Name)) + services[j].TWRP_Service_Name = services[j].Service_Name; + else if (Service_Exists("sbin" + services[j].Service_Name)) + services[j].TWRP_Service_Name = "sbin" + services[j].Service_Name; + else + services[j].TWRP_Service_Name.clear(); + +#ifdef _USING_SHORT_SERVICE_NAMES + if (services[j].TWRP_Service_Name.empty()) { + // Try matching Service_Binary (due to 16 character service_name limit in 7.1 and below) + map<string,size_t>::iterator it = rc_indeces.find(services[j].Service_Binary); + if (it != rc_indeces.end()) { + services[j].TWRP_Service_Name = RC_Services[it->second].Service_Name; + } + } +#endif + } + break; + } + } + } + + LOGINFO("List of additional services for vold_decrypt:\n"); + for (size_t i = 0; i < services.size(); ++i) { + if (services[i].exists) { + if (services[i].TWRP_Service_Name.empty()) { + LOGINFO(" %s: Enabled as %s -> %s\n", + services[i].Service_Name.c_str(), + services[i].VOLD_Service_Name.c_str(), services[i].Service_Path.c_str() + ); + } else { + LOGINFO(" %s: Enabled as %s -> %s (temporarily replacing TWRP's %s service)\n", + services[i].Service_Name.c_str(), + services[i].VOLD_Service_Name.c_str(), services[i].Service_Path.c_str(), + services[i].TWRP_Service_Name.c_str() + ); + } + } + else + LOGINFO(" %s: Disabled due to lack of matching binary\n", services[i].Service_Name.c_str()); + } return services; } #endif -int vold_decrypt(string Password) -{ + +/* Misc Functions */ +void Set_Needed_Properties(void) { + // vold won't start without ro.storage_structure on Kitkat + string sdkverstr = TWFunc::System_Property_Get("ro.build.version.sdk"); + int sdkver = 20; + if (!sdkverstr.empty()) { + sdkver = atoi(sdkverstr.c_str()); + } + if (sdkver <= 19) { + string ro_storage_structure = TWFunc::System_Property_Get("ro.storage_structure"); + if (!ro_storage_structure.empty()) + property_set("ro.storage_structure", ro_storage_structure.c_str()); + } +} + + +/* vdc Functions */ +typedef struct { + string Output; // Entire line excluding \n + int ResponseCode; // ResponseCode.h (int) + int Sequence; // Sequence (int) + int Message; // Message (string) but we're only interested in int +} vdc_ReturnValues; + +int Exec_vdc_cryptfs(const string& command, const string& argument, vdc_ReturnValues* vdcResult) { + pid_t pid; + int status; + int pipe_fd[2]; + vdcResult->Output.clear(); + + if (pipe(pipe_fd)) { + LOGERROR("exec_vdc_cryptfs: pipe() error!\n"); + return -1; + } + + const char *cmd[] = { "/system/bin/vdc", "cryptfs" }; + const char *env[] = { "LD_LIBRARY_PATH=/system/lib64:/system/lib", NULL }; + +#ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG + string log_name = "/tmp/strace_vdc_" + command; +#endif + + switch(pid = fork()) + { + case -1: + LOGERROR("exec_vdc_cryptfs: fork failed: %d (%s)!\n", errno, strerror(errno)); + return -1; + + case 0: // child + fflush(stdout); fflush(stderr); + close(pipe_fd[0]); + dup2(pipe_fd[1], STDOUT_FILENO); + dup2(pipe_fd[1], STDERR_FILENO); + close(pipe_fd[1]); + +#ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG + if (has_strace) { + if (argument.empty()) + execl(VD_STRACE_BIN, "strace", "-q", "-tt", "-ff", "-v", "-y", "-s", "1000", "-o", log_name.c_str(), + "-E", env[0], cmd[0], cmd[1], command.c_str(), NULL); + else + execl(VD_STRACE_BIN, "strace", "-q", "-tt", "-ff", "-v", "-y", "-s", "1000", "-o", log_name.c_str(), + "-E", env[0], cmd[0], cmd[1], command.c_str(), argument.c_str(), NULL); + } else +#endif + if (argument.empty()) + execle(cmd[0], cmd[0], cmd[1], command.c_str(), NULL, env); + else + execle(cmd[0], cmd[0], cmd[1], command.c_str(), argument.c_str(), NULL, env); + _exit(127); + break; + + default: + { + int timeout = 30*100; + vdcResult->Output.clear(); + close(pipe_fd[1]); + + // Non-blocking read loop with timeout + int flags = fcntl(pipe_fd[0], F_GETFL, 0); + fcntl(pipe_fd[0], F_SETFL, flags | O_NONBLOCK); + + char buffer[128]; + ssize_t count; + pid_t retpid = waitpid(pid, &status, WNOHANG); + while (true) { + count = read(pipe_fd[0], buffer, sizeof(buffer)); + if (count == -1) { + if (errno == EINTR) + continue; + else if (errno != EAGAIN) + LOGERROR("exec_vdc_cryptfs: read() error %d (%s)\n!", errno, strerror(errno)); + } else if (count > 0) { + vdcResult->Output.append(buffer, count); + } + + retpid = waitpid(pid, &status, WNOHANG); + if (retpid == 0 && --timeout) + usleep(10000); + else + break; + }; + close(pipe_fd[0]); + if (vdcResult->Output.length() > 0 && vdcResult->Output[vdcResult->Output.length() - 1] == '\n') + vdcResult->Output.erase(vdcResult->Output.length() - 1); + vdcResult->ResponseCode = vdcResult->Sequence = vdcResult->Message = -1; + sscanf(vdcResult->Output.c_str(), "%d %d %d", &vdcResult->ResponseCode, &vdcResult->Sequence, &vdcResult->Message); + + // Error handling + if (retpid == 0 && timeout == 0) { + LOGERROR("exec_vdc_cryptfs: took too long, killing process\n"); + kill(pid, SIGKILL); + for (timeout = 5; retpid == 0 && timeout; --timeout) { + sleep(1); + retpid = waitpid(pid, &status, WNOHANG); + } + if (retpid) + LOGINFO("exec_vdc_cryptfs: process killed successfully\n"); + else + LOGERROR("exec_vdc_cryptfs: process took too long to kill, may be a zombie process\n"); + return VD_ERR_VOLD_OPERATION_TIMEDOUT; + } else if (retpid > 0) { + if (WIFSIGNALED(status)) { + LOGERROR("exec_vdc_cryptfs: process ended with signal: %d\n", WTERMSIG(status)); // Seg fault or some other non-graceful termination + return -1; + } + } else if (retpid < 0) { // no PID returned + if (errno == ECHILD) + LOGINFO("exec_vdc_cryptfs: no child process exist\n"); + else { + LOGERROR("exec_vdc_cryptfs: Unexpected error %d (%s)\n", errno, strerror(errno)); + return -1; + } + } + return 0; + } + } +} + +int Run_vdc(const string& Password) { + int res; + struct timeval t1, t2; + vdc_ReturnValues vdcResult; + + LOGINFO("About to run vdc...\n"); + + // Wait for vold connection + gettimeofday(&t1, NULL); + t2 = t1; + while ((t2.tv_sec - t1.tv_sec) < 5) { + // cryptfs getpwtype returns: R1=213(PasswordTypeResult) R2=? R3="password", "pattern", "pin", "default" + res = Exec_vdc_cryptfs("getpwtype", "", &vdcResult); + if (vdcResult.ResponseCode == PASSWORD_TYPE_RESULT) { + char str_res[4 + sizeof(int) + 1]; + snprintf(str_res, sizeof(str_res), "ret=%d", res); + vdcResult.Output += str_res; + res = 0; + break; + } + LOGINFO("Retrying connection to vold (Reason: %s)\n", vdcResult.Output.c_str()); + usleep(SLEEP_MIN_USEC); // vdc usually usleep(10000), but that causes too many unnecessary attempts + gettimeofday(&t2, NULL); + } + + if (res == 0 && (t2.tv_sec - t1.tv_sec) < 5) + LOGINFO("Connected to vold (%s)\n", vdcResult.Output.c_str()); + else if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT) + return VD_ERR_VOLD_OPERATION_TIMEDOUT; // should never happen for getpwtype + else if (res) + return VD_ERR_FORK_EXECL_ERROR; + else if (vdcResult.ResponseCode != -1) + return VD_ERR_VOLD_UNEXPECTED_RESPONSE; + else + return VD_ERR_VDC_FAILED_TO_CONNECT; + + + // Input password from GUI, or default password + res = Exec_vdc_cryptfs("checkpw", Password, &vdcResult); + if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT) + return VD_ERR_VOLD_OPERATION_TIMEDOUT; + else if (res) + return VD_ERR_FORK_EXECL_ERROR; + + LOGINFO("vdc cryptfs result (passwd): %s (ret=%d)\n", vdcResult.Output.c_str(), res); + /* + if (res == 0 && vdcResult.ResponseCode != COMMAND_OKAY) + return VD_ERR_VOLD_UNEXPECTED_RESPONSE; + */ + + if (vdcResult.Message != 0) { + // try falling back to Lollipop hex passwords + string hexPassword = convert_key_to_hex_ascii(Password); + res = Exec_vdc_cryptfs("checkpw", hexPassword, &vdcResult); + if (res == VD_ERR_VOLD_OPERATION_TIMEDOUT) + return VD_ERR_VOLD_OPERATION_TIMEDOUT; + else if (res) + return VD_ERR_FORK_EXECL_ERROR; + + LOGINFO("vdc cryptfs result (hex_pw): %s (ret=%d)\n", vdcResult.Output.c_str(), res); + /* + if (res == 0 && vdcResult.ResponseCode != COMMAND_OKAY) + return VD_ERR_VOLD_UNEXPECTED_RESPONSE; + */ + } + + // vdc's return value is dependant upon source origin, it will either + // return 0 or ResponseCode, so disregard and focus on decryption instead + if (vdcResult.Message == 0) { + // Decryption successful wait for crypto blk dev + Wait_For_Property("ro.crypto.fs_crypto_blkdev"); + res = VD_SUCCESS; + } else if (vdcResult.ResponseCode != COMMAND_OKAY) { + res = VD_ERR_VOLD_UNEXPECTED_RESPONSE; + } else { + res = VD_ERR_DECRYPTION_FAILED; + } + + return res; +} + +int Vold_Decrypt_Core(const string& Password) { int res; - bool output_dmesg_to_log = false; bool is_vendor_symlinked = false; bool is_firmware_symlinked = false; + bool is_fstab_symlinked = false; bool is_vold_running = false; if (Password.empty()) { - LOGDECRYPT("vold_decrypt: password is empty!\n"); - return -1; + LOGINFO("vold_decrypt: password is empty!\n"); + return VD_ERR_PASSWORD_EMPTY; } // Mount system and check for vold and vdc if (!PartitionManager.Mount_By_Path("/system", true)) { - return -1; + return VD_ERR_UNABLE_TO_MOUNT_SYSTEM; } else if (!TWFunc::Path_Exists("/system/bin/vold")) { - LOGDECRYPT("ERROR: /system/bin/vold not found, aborting.\n"); - gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vold")); - return -1; + LOGINFO("ERROR: /system/bin/vold not found, aborting.\n"); + return VD_ERR_MISSING_VOLD; } else if (!TWFunc::Path_Exists("/system/bin/vdc")) { - LOGDECRYPT("ERROR: /system/bin/vdc not found, aborting.\n"); - gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vdc")); - return -1; + LOGINFO("ERROR: /system/bin/vdc not found, aborting.\n"); + return VD_ERR_MISSING_VDC; } fp_kmsg = fopen("/dev/kmsg", "a"); - LOGDECRYPT("TW_CRYPTO_USE_SYSTEM_VOLD := true\n"); - LOGDECRYPT("Attempting to use system's vold for decryption...\n"); + LOGINFO("TW_CRYPTO_USE_SYSTEM_VOLD := true\n"); -#ifndef TW_CRYPTO_SYSTEM_VOLD_DISABLE_TIMEOUT - has_timeout = TWFunc::Path_Exists("/sbin/timeout"); - if (!has_timeout) - LOGDECRYPT("timeout binary not found, disabling timeout in vold_decrypt!\n"); -#endif + // just cache the result to avoid unneeded duplicates in recovery.log + LOGINFO("Checking existence of vendor and firmware partitions...\n"); + is_Vendor_Mounted(); + is_Firmware_Mounted(); + + LOGINFO("Attempting to use system's vold for decryption...\n"); #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG - has_strace = TWFunc::Path_Exists("/sbin/strace"); - if (!has_strace) - LOGDECRYPT("strace binary not found, disabling strace in vold_decrypt!\n"); - pid_t pid_strace = strace_init(); + Strace_init_Start(); #endif #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES @@ -456,74 +1017,61 @@ int vold_decrypt(string Password) // Check if TWRP is running any of the services for (size_t i = 0; i < Services.size(); ++i) { - if (Service_Exists(Services[i].service_name)) - Services[i].twrp_svc_name = Services[i].service_name; - else if (Service_Exists("sbin" + Services[i].service_name)) - Services[i].twrp_svc_name = "sbin" + Services[i].service_name; - else - Services[i].twrp_svc_name.clear(); - - if (!Services[i].twrp_svc_name.empty() && !Is_Service_Stopped(Services[i].twrp_svc_name)) { + if (!Services[i].TWRP_Service_Name.empty() && !Is_Service_Stopped(Services[i].TWRP_Service_Name)) { Services[i].resume = true; - Stop_Service(Services[i].twrp_svc_name); + Stop_Service(Services[i].TWRP_Service_Name); } else Services[i].resume = false; - - // vold_decrypt system services have to be named sys_{service} in the .rc files - Services[i].service_name = "sys_" + Services[i].service_name; } #endif - LOGDECRYPT("Setting up folders and permissions...\n"); + LOGINFO("Setting up folders and permissions...\n"); + is_fstab_symlinked = Symlink_Recovery_Fstab(); is_vendor_symlinked = Symlink_Vendor_Folder(); is_firmware_symlinked = Symlink_Firmware_Folder(); Symlink_Firmware_Files(is_vendor_symlinked, is_firmware_symlinked); - set_needed_props(); + Set_Needed_Properties(); // Start services needed for vold decrypt - LOGDECRYPT("Starting services...\n"); + LOGINFO("Starting services...\n"); #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES for (size_t i = 0; i < Services.size(); ++i) { - Services[i].is_running = Start_Service(Services[i].service_name); + if (Services[i].exists) + Services[i].is_running = Start_Service(Services[i].VOLD_Service_Name); } #endif is_vold_running = Start_Service("sys_vold"); if (is_vold_running) { - #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES for (size_t i = 0; i < Services.size(); ++i) { - if (!Is_Service_Running(Services[i].service_name) && Services[i].resume) { + if (Services[i].exists && !Is_Service_Running(Services[i].VOLD_Service_Name) && Services[i].resume) { // if system_service has died restart the twrp_service - LOGDECRYPT("%s is not running, resuming %s!\n", Services[i].service_name.c_str(), Services[i].twrp_svc_name.c_str()); - Start_Service(Services[i].twrp_svc_name); + LOGINFO("%s is not running, resuming %s!\n", Services[i].VOLD_Service_Name.c_str(), Services[i].TWRP_Service_Name.c_str()); + Start_Service(Services[i].TWRP_Service_Name); } } #endif - - res = run_vdc(Password); + res = Run_vdc(Password); if (res != 0) { - // Decryption was unsuccessful - LOGDECRYPT("Decryption failed\n"); - output_dmesg_to_log = true; + LOGINFO("Decryption failed\n"); } } else { - LOGDECRYPT("Failed to start vold\n"); - TWFunc::Exec_Cmd("echo \"$(getprop | grep init.svc)\" >> /dev/kmsg"); - output_dmesg_to_log = true; + LOGINFO("Failed to start vold\n"); + res = VD_ERR_VOLD_FAILED_TO_START; } // Stop services needed for vold decrypt so /system can be unmounted - LOGDECRYPT("Stopping services...\n"); + LOGINFO("Stopping services...\n"); Stop_Service("sys_vold"); #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES for (size_t i = 0; i < Services.size(); ++i) { - if (!Is_Service_Running(Services[i].service_name) && Services[i].resume) - Stop_Service(Services[i].twrp_svc_name); - else - Stop_Service(Services[i].service_name); + if (!Is_Service_Running(Services[i].VOLD_Service_Name) && Services[i].resume) + Stop_Service(Services[i].TWRP_Service_Name); + else if (Services[i].exists) + Stop_Service(Services[i].VOLD_Service_Name); } #endif @@ -531,52 +1079,28 @@ int vold_decrypt(string Password) Restore_Firmware_Folder(); if (is_vendor_symlinked) Restore_Vendor_Folder(); + if (is_fstab_symlinked) + Restore_Recovery_Fstab(); if (!PartitionManager.UnMount_By_Path("/system", true)) { // PartitionManager failed to unmount /system, this should not happen, // but in case it does, do a lazy unmount - LOGDECRYPT("WARNING: system could not be unmounted normally!\n"); - TWFunc::Exec_Cmd("umount -l /system"); + LOGINFO("WARNING: system could not be unmounted normally!\n"); + umount2("/system", MNT_DETACH); } - LOGDECRYPT("Finished.\n"); + LOGINFO("Finished.\n"); #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES // Restart previously running services for (size_t i = 0; i < Services.size(); ++i) { if (Services[i].resume) - Start_Service(Services[i].twrp_svc_name); + Start_Service(Services[i].TWRP_Service_Name); } #endif #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG - if (pid_strace > 0) { - LOGDECRYPT_KMSG("Stopping strace_init (pid=%d)\n", pid_strace); - int timeout; - int status; - pid_t retpid = waitpid(pid_strace, &status, WNOHANG); - - kill(pid_strace, SIGTERM); - for (timeout = 5; retpid == 0 && timeout; --timeout) { - sleep(1); - retpid = waitpid(pid_strace, &status, WNOHANG); - } - if (retpid) - LOGDECRYPT_KMSG("strace_init terminated successfully\n"); - else { - // SIGTERM didn't work, kill it instead - kill(pid_strace, SIGKILL); - for (timeout = 5; retpid == 0 && timeout; --timeout) { - sleep(1); - retpid = waitpid(pid_strace, &status, WNOHANG); - } - if (retpid) - LOGDECRYPT_KMSG("strace_init killed successfully\n"); - else - LOGDECRYPT_KMSG("strace_init took too long to kill, may be a zombie process\n"); - } - } - output_dmesg_to_log = true; + Strace_init_Stop(); #endif // Finish up and exit @@ -585,14 +1109,18 @@ int vold_decrypt(string Password) fclose(fp_kmsg); } - if (output_dmesg_to_log) - output_dmesg_to_recoverylog(); + return res; +} - // Finally check if crypto device is up - if (wait_for_property("ro.crypto.fs_crypto_blkdev", 0) != "error") - res = 0; - else - res = -1; +} // namespace - return res; +/* + * Common vold Response Codes / Errors: + * 406 (OpFailedStorageNotFound) -> Problem reading or parsing fstab + * + */ + +/* Main function separated from core in case we want to return error info */ +int vold_decrypt(const string& Password) { + return Vold_Decrypt_Core(Password); } diff --git a/crypto/vold_decrypt/vold_decrypt.h b/crypto/vold_decrypt/vold_decrypt.h index 70db404e9..ba7a74720 100644 --- a/crypto/vold_decrypt/vold_decrypt.h +++ b/crypto/vold_decrypt/vold_decrypt.h @@ -21,6 +21,22 @@ #include <string> -int vold_decrypt(std::string Password); +// -_- +enum { + VD_SUCCESS = 0, + VD_ERR_DECRYPTION_FAILED = -1, + VD_ERR_UNABLE_TO_MOUNT_SYSTEM = -2, + VD_ERR_MISSING_VOLD = -3, + VD_ERR_MISSING_VDC = -4, + VD_ERR_VDC_FAILED_TO_CONNECT = -5, + VD_ERR_VOLD_FAILED_TO_START = -6, + VD_ERR_VOLD_UNEXPECTED_RESPONSE = -7, + VD_ERR_VOLD_OPERATION_TIMEDOUT = -8, + VD_ERR_FORK_EXECL_ERROR = -9, + VD_ERR_PASSWORD_EMPTY = -10, +}; + + +int vold_decrypt(const std::string& Password); #endif // _VOLD_DECRYPT_H |