summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornkk71 <nkk71x@gmail.com>2017-11-06 16:27:21 +0100
committerDees Troy <dees_troy@teamw.in>2017-11-28 23:05:54 +0100
commit7d1222a5fe2c2dfa393e0d37cb58605734b9af7f (patch)
tree654075439f74c31051af4b3fa130afad243d8be1
parentFBE for Pixel 2 (diff)
downloadandroid_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar.gz
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar.bz2
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar.lz
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar.xz
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.tar.zst
android_bootable_recovery-7d1222a5fe2c2dfa393e0d37cb58605734b9af7f.zip
-rw-r--r--crypto/vold_decrypt/Android.mk26
-rwxr-xr-xcrypto/vold_decrypt/init.recovery.vold_decrypt.hwservicemanager.rc18
-rwxr-xr-xcrypto/vold_decrypt/init.recovery.vold_decrypt.keymaster-3-0.rc17
-rwxr-xr-xcrypto/vold_decrypt/init.recovery.vold_decrypt.qseecomd.rc12
-rw-r--r--crypto/vold_decrypt/vold_decrypt.cpp1108
-rw-r--r--crypto/vold_decrypt/vold_decrypt.h18
-rw-r--r--partitionmanager.cpp10
7 files changed, 911 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
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 54ce6912d..7adcc9f46 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -1658,6 +1658,16 @@ int TWPartitionManager::Decrypt_Device(string Password) {
#ifdef TW_CRYPTO_USE_SYSTEM_VOLD
if (pwret != 0) {
pwret = vold_decrypt(Password);
+ switch (pwret) {
+ case VD_SUCCESS:
+ break;
+ case VD_ERR_MISSING_VDC:
+ gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vdc"));
+ break;
+ case VD_ERR_MISSING_VOLD:
+ gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vold"));
+ break;
+ }
}
#endif // TW_CRYPTO_USE_SYSTEM_VOLD