summaryrefslogtreecommitdiffstats
path: root/recovery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp133
1 files changed, 103 insertions, 30 deletions
diff --git a/recovery.cpp b/recovery.cpp
index 6b6643fab..79b99b176 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -19,7 +19,9 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <inttypes.h>
#include <limits.h>
+#include <linux/fs.h>
#include <linux/input.h>
#include <stdarg.h>
#include <stdio.h>
@@ -33,18 +35,23 @@
#include <unistd.h>
#include <chrono>
+#include <string>
+#include <vector>
#include <adb.h>
#include <android/log.h> /* Android Log Priority Tags */
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
#include <cutils/properties.h>
+#include <healthd/BatteryMonitor.h>
#include <log/logger.h> /* Android Log packet format */
#include <private/android_logger.h> /* private pmsg functions */
-
-#include <healthd/BatteryMonitor.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "adb_install.h"
#include "bootloader.h"
@@ -63,7 +70,6 @@
struct selabel_handle *sehandle;
static const struct option OPTIONS[] = {
- { "send_intent", required_argument, NULL, 'i' },
{ "update_package", required_argument, NULL, 'u' },
{ "retry_count", required_argument, NULL, 'n' },
{ "wipe_data", no_argument, NULL, 'w' },
@@ -77,12 +83,12 @@ static const struct option OPTIONS[] = {
{ "shutdown_after", no_argument, NULL, 'p' },
{ "reason", required_argument, NULL, 'r' },
{ "security", no_argument, NULL, 'e'},
+ { "brick", no_argument, NULL, 0 },
{ NULL, 0, NULL, 0 },
};
static const char *CACHE_LOG_DIR = "/cache/recovery";
static const char *COMMAND_FILE = "/cache/recovery/command";
-static const char *INTENT_FILE = "/cache/recovery/intent";
static const char *LOG_FILE = "/cache/recovery/log";
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
static const char *LOCALE_FILE = "/cache/recovery/last_locale";
@@ -103,6 +109,7 @@ static const int BATTERY_READ_TIMEOUT_IN_SEC = 10;
// So we should check battery with a slightly lower limitation.
static const int BATTERY_OK_PERCENTAGE = 20;
static const int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
+constexpr const char* RECOVERY_BRICK = "/etc/recovery.brick";
RecoveryUI* ui = NULL;
static const char* locale = "en_US";
@@ -115,10 +122,8 @@ static bool has_cache = false;
* The recovery tool communicates with the main system through /cache files.
* /cache/recovery/command - INPUT - command line for tool, one arg per line
* /cache/recovery/log - OUTPUT - combined log file from recovery run(s)
- * /cache/recovery/intent - OUTPUT - intent that was passed in
*
* The arguments which may be supplied in the recovery.command file:
- * --send_intent=anystring - write the text out to recovery.intent
* --update_package=path - verify install an OTA package file
* --wipe_data - erase user data (and cache), then reboot
* --wipe_cache - wipe cache (but not user data), then reboot
@@ -399,7 +404,7 @@ static void copy_log_file_to_pmsg(const char* source, const char* destination) {
}
// How much of the temp log we have copied to the copy in cache.
-static long tmplog_offset = 0;
+static off_t tmplog_offset = 0;
static void copy_log_file(const char* source, const char* destination, bool append) {
FILE* dest_fp = fopen_path(destination, append ? "a" : "w");
@@ -409,7 +414,7 @@ static void copy_log_file(const char* source, const char* destination, bool appe
FILE* source_fp = fopen(source, "r");
if (source_fp != nullptr) {
if (append) {
- fseek(source_fp, tmplog_offset, SEEK_SET); // Since last write
+ fseeko(source_fp, tmplog_offset, SEEK_SET); // Since last write
}
char buf[4096];
size_t bytes;
@@ -417,7 +422,7 @@ static void copy_log_file(const char* source, const char* destination, bool appe
fwrite(buf, 1, bytes, dest_fp);
}
if (append) {
- tmplog_offset = ftell(source_fp);
+ tmplog_offset = ftello(source_fp);
}
check_and_fclose(source_fp, source);
}
@@ -491,22 +496,10 @@ static void copy_logs() {
}
// clear the recovery command and prepare to boot a (hopefully working) system,
-// copy our log file to cache as well (for the system to read), and
-// record any intent we were asked to communicate back to the system.
-// this function is idempotent: call it as many times as you like.
+// copy our log file to cache as well (for the system to read). This function is
+// idempotent: call it as many times as you like.
static void
-finish_recovery(const char *send_intent) {
- // By this point, we're ready to return to the main system...
- if (send_intent != NULL && has_cache) {
- FILE *fp = fopen_path(INTENT_FILE, "w");
- if (fp == NULL) {
- LOGE("Can't open %s\n", INTENT_FILE);
- } else {
- fputs(send_intent, fp);
- check_and_fclose(fp, INTENT_FILE);
- }
- }
-
+finish_recovery() {
// Save the locale to cache, so if recovery is next started up
// without a --locale argument (eg, directly from the bootloader)
// it will use the last-known locale.
@@ -853,6 +846,75 @@ static bool wipe_cache(bool should_confirm, Device* device) {
return success;
}
+// Secure-wipe a given partition. It uses BLKSECDISCARD, if supported.
+// Otherwise, it goes with BLKDISCARD (if device supports BLKDISCARDZEROES) or
+// BLKZEROOUT.
+static bool secure_wipe_partition(const std::string& partition) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(partition.c_str(), O_WRONLY)));
+ if (fd == -1) {
+ LOGE("failed to open \"%s\": %s\n", partition.c_str(), strerror(errno));
+ return false;
+ }
+
+ uint64_t range[2] = {0, 0};
+ if (ioctl(fd, BLKGETSIZE64, &range[1]) == -1 || range[1] == 0) {
+ LOGE("failed to get partition size: %s\n", strerror(errno));
+ return false;
+ }
+ printf("Secure-wiping \"%s\" from %" PRIu64 " to %" PRIu64 ".\n",
+ partition.c_str(), range[0], range[1]);
+
+ printf("Trying BLKSECDISCARD...\t");
+ if (ioctl(fd, BLKSECDISCARD, &range) == -1) {
+ printf("failed: %s\n", strerror(errno));
+
+ // Use BLKDISCARD if it zeroes out blocks, otherwise use BLKZEROOUT.
+ unsigned int zeroes;
+ if (ioctl(fd, BLKDISCARDZEROES, &zeroes) == 0 && zeroes != 0) {
+ printf("Trying BLKDISCARD...\t");
+ if (ioctl(fd, BLKDISCARD, &range) == -1) {
+ printf("failed: %s\n", strerror(errno));
+ return false;
+ }
+ } else {
+ printf("Trying BLKZEROOUT...\t");
+ if (ioctl(fd, BLKZEROOUT, &range) == -1) {
+ printf("failed: %s\n", strerror(errno));
+ return false;
+ }
+ }
+ }
+
+ printf("done\n");
+ return true;
+}
+
+// Brick the current device, with a secure wipe of all the partitions in
+// RECOVERY_BRICK.
+static bool brick_device() {
+ ui->SetBackground(RecoveryUI::ERASING);
+ ui->SetProgressType(RecoveryUI::INDETERMINATE);
+
+ std::string partition_list;
+ if (!android::base::ReadFileToString(RECOVERY_BRICK, &partition_list)) {
+ LOGE("failed to read \"%s\".\n", RECOVERY_BRICK);
+ return false;
+ }
+
+ std::vector<std::string> lines = android::base::Split(partition_list, "\n");
+ for (const std::string& line : lines) {
+ std::string partition = android::base::Trim(line);
+ // Ignore '#' comment or empty lines.
+ if (android::base::StartsWith(partition, "#") || partition.empty()) {
+ continue;
+ }
+
+ // Proceed anyway even if it fails to wipe some partition.
+ secure_wipe_partition(partition);
+ }
+ return true;
+}
+
static void choose_recovery_file(Device* device) {
if (!has_cache) {
ui->Print("No /cache partition found.\n");
@@ -1028,7 +1090,7 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
static Device::BuiltinAction
prompt_and_wait(Device* device, int status) {
for (;;) {
- finish_recovery(NULL);
+ finish_recovery();
switch (status) {
case INSTALL_SUCCESS:
case INSTALL_NONE:
@@ -1290,7 +1352,7 @@ static ssize_t logrotate(
if (!isdigit(number.data()[0])) {
name += ".1";
} else {
- unsigned long long i = std::stoull(number);
+ auto i = std::stoull(number);
name = sub + "." + std::to_string(i + 1);
}
}
@@ -1336,10 +1398,10 @@ int main(int argc, char **argv) {
get_args(&argc, &argv);
- const char *send_intent = NULL;
const char *update_package = NULL;
bool should_wipe_data = false;
bool should_wipe_cache = false;
+ bool should_brick = false;
bool show_text = false;
bool sideload = false;
bool sideload_auto_reboot = false;
@@ -1349,9 +1411,9 @@ int main(int argc, char **argv) {
bool security_update = false;
int arg;
- while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
+ int option_index;
+ while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
switch (arg) {
- case 'i': send_intent = optarg; break;
case 'n': android::base::ParseInt(optarg, &retry_count, 0); break;
case 'u': update_package = optarg; break;
case 'w': should_wipe_data = true; break;
@@ -1372,6 +1434,13 @@ int main(int argc, char **argv) {
case 'p': shutdown_after = true; break;
case 'r': reason = optarg; break;
case 'e': security_update = true; break;
+ case 0: {
+ if (strcmp(OPTIONS[option_index].name, "brick") == 0) {
+ should_brick = true;
+ break;
+ }
+ break;
+ }
case '?':
LOGE("Invalid command argument\n");
continue;
@@ -1510,6 +1579,10 @@ int main(int argc, char **argv) {
if (!wipe_cache(false, device)) {
status = INSTALL_ERROR;
}
+ } else if (should_brick) {
+ if (!brick_device()) {
+ status = INSTALL_ERROR;
+ }
} else if (sideload) {
// 'adb reboot sideload' acts the same as user presses key combinations
// to enter the sideload mode. When 'sideload-auto-reboot' is used, text
@@ -1557,7 +1630,7 @@ int main(int argc, char **argv) {
}
// Save logs and clean up before rebooting or shutting down.
- finish_recovery(send_intent);
+ finish_recovery();
switch (after) {
case Device::SHUTDOWN: