nkk71 | 71c6c50 | 2017-01-05 23:55:05 +0200 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2017 TeamWin |
| 3 | This file is part of TWRP/TeamWin Recovery Project. |
| 4 | |
| 5 | TWRP is free software: you can redistribute it and/or modify |
| 6 | it under the terms of the GNU General Public License as published by |
| 7 | the Free Software Foundation, either version 3 of the License, or |
| 8 | (at your option) any later version. |
| 9 | |
| 10 | TWRP is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | GNU General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU General Public License |
| 16 | along with TWRP. If not, see <http://www.gnu.org/licenses/>. |
| 17 | */ |
| 18 | |
| 19 | |
| 20 | #include <stdio.h> |
| 21 | #include <stdlib.h> |
| 22 | #include <string.h> |
| 23 | #include <unistd.h> |
| 24 | #include <errno.h> |
| 25 | #include <sys/time.h> |
| 26 | |
| 27 | #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG |
| 28 | #include <signal.h> |
| 29 | #include <sys/types.h> |
| 30 | #include <sys/wait.h> |
| 31 | #endif |
| 32 | |
| 33 | #include <string> |
| 34 | #include <vector> |
| 35 | #include <sstream> |
| 36 | |
| 37 | #include "../../twcommon.h" |
| 38 | #include "../../partitions.hpp" |
| 39 | #include "../../twrp-functions.hpp" |
| 40 | #include "../../gui/gui.hpp" |
| 41 | |
| 42 | using namespace std; |
| 43 | |
| 44 | extern "C" { |
| 45 | #include <cutils/properties.h> |
| 46 | } |
| 47 | |
| 48 | /* Timeouts as defined by ServiceManager */ |
| 49 | |
| 50 | /* The maximum amount of time to wait for a service to start or stop, |
| 51 | * in micro-seconds (really an approximation) */ |
| 52 | #define SLEEP_MAX_USEC 2000000 /* 2 seconds */ |
| 53 | /* The minimal sleeping interval between checking for the service's state |
| 54 | * when looping for SLEEP_MAX_USEC */ |
| 55 | #define SLEEP_MIN_USEC 200000 /* 200 msec */ |
| 56 | |
| 57 | |
| 58 | #define LOGDECRYPT(...) do { printf(__VA_ARGS__); if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]" __VA_ARGS__); fflush(fp_kmsg); } } while (0) |
| 59 | #define LOGDECRYPT_KMSG(...) do { if (fp_kmsg) { fprintf(fp_kmsg, "[VOLD_DECRYPT]" __VA_ARGS__); fflush(fp_kmsg); } } while (0) |
| 60 | |
| 61 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 62 | typedef struct { |
| 63 | string service_name; |
| 64 | string twrp_svc_name; |
| 65 | bool is_running; |
| 66 | bool resume; |
| 67 | } AdditionalService; |
| 68 | #endif |
| 69 | |
| 70 | FILE *fp_kmsg = NULL; |
| 71 | bool has_timeout = false; |
| 72 | |
| 73 | #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG |
| 74 | bool has_strace = false; |
| 75 | |
| 76 | pid_t strace_init(void) { |
| 77 | if (!has_strace) |
| 78 | return -1; |
| 79 | |
| 80 | pid_t pid; |
| 81 | switch(pid = fork()) |
| 82 | { |
| 83 | case -1: |
| 84 | LOGDECRYPT_KMSG("forking strace_init failed: %d!\n", errno); |
| 85 | return -1; |
| 86 | case 0: // child |
| 87 | execl("/sbin/strace", "strace", "-q", "-tt", "-ff", "-v", "-y", "-s", "1000", "-o", "/tmp/strace_init.log", "-p", "1" , NULL); |
| 88 | LOGDECRYPT_KMSG("strace_init fork failed: %d!\n", errno); |
| 89 | exit(-1); |
| 90 | default: |
| 91 | LOGDECRYPT_KMSG("Starting strace_init (pid=%d)\n", pid); |
| 92 | return pid; |
| 93 | } |
| 94 | } |
| 95 | #endif |
| 96 | |
| 97 | /* Convert a binary key of specified length into an ascii hex string equivalent, |
| 98 | * without the leading 0x and with null termination |
| 99 | * |
| 100 | * Original code from cryptfs.c |
| 101 | */ |
| 102 | string convert_key_to_hex_ascii(string master_key) { |
| 103 | size_t i; |
| 104 | unsigned char nibble; |
| 105 | string master_key_ascii = ""; |
| 106 | |
| 107 | for (i = 0; i < master_key.size(); ++i) { |
| 108 | nibble = (master_key[i] >> 4) & 0xf; |
| 109 | nibble += nibble > 9 ? 0x57 : 0x30; |
| 110 | master_key_ascii += nibble; |
| 111 | |
| 112 | nibble = master_key[i] & 0xf; |
| 113 | nibble += nibble > 9 ? 0x57 : 0x30; |
| 114 | master_key_ascii += nibble; |
| 115 | } |
| 116 | |
| 117 | return master_key_ascii; |
| 118 | } |
| 119 | |
| 120 | string wait_for_property(string property_name, int utimeout = SLEEP_MAX_USEC, string expected_value = "not_empty") { |
| 121 | char prop_value[PROPERTY_VALUE_MAX]; |
| 122 | |
| 123 | if (expected_value == "not_empty") { |
| 124 | while (utimeout > 0) { |
| 125 | property_get(property_name.c_str(), prop_value, "error"); |
| 126 | if (strcmp(prop_value, "error") != 0) |
| 127 | break; |
| 128 | LOGDECRYPT_KMSG("waiting for %s to get set\n", property_name.c_str()); |
| 129 | utimeout -= SLEEP_MIN_USEC; |
| 130 | usleep(SLEEP_MIN_USEC);; |
| 131 | } |
| 132 | } |
| 133 | else { |
| 134 | while (utimeout > 0) { |
| 135 | property_get(property_name.c_str(), prop_value, "error"); |
| 136 | if (strcmp(prop_value, expected_value.c_str()) == 0) |
| 137 | break; |
| 138 | LOGDECRYPT_KMSG("waiting for %s to change from '%s' to '%s'\n", property_name.c_str(), prop_value, expected_value.c_str()); |
| 139 | utimeout -= SLEEP_MIN_USEC; |
| 140 | usleep(SLEEP_MIN_USEC);; |
| 141 | } |
| 142 | } |
| 143 | property_get(property_name.c_str(), prop_value, "error"); |
| 144 | |
| 145 | return prop_value; |
| 146 | } |
| 147 | |
| 148 | bool Service_Exists(string initrc_svc) { |
| 149 | char prop_value[PROPERTY_VALUE_MAX]; |
| 150 | string init_svc = "init.svc." + initrc_svc; |
| 151 | property_get(init_svc.c_str(), prop_value, "error"); |
| 152 | return (strcmp(prop_value, "error") != 0); |
| 153 | } |
| 154 | |
| 155 | bool Is_Service_Running(string initrc_svc) { |
| 156 | char prop_value[PROPERTY_VALUE_MAX]; |
| 157 | string init_svc = "init.svc." + initrc_svc; |
| 158 | property_get(init_svc.c_str(), prop_value, "error"); |
| 159 | return (strcmp(prop_value, "running") == 0); |
| 160 | } |
| 161 | |
| 162 | bool Is_Service_Stopped(string initrc_svc) { |
| 163 | char prop_value[PROPERTY_VALUE_MAX]; |
| 164 | string init_svc = "init.svc." + initrc_svc; |
| 165 | property_get(init_svc.c_str(), prop_value, "error"); |
| 166 | return (strcmp(prop_value, "stopped") == 0); |
| 167 | } |
| 168 | |
| 169 | bool Start_Service(string initrc_svc, int utimeout = SLEEP_MAX_USEC) { |
| 170 | string res = "error"; |
| 171 | string init_svc = "init.svc." + initrc_svc; |
| 172 | |
| 173 | property_set("ctl.start", initrc_svc.c_str()); |
| 174 | |
| 175 | res = wait_for_property(init_svc, utimeout, "running"); |
| 176 | |
| 177 | LOGDECRYPT("Start service %s: %s.\n", initrc_svc.c_str(), res.c_str()); |
| 178 | |
| 179 | return (res == "running"); |
| 180 | } |
| 181 | |
| 182 | bool Stop_Service(string initrc_svc, int utimeout = SLEEP_MAX_USEC) { |
| 183 | string res = "error"; |
| 184 | |
| 185 | if (Service_Exists(initrc_svc)) { |
| 186 | string init_svc = "init.svc." + initrc_svc; |
| 187 | property_set("ctl.stop", initrc_svc.c_str()); |
| 188 | res = wait_for_property(init_svc, utimeout, "stopped"); |
| 189 | LOGDECRYPT("Stop service %s: %s.\n", initrc_svc.c_str(), res.c_str()); |
| 190 | } |
| 191 | |
| 192 | return (res == "stopped"); |
| 193 | } |
| 194 | |
| 195 | void output_dmesg_to_recoverylog(void) { |
| 196 | TWFunc::Exec_Cmd( |
| 197 | "echo \"---- DMESG LOG FOLLOWS ----\";" |
| 198 | "dmesg | grep 'DECRYPT\\|vold\\|qseecom\\|QSEECOM\\|keymaste\\|keystore\\|cmnlib';" |
| 199 | "echo \"---- DMESG LOG ENDS ----\"" |
| 200 | ); |
| 201 | } |
| 202 | |
| 203 | void set_needed_props(void) { |
| 204 | // vold won't start without ro.storage_structure on Kitkat |
| 205 | string sdkverstr = TWFunc::System_Property_Get("ro.build.version.sdk"); |
| 206 | int sdkver = 20; |
| 207 | if (!sdkverstr.empty()) { |
| 208 | sdkver = atoi(sdkverstr.c_str()); |
| 209 | } |
| 210 | if (sdkver <= 19) { |
| 211 | string ro_storage_structure = TWFunc::System_Property_Get("ro.storage_structure"); |
| 212 | if (!ro_storage_structure.empty()) |
| 213 | property_set("ro.storage_structure", ro_storage_structure.c_str()); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | string vdc_cryptfs_cmd(string log_name) { |
nkk71 | 201d4b2 | 2017-03-06 22:06:31 +0200 | [diff] [blame^] | 218 | string cmd = "LD_LIBRARY_PATH=/system/lib64:/system/lib /system/bin/vdc cryptfs"; |
nkk71 | 71c6c50 | 2017-01-05 23:55:05 +0200 | [diff] [blame] | 219 | |
nkk71 | 201d4b2 | 2017-03-06 22:06:31 +0200 | [diff] [blame^] | 220 | #ifndef TW_CRYPTO_SYSTEM_VOLD_DEBUG |
| 221 | (void)log_name; // do nothing, but get rid of compiler warning in non debug builds |
| 222 | #else |
nkk71 | 71c6c50 | 2017-01-05 23:55:05 +0200 | [diff] [blame] | 223 | if (has_timeout && has_strace) |
| 224 | cmd = "/sbin/strace -q -tt -ff -v -y -s 1000 -o /tmp/strace_vdc_" + log_name + " /sbin/timeout -t 30 -s KILL env " + cmd; |
| 225 | else if (has_strace) |
| 226 | cmd = "/sbin/strace -q -tt -ff -v -y -s 1000 -o /tmp/strace_vdc_" + log_name + " -E " + cmd; |
| 227 | else |
| 228 | #endif |
| 229 | if (has_timeout) |
| 230 | cmd = "/sbin/timeout -t 30 -s KILL env " + cmd; |
| 231 | |
| 232 | return cmd; |
| 233 | } |
| 234 | |
| 235 | int run_vdc(string Password) { |
| 236 | int res = -1; |
| 237 | struct timeval t1, t2; |
| 238 | string vdc_res; |
| 239 | int vdc_r1, vdc_r2, vdc_r3; |
| 240 | |
| 241 | LOGDECRYPT("About to run vdc...\n"); |
| 242 | |
| 243 | // Wait for vold connection |
| 244 | gettimeofday(&t1, NULL); |
| 245 | t2 = t1; |
| 246 | while ((t2.tv_sec - t1.tv_sec) < 5) { |
| 247 | vdc_res.clear(); |
| 248 | // cryptfs getpwtype returns: R1=213(PasswordTypeResult) R2=? R3="password", "pattern", "pin", "default" |
| 249 | res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("connect") + " getpwtype", vdc_res); |
| 250 | std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) |
| 251 | vdc_r1 = vdc_r2 = vdc_r3 = -1; |
| 252 | sscanf(vdc_res.c_str(), "%d", &vdc_r1); |
| 253 | if (vdc_r1 == 213) { |
| 254 | char str_res[sizeof(int) + 1]; |
| 255 | snprintf(str_res, sizeof(str_res), "%d", res); |
| 256 | vdc_res += "ret="; |
| 257 | vdc_res += str_res; |
| 258 | res = 0; |
| 259 | break; |
| 260 | } |
| 261 | LOGDECRYPT("Retrying connection to vold\n"); |
| 262 | usleep(SLEEP_MIN_USEC); // vdc usually usleep(10000), but that causes too many unnecessary attempts |
| 263 | gettimeofday(&t2, NULL); |
| 264 | } |
| 265 | |
| 266 | if (res != 0) |
| 267 | return res; |
| 268 | |
| 269 | LOGDECRYPT("Connected to vold (%s)\n", vdc_res.c_str()); |
| 270 | |
| 271 | // Input password from GUI, or default password |
| 272 | vdc_res.clear(); |
| 273 | res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("passwd") + " checkpw '" + Password + "'", vdc_res); |
| 274 | std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) |
| 275 | LOGDECRYPT("vdc cryptfs result (passwd): %s (ret=%d)\n", vdc_res.c_str(), res); |
| 276 | vdc_r1 = vdc_r2 = vdc_r3 = -1; |
| 277 | sscanf(vdc_res.c_str(), "%d %d %d", &vdc_r1, &vdc_r2, &vdc_r3); |
| 278 | |
| 279 | if (vdc_r3 != 0) { |
| 280 | // try falling back to Lollipop hex passwords |
| 281 | string hexPassword = convert_key_to_hex_ascii(Password); |
| 282 | vdc_res.clear(); |
| 283 | res = TWFunc::Exec_Cmd(vdc_cryptfs_cmd("hex_pw") + " checkpw '" + hexPassword + "'", vdc_res); |
| 284 | std::replace(vdc_res.begin(), vdc_res.end(), '\n', ' '); // remove newline(s) |
| 285 | LOGDECRYPT("vdc cryptfs result (hex_pw): %s (ret=%d)\n", vdc_res.c_str(), res); |
| 286 | vdc_r1 = vdc_r2 = vdc_r3 = -1; |
| 287 | sscanf(vdc_res.c_str(), "%d %d %d", &vdc_r1, &vdc_r2, &vdc_r3); |
| 288 | } |
| 289 | |
| 290 | // vdc's return value is dependant upon source origin, it will either |
| 291 | // return 0 or vdc_r1, so disregard and focus on decryption instead |
| 292 | if (vdc_r3 == 0) { |
| 293 | // Decryption successful wait for crypto blk dev |
| 294 | wait_for_property("ro.crypto.fs_crypto_blkdev"); |
| 295 | res = 0; |
| 296 | } else { |
| 297 | res = -1; |
| 298 | } |
| 299 | |
| 300 | return res; |
| 301 | } |
| 302 | |
| 303 | bool Symlink_Vendor_Folder(void) { |
| 304 | bool is_vendor_symlinked = false; |
| 305 | |
| 306 | if (PartitionManager.Is_Mounted_By_Path("/vendor")) { |
| 307 | LOGDECRYPT("vendor partition mounted, skipping /vendor substitution\n"); |
| 308 | } |
| 309 | else if (TWFunc::Path_Exists("/system/vendor")) { |
| 310 | LOGDECRYPT("Symlinking vendor folder...\n"); |
| 311 | if (TWFunc::Path_Exists("/vendor") && rename("/vendor", "/vendor-orig") != 0) { |
| 312 | LOGDECRYPT("Failed to rename original /vendor folder: %s\n", strerror(errno)); |
| 313 | } else { |
| 314 | TWFunc::Recursive_Mkdir("/vendor/firmware/keymaster"); |
| 315 | LOGDECRYPT_KMSG("Symlinking /system/vendor/lib64 to /vendor/lib64 (res=%d)\n", |
| 316 | symlink("/system/vendor/lib64", "/vendor/lib64") |
| 317 | ); |
| 318 | LOGDECRYPT_KMSG("Symlinking /system/vendor/lib to /vendor/lib (res=%d)\n", |
| 319 | symlink("/system/vendor/lib", "/vendor/lib") |
| 320 | ); |
| 321 | is_vendor_symlinked = true; |
| 322 | property_set("vold_decrypt.symlinked_vendor", "1"); |
| 323 | } |
| 324 | } |
| 325 | return is_vendor_symlinked; |
| 326 | } |
| 327 | |
| 328 | void Restore_Vendor_Folder(void) { |
| 329 | property_set("vold_decrypt.symlinked_vendor", "0"); |
| 330 | TWFunc::removeDir("/vendor", false); |
| 331 | rename("/vendor-orig", "/vendor"); |
| 332 | } |
| 333 | |
| 334 | bool Symlink_Firmware_Folder(void) { |
| 335 | bool is_firmware_symlinked = false; |
| 336 | |
| 337 | if (PartitionManager.Is_Mounted_By_Path("/firmware")) { |
| 338 | LOGDECRYPT("firmware partition mounted, skipping /firmware substitution\n"); |
| 339 | } else { |
| 340 | LOGDECRYPT("Symlinking firmware folder...\n"); |
| 341 | if (TWFunc::Path_Exists("/firmware") && rename("/firmware", "/firmware-orig") != 0) { |
| 342 | LOGDECRYPT("Failed to rename original /firmware folder: %s\n", strerror(errno)); |
| 343 | } else { |
| 344 | TWFunc::Recursive_Mkdir("/firmware/image"); |
| 345 | is_firmware_symlinked = true; |
| 346 | property_set("vold_decrypt.symlinked_firmware", "1"); |
| 347 | } |
| 348 | } |
| 349 | return is_firmware_symlinked; |
| 350 | } |
| 351 | |
| 352 | void Restore_Firmware_Folder(void) { |
| 353 | property_set("vold_decrypt.symlinked_firmware", "0"); |
| 354 | TWFunc::removeDir("/firmware", false); |
| 355 | rename("/firmware-orig", "/firmware"); |
| 356 | } |
| 357 | |
| 358 | void Symlink_Firmware_Files(bool is_vendor_symlinked, bool is_firmware_symlinked) { |
| 359 | if (!is_vendor_symlinked && !is_firmware_symlinked) |
| 360 | return; |
| 361 | |
| 362 | LOGDECRYPT("Symlinking firmware files...\n"); |
| 363 | string result_of_find; |
| 364 | TWFunc::Exec_Cmd("find /system -name keymaste*.* -type f -o -name cmnlib.* -type f 2>/dev/null", result_of_find); |
| 365 | |
| 366 | stringstream ss(result_of_find); |
| 367 | string line; |
| 368 | int count = 0; |
| 369 | |
| 370 | while(getline(ss, line)) { |
| 371 | const char *fwfile = line.c_str(); |
| 372 | string base_name = TWFunc::Get_Filename(line); |
| 373 | count++; |
| 374 | |
| 375 | if (is_firmware_symlinked) { |
| 376 | LOGDECRYPT_KMSG("Symlinking %s to /firmware/image/ (res=%d)\n", fwfile, |
| 377 | symlink(fwfile, ("/firmware/image/" + base_name).c_str()) |
| 378 | ); |
| 379 | } |
| 380 | |
| 381 | if (is_vendor_symlinked) { |
| 382 | LOGDECRYPT_KMSG("Symlinking %s to /vendor/firmware/ (res=%d)\n", fwfile, |
| 383 | symlink(fwfile, ("/vendor/firmware/" + base_name).c_str()) |
| 384 | ); |
| 385 | |
| 386 | LOGDECRYPT_KMSG("Symlinking %s to /vendor/firmware/keymaster/ (res=%d)\n", fwfile, |
| 387 | symlink(fwfile, ("/vendor/firmware/keymaster/" + base_name).c_str()) |
| 388 | ); |
| 389 | } |
| 390 | } |
| 391 | LOGDECRYPT("%d file(s) symlinked.\n", count); |
| 392 | } |
| 393 | |
| 394 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 395 | vector<AdditionalService> Get_List_Of_Additional_Services (void) { |
| 396 | vector<AdditionalService> services; |
| 397 | |
| 398 | vector<string> service_names = TWFunc::Split_String(TW_CRYPTO_SYSTEM_VOLD_SERVICES, " "); |
| 399 | |
| 400 | for (size_t i = 0; i < service_names.size(); ++i) { |
| 401 | AdditionalService svc; |
| 402 | svc.service_name = service_names[i]; |
| 403 | services.push_back(svc); |
| 404 | } |
| 405 | |
| 406 | return services; |
| 407 | } |
| 408 | #endif |
| 409 | |
| 410 | int vold_decrypt(string Password) |
| 411 | { |
| 412 | int res; |
| 413 | bool output_dmesg_to_log = false; |
| 414 | bool is_vendor_symlinked = false; |
| 415 | bool is_firmware_symlinked = false; |
| 416 | bool is_vold_running = false; |
| 417 | |
| 418 | if (Password.empty()) { |
| 419 | LOGDECRYPT("vold_decrypt: password is empty!\n"); |
| 420 | return -1; |
| 421 | } |
| 422 | |
| 423 | // Mount system and check for vold and vdc |
| 424 | if (!PartitionManager.Mount_By_Path("/system", true)) { |
| 425 | return -1; |
| 426 | } else if (!TWFunc::Path_Exists("/system/bin/vold")) { |
| 427 | LOGDECRYPT("ERROR: /system/bin/vold not found, aborting.\n"); |
| 428 | gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vold")); |
| 429 | return -1; |
| 430 | } else if (!TWFunc::Path_Exists("/system/bin/vdc")) { |
| 431 | LOGDECRYPT("ERROR: /system/bin/vdc not found, aborting.\n"); |
| 432 | gui_msg(Msg(msg::kError, "decrypt_data_vold_os_missing=Missing files needed for vold decrypt: {1}")("/system/bin/vdc")); |
| 433 | return -1; |
| 434 | } |
| 435 | |
| 436 | fp_kmsg = fopen("/dev/kmsg", "a"); |
| 437 | |
| 438 | LOGDECRYPT("TW_CRYPTO_USE_SYSTEM_VOLD := true\n"); |
| 439 | LOGDECRYPT("Attempting to use system's vold for decryption...\n"); |
| 440 | |
| 441 | #ifndef TW_CRYPTO_SYSTEM_VOLD_DISABLE_TIMEOUT |
| 442 | has_timeout = TWFunc::Path_Exists("/sbin/timeout"); |
| 443 | if (!has_timeout) |
| 444 | LOGDECRYPT("timeout binary not found, disabling timeout in vold_decrypt!\n"); |
| 445 | #endif |
| 446 | |
| 447 | #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG |
| 448 | has_strace = TWFunc::Path_Exists("/sbin/strace"); |
| 449 | if (!has_strace) |
| 450 | LOGDECRYPT("strace binary not found, disabling strace in vold_decrypt!\n"); |
| 451 | pid_t pid_strace = strace_init(); |
| 452 | #endif |
| 453 | |
| 454 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 455 | vector<AdditionalService> Services = Get_List_Of_Additional_Services(); |
| 456 | |
| 457 | // Check if TWRP is running any of the services |
| 458 | for (size_t i = 0; i < Services.size(); ++i) { |
| 459 | if (Service_Exists(Services[i].service_name)) |
| 460 | Services[i].twrp_svc_name = Services[i].service_name; |
| 461 | else if (Service_Exists("sbin" + Services[i].service_name)) |
| 462 | Services[i].twrp_svc_name = "sbin" + Services[i].service_name; |
| 463 | else |
| 464 | Services[i].twrp_svc_name.clear(); |
| 465 | |
| 466 | if (!Services[i].twrp_svc_name.empty() && !Is_Service_Stopped(Services[i].twrp_svc_name)) { |
| 467 | Services[i].resume = true; |
| 468 | Stop_Service(Services[i].twrp_svc_name); |
| 469 | } else |
| 470 | Services[i].resume = false; |
| 471 | |
| 472 | // vold_decrypt system services have to be named sys_{service} in the .rc files |
| 473 | Services[i].service_name = "sys_" + Services[i].service_name; |
| 474 | } |
| 475 | #endif |
| 476 | |
| 477 | LOGDECRYPT("Setting up folders and permissions...\n"); |
| 478 | is_vendor_symlinked = Symlink_Vendor_Folder(); |
| 479 | is_firmware_symlinked = Symlink_Firmware_Folder(); |
| 480 | Symlink_Firmware_Files(is_vendor_symlinked, is_firmware_symlinked); |
| 481 | |
| 482 | set_needed_props(); |
| 483 | |
| 484 | // Start services needed for vold decrypt |
| 485 | LOGDECRYPT("Starting services...\n"); |
| 486 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 487 | for (size_t i = 0; i < Services.size(); ++i) { |
| 488 | Services[i].is_running = Start_Service(Services[i].service_name); |
| 489 | } |
| 490 | #endif |
| 491 | is_vold_running = Start_Service("sys_vold"); |
| 492 | |
| 493 | if (is_vold_running) { |
| 494 | |
| 495 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 496 | for (size_t i = 0; i < Services.size(); ++i) { |
| 497 | if (!Is_Service_Running(Services[i].service_name) && Services[i].resume) { |
| 498 | // if system_service has died restart the twrp_service |
| 499 | LOGDECRYPT("%s is not running, resuming %s!\n", Services[i].service_name.c_str(), Services[i].twrp_svc_name.c_str()); |
| 500 | Start_Service(Services[i].twrp_svc_name); |
| 501 | } |
| 502 | } |
| 503 | #endif |
| 504 | |
| 505 | res = run_vdc(Password); |
| 506 | |
| 507 | if (res != 0) { |
| 508 | // Decryption was unsuccessful |
| 509 | LOGDECRYPT("Decryption failed\n"); |
| 510 | output_dmesg_to_log = true; |
| 511 | } |
| 512 | } else { |
| 513 | LOGDECRYPT("Failed to start vold\n"); |
| 514 | TWFunc::Exec_Cmd("echo \"$(getprop | grep init.svc)\" >> /dev/kmsg"); |
| 515 | output_dmesg_to_log = true; |
| 516 | } |
| 517 | |
| 518 | // Stop services needed for vold decrypt so /system can be unmounted |
| 519 | LOGDECRYPT("Stopping services...\n"); |
| 520 | Stop_Service("sys_vold"); |
| 521 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 522 | for (size_t i = 0; i < Services.size(); ++i) { |
| 523 | if (!Is_Service_Running(Services[i].service_name) && Services[i].resume) |
| 524 | Stop_Service(Services[i].twrp_svc_name); |
| 525 | else |
| 526 | Stop_Service(Services[i].service_name); |
| 527 | } |
| 528 | #endif |
| 529 | |
| 530 | if (is_firmware_symlinked) |
| 531 | Restore_Firmware_Folder(); |
| 532 | if (is_vendor_symlinked) |
| 533 | Restore_Vendor_Folder(); |
| 534 | |
| 535 | if (!PartitionManager.UnMount_By_Path("/system", true)) { |
| 536 | // PartitionManager failed to unmount /system, this should not happen, |
| 537 | // but in case it does, do a lazy unmount |
| 538 | LOGDECRYPT("WARNING: system could not be unmounted normally!\n"); |
| 539 | TWFunc::Exec_Cmd("umount -l /system"); |
| 540 | } |
| 541 | |
| 542 | LOGDECRYPT("Finished.\n"); |
| 543 | |
| 544 | #ifdef TW_CRYPTO_SYSTEM_VOLD_SERVICES |
| 545 | // Restart previously running services |
| 546 | for (size_t i = 0; i < Services.size(); ++i) { |
| 547 | if (Services[i].resume) |
| 548 | Start_Service(Services[i].twrp_svc_name); |
| 549 | } |
| 550 | #endif |
| 551 | |
| 552 | #ifdef TW_CRYPTO_SYSTEM_VOLD_DEBUG |
| 553 | if (pid_strace > 0) { |
| 554 | LOGDECRYPT_KMSG("Stopping strace_init (pid=%d)\n", pid_strace); |
nkk71 | 71c6c50 | 2017-01-05 23:55:05 +0200 | [diff] [blame] | 555 | int timeout; |
| 556 | int status; |
| 557 | pid_t retpid = waitpid(pid_strace, &status, WNOHANG); |
| 558 | |
| 559 | kill(pid_strace, SIGTERM); |
| 560 | for (timeout = 5; retpid == 0 && timeout; --timeout) { |
| 561 | sleep(1); |
| 562 | retpid = waitpid(pid_strace, &status, WNOHANG); |
| 563 | } |
| 564 | if (retpid) |
| 565 | LOGDECRYPT_KMSG("strace_init terminated successfully\n"); |
| 566 | else { |
| 567 | // SIGTERM didn't work, kill it instead |
| 568 | kill(pid_strace, SIGKILL); |
| 569 | for (timeout = 5; retpid == 0 && timeout; --timeout) { |
| 570 | sleep(1); |
| 571 | retpid = waitpid(pid_strace, &status, WNOHANG); |
| 572 | } |
| 573 | if (retpid) |
| 574 | LOGDECRYPT_KMSG("strace_init killed successfully\n"); |
| 575 | else |
| 576 | LOGDECRYPT_KMSG("strace_init took too long to kill, may be a zombie process\n"); |
| 577 | } |
| 578 | } |
| 579 | output_dmesg_to_log = true; |
| 580 | #endif |
| 581 | |
| 582 | // Finish up and exit |
| 583 | if (fp_kmsg) { |
| 584 | fflush(fp_kmsg); |
| 585 | fclose(fp_kmsg); |
| 586 | } |
| 587 | |
| 588 | if (output_dmesg_to_log) |
| 589 | output_dmesg_to_recoverylog(); |
| 590 | |
| 591 | // Finally check if crypto device is up |
| 592 | if (wait_for_property("ro.crypto.fs_crypto_blkdev", 0) != "error") |
| 593 | res = 0; |
| 594 | else |
| 595 | res = -1; |
| 596 | |
| 597 | return res; |
| 598 | } |