remove retouching code from updater
Removes the retouch_binaries and undo_retouch_binaries from updater; newly generated OTA packages should not call them any more. Note that applypatch retains the ability to unretouch a file as it reads it. This will be needed as long as we want to support OTAs from devices that were installed with retouching. Change-Id: Ib3f6baeae90c84ba85983f626d821ab7e436ceb2
This commit is contained in:
parent
b07b293944
commit
35a35a6766
3 changed files with 0 additions and 334 deletions
210
minelf/Retouch.c
210
minelf/Retouch.c
|
@ -194,213 +194,3 @@ int retouch_mask_data(uint8_t *binary_object,
|
|||
if (retouch_offset != NULL) *retouch_offset = offset_candidate;
|
||||
return RETOUCH_DATA_MATCHED;
|
||||
}
|
||||
|
||||
// On success, _override is set to the offset that was actually applied.
|
||||
// This implies that once we randomize to an offset we stick with it.
|
||||
// This in turn is necessary in order to guarantee recovery after crash.
|
||||
bool retouch_one_library(const char *binary_name,
|
||||
const char *binary_sha1,
|
||||
int32_t retouch_offset,
|
||||
int32_t *retouch_offset_override) {
|
||||
bool success = true;
|
||||
int result;
|
||||
|
||||
FileContents file;
|
||||
file.data = NULL;
|
||||
|
||||
char binary_name_atomic[strlen(binary_name)+10];
|
||||
strcpy(binary_name_atomic, binary_name);
|
||||
strcat(binary_name_atomic, ".atomic");
|
||||
|
||||
// We need a path that exists for calling statfs() later.
|
||||
//
|
||||
// Assume that binary_name (eg "/system/app/Foo.apk") is located
|
||||
// on the same filesystem as its top-level directory ("/system").
|
||||
char target_fs[strlen(binary_name)+1];
|
||||
char* slash = strchr(binary_name+1, '/');
|
||||
if (slash != NULL) {
|
||||
int count = slash - binary_name;
|
||||
strncpy(target_fs, binary_name, count);
|
||||
target_fs[count] = '\0';
|
||||
} else {
|
||||
strcpy(target_fs, binary_name);
|
||||
}
|
||||
|
||||
result = LoadFileContents(binary_name, &file, RETOUCH_DONT_MASK);
|
||||
|
||||
if (result == 0) {
|
||||
// Figure out the *apparent* offset to which this file has been
|
||||
// retouched. If it looks good, we will skip processing (we might
|
||||
// have crashed and during this recovery pass we don't want to
|
||||
// overwrite a valuable saved file in /cache---which would happen
|
||||
// if we blindly retouch everything again). NOTE: This implies
|
||||
// that we might have to override the supplied retouch offset. We
|
||||
// can do the override only once though: everything should match
|
||||
// afterward.
|
||||
|
||||
int32_t inferred_offset;
|
||||
int retouch_probe_result = retouch_mask_data(file.data,
|
||||
file.size,
|
||||
NULL,
|
||||
&inferred_offset);
|
||||
|
||||
if (retouch_probe_result == RETOUCH_DATA_MATCHED) {
|
||||
if ((retouch_offset == inferred_offset) ||
|
||||
((retouch_offset != 0 && inferred_offset != 0) &&
|
||||
(retouch_offset_override != NULL))) {
|
||||
// This file is OK already and we are allowed to override.
|
||||
// Let's just return the offset override value. It is critical
|
||||
// to skip regardless of override: a broken file might need
|
||||
// recovery down the list and we should not mess up the saved
|
||||
// copy by doing unnecessary retouching.
|
||||
//
|
||||
// NOTE: If retouching was already started with a different
|
||||
// value, we will not be allowed to override. This happens
|
||||
// if on the retouch list there is a patched binary (which is
|
||||
// masked in apply_patch()) before there is a non-patched
|
||||
// binary.
|
||||
if (retouch_offset_override != NULL)
|
||||
*retouch_offset_override = inferred_offset;
|
||||
success = true;
|
||||
goto out;
|
||||
} else {
|
||||
// Retouch to zero (mask the retouching), to make sure that
|
||||
// the SHA-1 check will pass below.
|
||||
int32_t zero = 0;
|
||||
retouch_mask_data(file.data, file.size, &zero, NULL);
|
||||
SHA(file.data, file.size, file.sha1);
|
||||
}
|
||||
}
|
||||
|
||||
if (retouch_probe_result == RETOUCH_DATA_NOTAPPLICABLE) {
|
||||
// In the case of not retouchable, fake it. We do not want
|
||||
// to do the normal processing and overwrite the backup file:
|
||||
// we might be recovering!
|
||||
//
|
||||
// We return a zero override, which tells the caller that we
|
||||
// simply skipped the file.
|
||||
if (retouch_offset_override != NULL)
|
||||
*retouch_offset_override = 0;
|
||||
success = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// If we get here, either there was a mismatch in the offset, or
|
||||
// the file has not been processed yet. Continue with normal
|
||||
// processing.
|
||||
}
|
||||
|
||||
if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
|
||||
free(file.data);
|
||||
printf("Attempting to recover source from '%s' ...\n",
|
||||
CACHE_TEMP_SOURCE);
|
||||
result = LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK);
|
||||
if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
|
||||
printf(" failed.\n");
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
printf(" succeeded.\n");
|
||||
}
|
||||
|
||||
// Retouch in-memory before worrying about backing up the original.
|
||||
//
|
||||
// Recovery steps will be oblivious to the actual retouch offset used,
|
||||
// so might as well write out the already-retouched copy. Then, in the
|
||||
// usual case, we will just swap the file locally, with no more writes
|
||||
// needed. In the no-free-space case, we will then write the same to the
|
||||
// original location.
|
||||
|
||||
result = retouch_mask_data(file.data, file.size, &retouch_offset, NULL);
|
||||
if (result != RETOUCH_DATA_MATCHED) {
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
if (retouch_offset_override != NULL)
|
||||
*retouch_offset_override = retouch_offset;
|
||||
|
||||
// How much free space do we need?
|
||||
bool enough_space = false;
|
||||
size_t free_space = FreeSpaceForFile(target_fs);
|
||||
// 50% margin when estimating the space needed.
|
||||
enough_space = (free_space > (file.size * 3 / 2));
|
||||
|
||||
// The experts say we have to allow for a retry of the
|
||||
// whole process to avoid filesystem weirdness.
|
||||
int retry = 1;
|
||||
bool made_copy = false;
|
||||
do {
|
||||
// First figure out where to store a copy of the original.
|
||||
// Ideally leave the original itself intact until the
|
||||
// atomic swap. If no room on the same partition, fall back
|
||||
// to the cache partition and remove the original.
|
||||
|
||||
if (!enough_space) {
|
||||
printf("Target is %ldB; free space is %ldB: not enough.\n",
|
||||
(long)file.size, (long)free_space);
|
||||
|
||||
retry = 0;
|
||||
if (MakeFreeSpaceOnCache(file.size) < 0) {
|
||||
printf("Not enough free space on '/cache'.\n");
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
if (SaveFileContents(CACHE_TEMP_SOURCE, &file) < 0) {
|
||||
printf("Failed to back up source file.\n");
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
made_copy = true;
|
||||
unlink(binary_name);
|
||||
|
||||
size_t free_space = FreeSpaceForFile(target_fs);
|
||||
printf("(now %ld bytes free for target)\n", (long)free_space);
|
||||
}
|
||||
|
||||
result = SaveFileContents(binary_name_atomic, &file);
|
||||
if (result != 0) {
|
||||
// Maybe the filesystem was optimistic: retry.
|
||||
enough_space = false;
|
||||
unlink(binary_name_atomic);
|
||||
printf("Saving the retouched contents failed; retrying.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Succeeded; no need to retry.
|
||||
break;
|
||||
} while (retry-- > 0);
|
||||
|
||||
// Give the .atomic file the same owner, group, and mode of the
|
||||
// original source file.
|
||||
if (chmod(binary_name_atomic, file.st.st_mode) != 0) {
|
||||
printf("chmod of \"%s\" failed: %s\n",
|
||||
binary_name_atomic, strerror(errno));
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
if (chown(binary_name_atomic, file.st.st_uid, file.st.st_gid) != 0) {
|
||||
printf("chown of \"%s\" failed: %s\n",
|
||||
binary_name_atomic,
|
||||
strerror(errno));
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Finally, rename the .atomic file to replace the target file.
|
||||
if (rename(binary_name_atomic, binary_name) != 0) {
|
||||
printf("rename of .atomic to \"%s\" failed: %s\n",
|
||||
binary_name, strerror(errno));
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// If this run created a copy, and we're here, we can delete it.
|
||||
if (made_copy) unlink(CACHE_TEMP_SOURCE);
|
||||
|
||||
out:
|
||||
// clean up
|
||||
free(file.data);
|
||||
unlink(binary_name_atomic);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,6 @@ typedef struct {
|
|||
uint32_t blob_size; /* in bytes, located right before this struct */
|
||||
} retouch_info_t __attribute__((packed));
|
||||
|
||||
// Retouch a file. Use CACHED_SOURCE_TEMP to store a copy.
|
||||
bool retouch_one_library(const char *binary_name,
|
||||
const char *binary_sha1,
|
||||
int32_t retouch_offset,
|
||||
int32_t *retouch_offset_override);
|
||||
|
||||
#define RETOUCH_DONT_MASK 0
|
||||
#define RETOUCH_DO_MASK 1
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "edify/expr.h"
|
||||
#include "mincrypt/sha.h"
|
||||
#include "minzip/DirUtil.h"
|
||||
#include "minelf/Retouch.h"
|
||||
#include "mtdutils/mounts.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "updater.h"
|
||||
|
@ -435,121 +434,6 @@ Value* PackageExtractFileFn(const char* name, State* state,
|
|||
}
|
||||
|
||||
|
||||
// retouch_binaries(lib1, lib2, ...)
|
||||
Value* RetouchBinariesFn(const char* name, State* state,
|
||||
int argc, Expr* argv[]) {
|
||||
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
|
||||
|
||||
char **retouch_entries = ReadVarArgs(state, argc, argv);
|
||||
if (retouch_entries == NULL) {
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
// some randomness from the clock
|
||||
int32_t override_base;
|
||||
bool override_set = false;
|
||||
int32_t random_base = time(NULL) % 1024;
|
||||
// some more randomness from /dev/random
|
||||
FILE *f_random = fopen("/dev/random", "rb");
|
||||
uint16_t random_bits = 0;
|
||||
if (f_random != NULL) {
|
||||
fread(&random_bits, 2, 1, f_random);
|
||||
random_bits = random_bits % 1024;
|
||||
fclose(f_random);
|
||||
}
|
||||
random_base = (random_base + random_bits) % 1024;
|
||||
fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base);
|
||||
fprintf(ui->cmd_pipe, "ui_print\n");
|
||||
|
||||
// make sure we never randomize to zero; this let's us look at a file
|
||||
// and know for sure whether it has been processed; important in the
|
||||
// crash recovery process
|
||||
if (random_base == 0) random_base = 1;
|
||||
// make sure our randomization is page-aligned
|
||||
random_base *= -0x1000;
|
||||
override_base = random_base;
|
||||
|
||||
int i = 0;
|
||||
bool success = true;
|
||||
while (i < (argc - 1)) {
|
||||
success = success && retouch_one_library(retouch_entries[i],
|
||||
retouch_entries[i+1],
|
||||
random_base,
|
||||
override_set ?
|
||||
NULL :
|
||||
&override_base);
|
||||
if (!success)
|
||||
ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]);
|
||||
|
||||
free(retouch_entries[i]);
|
||||
free(retouch_entries[i+1]);
|
||||
i += 2;
|
||||
|
||||
if (success && override_base != 0) {
|
||||
random_base = override_base;
|
||||
override_set = true;
|
||||
}
|
||||
}
|
||||
if (i < argc) {
|
||||
free(retouch_entries[i]);
|
||||
success = false;
|
||||
}
|
||||
free(retouch_entries);
|
||||
|
||||
if (!success) {
|
||||
Value* v = malloc(sizeof(Value));
|
||||
v->type = VAL_STRING;
|
||||
v->data = NULL;
|
||||
v->size = -1;
|
||||
return v;
|
||||
}
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
|
||||
// undo_retouch_binaries(lib1, lib2, ...)
|
||||
Value* UndoRetouchBinariesFn(const char* name, State* state,
|
||||
int argc, Expr* argv[]) {
|
||||
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
|
||||
|
||||
char **retouch_entries = ReadVarArgs(state, argc, argv);
|
||||
if (retouch_entries == NULL) {
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
bool success = true;
|
||||
int32_t override_base;
|
||||
while (i < (argc-1)) {
|
||||
success = success && retouch_one_library(retouch_entries[i],
|
||||
retouch_entries[i+1],
|
||||
0 /* undo => offset==0 */,
|
||||
NULL);
|
||||
if (!success)
|
||||
ErrorAbort(state, "Failed to unretouch '%s'.",
|
||||
retouch_entries[i]);
|
||||
|
||||
free(retouch_entries[i]);
|
||||
free(retouch_entries[i+1]);
|
||||
i += 2;
|
||||
}
|
||||
if (i < argc) {
|
||||
free(retouch_entries[i]);
|
||||
success = false;
|
||||
}
|
||||
free(retouch_entries);
|
||||
|
||||
if (!success) {
|
||||
Value* v = malloc(sizeof(Value));
|
||||
v->type = VAL_STRING;
|
||||
v->data = NULL;
|
||||
v->size = -1;
|
||||
return v;
|
||||
}
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
|
||||
// symlink target src1 src2 ...
|
||||
// unlinks any previously existing src1, src2, etc before creating symlinks.
|
||||
Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
@ -1190,8 +1074,6 @@ void RegisterInstallFunctions() {
|
|||
RegisterFunction("delete_recursive", DeleteFn);
|
||||
RegisterFunction("package_extract_dir", PackageExtractDirFn);
|
||||
RegisterFunction("package_extract_file", PackageExtractFileFn);
|
||||
RegisterFunction("retouch_binaries", RetouchBinariesFn);
|
||||
RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
|
||||
RegisterFunction("symlink", SymlinkFn);
|
||||
RegisterFunction("set_perm", SetPermFn);
|
||||
RegisterFunction("set_perm_recursive", SetPermFn);
|
||||
|
|
Loading…
Reference in a new issue