Working ASLR implementation.
ASLR for shared libraries is controlled by "-a" in ota_from_target_files. Binary files are self-contained (supported by apriori/soslim). Signed-off-by: Hristo Bojinov <hristo@google.com> Change-Id: I500e325bf4a70a8d69a2ab9b2938e83dadb4e65d
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <libelf.h>
|
#include <libelf.h>
|
||||||
@@ -54,6 +55,154 @@ extern int verbose_flag;
|
|||||||
|
|
||||||
static source_t *sources = NULL;
|
static source_t *sources = NULL;
|
||||||
|
|
||||||
|
/* Retouch data is a very concise representation of the resolved relocations.
|
||||||
|
This data is used to randomize the location of prelinked libraries at
|
||||||
|
update time, on the device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We will store retouch entries into this buffer, then dump them at the
|
||||||
|
// end of the .so file before setup_prelink_info().
|
||||||
|
#define RETOUCH_MAX_SIZE 500000
|
||||||
|
static char *retouch_buf;
|
||||||
|
static unsigned int retouch_byte_cnt;
|
||||||
|
// Compression state.
|
||||||
|
static int32_t offs_prev;
|
||||||
|
static uint32_t cont_prev;
|
||||||
|
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
void retouch_init(void) {
|
||||||
|
offs_prev = 0;
|
||||||
|
cont_prev = 0;
|
||||||
|
retouch_byte_cnt = 0;
|
||||||
|
retouch_buf = malloc(RETOUCH_MAX_SIZE+12);
|
||||||
|
FAILIF(retouch_buf == NULL,
|
||||||
|
"Could not allocate %d bytes.\n", RETOUCH_MAX_SIZE+12);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We use three encoding schemes; this takes care of much of the redundancy
|
||||||
|
// inherent in lists of relocations:
|
||||||
|
//
|
||||||
|
// * two bytes, leading 1, 2b for d_offset ("s"), 13b for d_contents ("c")
|
||||||
|
//
|
||||||
|
// 76543210 76543210
|
||||||
|
// 1ssccccc cccccccc
|
||||||
|
//
|
||||||
|
// * three bytes, leading 01, 2b for delta offset, 20b for delta contents
|
||||||
|
//
|
||||||
|
// 76543210 76543210 76543210
|
||||||
|
// 01sscccc cccccccc cccccccc
|
||||||
|
//
|
||||||
|
// * eigth bytes, leading 00, 30b for offset, 32b for contents
|
||||||
|
//
|
||||||
|
// 76543210 76543210 76543210 76543210
|
||||||
|
// 00ssssss ssssssss ssssssss ssssssss + 4 bytes contents
|
||||||
|
//
|
||||||
|
// NOTE 1: All deltas are w.r.t. the previous line in the list.
|
||||||
|
// NOTE 2: Two-bit ("ss") offsets mean: "00"=4, "01"=8, "10"=12, and "11"=16.
|
||||||
|
// NOTE 3: Delta contents are signed. To map back to a int32 we refill with 1s.
|
||||||
|
// NOTE 4: Special encoding for -1 offset. Extended back to 32b when decoded.
|
||||||
|
//
|
||||||
|
|
||||||
|
void retouch_encode(int32_t offset, uint32_t contents) {
|
||||||
|
int64_t d_offs = offset-offs_prev;
|
||||||
|
int64_t d_cont = (int64_t)contents-(int64_t)cont_prev;
|
||||||
|
|
||||||
|
uint8_t output[8];
|
||||||
|
uint32_t output_size;
|
||||||
|
|
||||||
|
if ((d_offs > 3) &&
|
||||||
|
(d_offs % 4) == 0 &&
|
||||||
|
(d_offs / 4) < 5 &&
|
||||||
|
(d_cont < 4000) &&
|
||||||
|
(d_cont > -4000)) {
|
||||||
|
// we can fit in 2 bytes
|
||||||
|
output[0] =
|
||||||
|
0x80 |
|
||||||
|
(((d_offs/4)-1) << 5) |
|
||||||
|
(((uint64_t)d_cont & 0x1f00) >> 8);
|
||||||
|
output[1] =
|
||||||
|
((uint64_t)d_cont & 0xff);
|
||||||
|
output_size = 2;
|
||||||
|
} else if ((d_offs > 3) &&
|
||||||
|
(d_offs % 4) == 0 &&
|
||||||
|
(d_offs / 4) < 5 &&
|
||||||
|
(d_cont < 510000) &&
|
||||||
|
(d_cont > -510000)) {
|
||||||
|
// fit in 3 bytes
|
||||||
|
output[0] =
|
||||||
|
0x40 |
|
||||||
|
(((d_offs/4)-1) << 4) |
|
||||||
|
(((uint64_t)d_cont & 0xf0000) >> 16);
|
||||||
|
output[1] =
|
||||||
|
((uint64_t)d_cont & 0xff00) >> 8;
|
||||||
|
output[2] =
|
||||||
|
((uint64_t)d_cont & 0xff);
|
||||||
|
output_size = 3;
|
||||||
|
} else {
|
||||||
|
// fit in 8 bytes; we can't support files bigger than (1GB-1)
|
||||||
|
// with this encoding: no library is that big anyway..
|
||||||
|
FAILIF(offset < -1 || offset > 0x3ffffffe, "Offset out of range.\n");
|
||||||
|
output[0] = (offset & 0x3f000000) >> 24;
|
||||||
|
output[1] = (offset & 0xff0000) >> 16;
|
||||||
|
output[2] = (offset & 0xff00) >> 8;
|
||||||
|
output[3] = (offset & 0xff);
|
||||||
|
output[4] = (contents & 0xff000000) >> 24;
|
||||||
|
output[5] = (contents & 0xff0000) >> 16;
|
||||||
|
output[6] = (contents & 0xff00) >> 8;
|
||||||
|
output[7] = (contents & 0xff);
|
||||||
|
output_size = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this happens, the retouch buffer size can be bumped up.
|
||||||
|
// Currently, the largest case is libwebcore, at about 250K.
|
||||||
|
FAILIF((retouch_byte_cnt+output_size) > RETOUCH_MAX_SIZE,
|
||||||
|
"About to overflow retouch buffer.\n");
|
||||||
|
|
||||||
|
memcpy(retouch_buf+retouch_byte_cnt, output, output_size);
|
||||||
|
retouch_byte_cnt += output_size;
|
||||||
|
|
||||||
|
offs_prev = offset;
|
||||||
|
cont_prev = contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
void retouch_dump(const char *fname, int elf_little,
|
||||||
|
unsigned int retouch_byte_cnt, char *retouch_buf) {
|
||||||
|
int fd = open(fname, O_WRONLY);
|
||||||
|
FAILIF(fd < 0,
|
||||||
|
"open(%s, O_WRONLY): %s (%d)\n" ,
|
||||||
|
fname, strerror(errno), errno);
|
||||||
|
off_t sz = lseek(fd, 0, SEEK_END);
|
||||||
|
FAILIF(sz == (off_t)-1,
|
||||||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
|
||||||
|
// The retouch blob ends with "RETOUCH XXXX", where XXXX is the 4-byte
|
||||||
|
// size of the retouch blob, in target endianness.
|
||||||
|
strncpy(retouch_buf+retouch_byte_cnt, "RETOUCH ", 8);
|
||||||
|
if (elf_little ^ is_host_little()) {
|
||||||
|
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
|
||||||
|
switch_endianness(retouch_byte_cnt);
|
||||||
|
} else {
|
||||||
|
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
|
||||||
|
retouch_byte_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_written = write(fd, retouch_buf, retouch_byte_cnt+12);
|
||||||
|
FAILIF(num_written < 0,
|
||||||
|
"write(%d, &info, sizeof(info)): %s (%d)\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
FAILIF((retouch_byte_cnt+12) != num_written,
|
||||||
|
"Could not write %d bytes as expected (wrote %d bytes instead)!\n",
|
||||||
|
retouch_byte_cnt, num_written);
|
||||||
|
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of retouch code.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(DEBUG) && 0
|
#if defined(DEBUG) && 0
|
||||||
|
|
||||||
static void print_shdr(source_t *source, Elf_Scn *scn)
|
static void print_shdr(source_t *source, Elf_Scn *scn)
|
||||||
@@ -325,6 +474,9 @@ static Elf * init_elf(source_t *source, bool create_new_sections)
|
|||||||
basename(source->name));
|
basename(source->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Save some of the info; needed for retouching (ASLR). */
|
||||||
|
retouch_init();
|
||||||
|
|
||||||
source->newelf_fd = open(source->output,
|
source->newelf_fd = open(source->output,
|
||||||
O_RDWR | O_CREAT,
|
O_RDWR | O_CREAT,
|
||||||
0666);
|
0666);
|
||||||
@@ -615,15 +767,15 @@ static source_t* init_source(const char *full_path,
|
|||||||
strerror(errno),
|
strerror(errno),
|
||||||
errno);
|
errno);
|
||||||
|
|
||||||
FAILIF(fstat(source->elf_fd, &source->elf_file_info) < 0,
|
FAILIF(fstat(source->elf_fd, &source->elf_file_info) < 0,
|
||||||
"fstat(%s(fd %d)): %s (%d)\n",
|
"fstat(%s(fd %d)): %s (%d)\n",
|
||||||
source->name,
|
source->name,
|
||||||
source->elf_fd,
|
source->elf_fd,
|
||||||
strerror(errno),
|
strerror(errno),
|
||||||
errno);
|
errno);
|
||||||
INFO("File [%s]'s size is %lld bytes!\n",
|
INFO("File [%s]'s size is %lld bytes!\n",
|
||||||
source->name,
|
source->name,
|
||||||
source->elf_file_info.st_size);
|
source->elf_file_info.st_size);
|
||||||
|
|
||||||
INFO("Calling elf_begin(%s)...\n", full_path);
|
INFO("Calling elf_begin(%s)...\n", full_path);
|
||||||
|
|
||||||
@@ -775,6 +927,11 @@ static void destroy_source(source_t *source)
|
|||||||
function setup_prelink_info() below. */
|
function setup_prelink_info() below. */
|
||||||
INFO("%s: setting up prelink tag at end of file.\n",
|
INFO("%s: setting up prelink tag at end of file.\n",
|
||||||
source->output ? source->output : source->name);
|
source->output ? source->output : source->name);
|
||||||
|
retouch_encode(-1, source->base);
|
||||||
|
retouch_dump(source->output ? source->output : source->name,
|
||||||
|
source->elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB,
|
||||||
|
retouch_byte_cnt,
|
||||||
|
retouch_buf);
|
||||||
setup_prelink_info(source->output ? source->output : source->name,
|
setup_prelink_info(source->output ? source->output : source->name,
|
||||||
source->elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB,
|
source->elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB,
|
||||||
source->base);
|
source->base);
|
||||||
@@ -785,6 +942,7 @@ static void destroy_source(source_t *source)
|
|||||||
#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
|
#endif/*SUPPORT_ANDROID_PRELINK_TAGS*/
|
||||||
|
|
||||||
do_destroy_source(source);
|
do_destroy_source(source);
|
||||||
|
if (retouch_buf != NULL) { free(retouch_buf); retouch_buf = NULL; }
|
||||||
|
|
||||||
if (source->shstrtab_data != NULL)
|
if (source->shstrtab_data != NULL)
|
||||||
FREEIF(source->shstrtab_data->d_buf); /* adjust_elf */
|
FREEIF(source->shstrtab_data->d_buf); /* adjust_elf */
|
||||||
@@ -1226,8 +1384,11 @@ static int do_prelink(source_t *source,
|
|||||||
rel->r_offset,
|
rel->r_offset,
|
||||||
found_sym->st_value,
|
found_sym->st_value,
|
||||||
sym_source->base);
|
sym_source->base);
|
||||||
if (!dry_run)
|
if (!dry_run) {
|
||||||
|
PRINT("WARNING: Relocation type not supported "
|
||||||
|
"for retouching!");
|
||||||
*dest = found_sym->st_value + sym_source->base;
|
*dest = found_sym->st_value + sym_source->base;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
num_relocations++;
|
num_relocations++;
|
||||||
break;
|
break;
|
||||||
@@ -1240,8 +1401,15 @@ static int do_prelink(source_t *source,
|
|||||||
sname,
|
sname,
|
||||||
symname ?: "(symbol has no name)",
|
symname ?: "(symbol has no name)",
|
||||||
rel->r_offset, *dest, source->base);
|
rel->r_offset, *dest, source->base);
|
||||||
if (!dry_run)
|
if (!dry_run) {
|
||||||
*dest += source->base;
|
*dest += source->base;
|
||||||
|
|
||||||
|
/* Output an entry for the ASLR touch-up process. */
|
||||||
|
retouch_encode(rel->r_offset
|
||||||
|
-shdr_mem.sh_addr
|
||||||
|
+shdr_mem.sh_offset,
|
||||||
|
*dest);
|
||||||
|
}
|
||||||
num_relocations++;
|
num_relocations++;
|
||||||
break;
|
break;
|
||||||
case R_ARM_COPY:
|
case R_ARM_COPY:
|
||||||
@@ -1352,15 +1520,21 @@ static int do_prelink(source_t *source,
|
|||||||
ASSERT(data->d_buf != NULL);
|
ASSERT(data->d_buf != NULL);
|
||||||
ASSERT(data->d_size >= rel->r_offset -
|
ASSERT(data->d_size >= rel->r_offset -
|
||||||
shdr_mem.sh_addr);
|
shdr_mem.sh_addr);
|
||||||
if (!dry_run)
|
if (!dry_run) {
|
||||||
memcpy(dest, src, found_sym->st_size);
|
PRINT("WARNING: Relocation type not supported "
|
||||||
|
"for retouching!");
|
||||||
|
memcpy(dest, src, found_sym->st_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ASSERT(src == NULL);
|
ASSERT(src == NULL);
|
||||||
ASSERT(elf_ndxscn(src_scn) ==
|
ASSERT(elf_ndxscn(src_scn) ==
|
||||||
elf_ndxscn(sym_source->bss.scn));
|
elf_ndxscn(sym_source->bss.scn));
|
||||||
if (!dry_run)
|
if (!dry_run) {
|
||||||
memset(dest, 0, found_sym->st_size);
|
PRINT("WARNING: Relocation type not supported "
|
||||||
|
"for retouching!");
|
||||||
|
memset(dest, 0, found_sym->st_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,8 @@ struct source_t {
|
|||||||
Elf_Data *shstrtab_data;
|
Elf_Data *shstrtab_data;
|
||||||
int elf_fd;
|
int elf_fd;
|
||||||
int newelf_fd; /* fd of output file, -1 if output == NULL */
|
int newelf_fd; /* fd of output file, -1 if output == NULL */
|
||||||
struct stat elf_file_info;
|
int newelf_relo_fd; /* fd of relocaion output file */
|
||||||
|
struct stat elf_file_info;
|
||||||
GElf_Ehdr elf_hdr, oldelf_hdr;
|
GElf_Ehdr elf_hdr, oldelf_hdr;
|
||||||
size_t shstrndx;
|
size_t shstrndx;
|
||||||
int shnum; /* number of sections */
|
int shnum; /* number of sections */
|
||||||
|
@@ -235,6 +235,20 @@ class EdifyGenerator(object):
|
|||||||
",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
|
",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
|
||||||
self.script.append(self._WordWrap(cmd))
|
self.script.append(self._WordWrap(cmd))
|
||||||
|
|
||||||
|
def RetouchBinaries(self, file_list):
|
||||||
|
"""Execute the retouch instructions in files listed."""
|
||||||
|
cmd = ('retouch_binaries(' +
|
||||||
|
', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) +
|
||||||
|
');')
|
||||||
|
self.script.append(self._WordWrap(cmd))
|
||||||
|
|
||||||
|
def UndoRetouchBinaries(self, file_list):
|
||||||
|
"""Undo the retouching (retouch to zero offset)."""
|
||||||
|
cmd = ('undo_retouch_binaries(' +
|
||||||
|
', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) +
|
||||||
|
');')
|
||||||
|
self.script.append(self._WordWrap(cmd))
|
||||||
|
|
||||||
def AppendExtra(self, extra):
|
def AppendExtra(self, extra):
|
||||||
"""Append text verbatim to the output script."""
|
"""Append text verbatim to the output script."""
|
||||||
self.script.append(extra)
|
self.script.append(extra)
|
||||||
|
@@ -44,6 +44,8 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package
|
|||||||
-e (--extra_script) <file>
|
-e (--extra_script) <file>
|
||||||
Insert the contents of file at the end of the update script.
|
Insert the contents of file at the end of the update script.
|
||||||
|
|
||||||
|
-a (--use_aslr)
|
||||||
|
Specify whether to build the package with ASLR enabled (off by default).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -75,6 +77,7 @@ OPTIONS.patch_threshold = 0.95
|
|||||||
OPTIONS.wipe_user_data = False
|
OPTIONS.wipe_user_data = False
|
||||||
OPTIONS.omit_prereq = False
|
OPTIONS.omit_prereq = False
|
||||||
OPTIONS.extra_script = None
|
OPTIONS.extra_script = None
|
||||||
|
OPTIONS.aslr_mode = False
|
||||||
OPTIONS.worker_threads = 3
|
OPTIONS.worker_threads = 3
|
||||||
|
|
||||||
def MostPopularKey(d, default):
|
def MostPopularKey(d, default):
|
||||||
@@ -91,6 +94,10 @@ def IsSymlink(info):
|
|||||||
symlink."""
|
symlink."""
|
||||||
return (info.external_attr >> 16) == 0120777
|
return (info.external_attr >> 16) == 0120777
|
||||||
|
|
||||||
|
def IsRegular(info):
|
||||||
|
"""Return true if the zipfile.ZipInfo object passed in represents a
|
||||||
|
symlink."""
|
||||||
|
return (info.external_attr >> 28) == 010
|
||||||
|
|
||||||
|
|
||||||
class Item:
|
class Item:
|
||||||
@@ -246,13 +253,15 @@ def CopySystemFiles(input_zip, output_zip=None,
|
|||||||
substitute=None):
|
substitute=None):
|
||||||
"""Copies files underneath system/ in the input zip to the output
|
"""Copies files underneath system/ in the input zip to the output
|
||||||
zip. Populates the Item class with their metadata, and returns a
|
zip. Populates the Item class with their metadata, and returns a
|
||||||
list of symlinks. output_zip may be None, in which case the copy is
|
list of symlinks as well as a list of files that will be retouched.
|
||||||
skipped (but the other side effects still happen). substitute is an
|
output_zip may be None, in which case the copy is skipped (but the
|
||||||
optional dict of {output filename: contents} to be output instead of
|
other side effects still happen). substitute is an optional dict
|
||||||
certain input files.
|
of {output filename: contents} to be output instead of certain input
|
||||||
|
files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
symlinks = []
|
symlinks = []
|
||||||
|
retouch_files = []
|
||||||
|
|
||||||
for info in input_zip.infolist():
|
for info in input_zip.infolist():
|
||||||
if info.filename.startswith("SYSTEM/"):
|
if info.filename.startswith("SYSTEM/"):
|
||||||
@@ -270,6 +279,9 @@ def CopySystemFiles(input_zip, output_zip=None,
|
|||||||
data = substitute[fn]
|
data = substitute[fn]
|
||||||
else:
|
else:
|
||||||
data = input_zip.read(info.filename)
|
data = input_zip.read(info.filename)
|
||||||
|
if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
|
||||||
|
retouch_files.append(("/system/" + basefilename,
|
||||||
|
sha.sha(data).hexdigest()))
|
||||||
output_zip.writestr(info2, data)
|
output_zip.writestr(info2, data)
|
||||||
if fn.endswith("/"):
|
if fn.endswith("/"):
|
||||||
Item.Get(fn[:-1], dir=True)
|
Item.Get(fn[:-1], dir=True)
|
||||||
@@ -277,7 +289,7 @@ def CopySystemFiles(input_zip, output_zip=None,
|
|||||||
Item.Get(fn, dir=False)
|
Item.Get(fn, dir=False)
|
||||||
|
|
||||||
symlinks.sort()
|
symlinks.sort()
|
||||||
return symlinks
|
return (symlinks, retouch_files)
|
||||||
|
|
||||||
|
|
||||||
def SignOutput(temp_zip_name, output_zip_name):
|
def SignOutput(temp_zip_name, output_zip_name):
|
||||||
@@ -375,8 +387,12 @@ def WriteFullOTAPackage(input_zip, output_zip, info):
|
|||||||
script.UnpackPackageDir("recovery", "/system")
|
script.UnpackPackageDir("recovery", "/system")
|
||||||
script.UnpackPackageDir("system", "/system")
|
script.UnpackPackageDir("system", "/system")
|
||||||
|
|
||||||
symlinks = CopySystemFiles(input_zip, output_zip)
|
(symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)
|
||||||
script.MakeSymlinks(symlinks)
|
script.MakeSymlinks(symlinks)
|
||||||
|
if OPTIONS.aslr_mode:
|
||||||
|
script.RetouchBinaries(retouch_files)
|
||||||
|
else:
|
||||||
|
script.UndoRetouchBinaries(retouch_files)
|
||||||
|
|
||||||
boot_img = File("boot.img", common.BuildBootableImage(
|
boot_img = File("boot.img", common.BuildBootableImage(
|
||||||
os.path.join(OPTIONS.input_tmp, "BOOT")))
|
os.path.join(OPTIONS.input_tmp, "BOOT")))
|
||||||
@@ -432,12 +448,17 @@ def LoadSystemFiles(z):
|
|||||||
"""Load all the files from SYSTEM/... in a given target-files
|
"""Load all the files from SYSTEM/... in a given target-files
|
||||||
ZipFile, and return a dict of {filename: File object}."""
|
ZipFile, and return a dict of {filename: File object}."""
|
||||||
out = {}
|
out = {}
|
||||||
|
retouch_files = []
|
||||||
for info in z.infolist():
|
for info in z.infolist():
|
||||||
if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
|
if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
|
||||||
fn = "system/" + info.filename[7:]
|
basefilename = info.filename[7:]
|
||||||
|
fn = "system/" + basefilename
|
||||||
data = z.read(info.filename)
|
data = z.read(info.filename)
|
||||||
out[fn] = File(fn, data)
|
out[fn] = File(fn, data)
|
||||||
return out
|
if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
|
||||||
|
retouch_files.append(("/system/" + basefilename,
|
||||||
|
out[fn].sha1))
|
||||||
|
return (out, retouch_files)
|
||||||
|
|
||||||
|
|
||||||
DIFF_PROGRAM_BY_EXT = {
|
DIFF_PROGRAM_BY_EXT = {
|
||||||
@@ -600,9 +621,9 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info):
|
|||||||
metadata=metadata)
|
metadata=metadata)
|
||||||
|
|
||||||
print "Loading target..."
|
print "Loading target..."
|
||||||
target_data = LoadSystemFiles(target_zip)
|
(target_data, target_retouch_files) = LoadSystemFiles(target_zip)
|
||||||
print "Loading source..."
|
print "Loading source..."
|
||||||
source_data = LoadSystemFiles(source_zip)
|
(source_data, source_retouch_files) = LoadSystemFiles(source_zip)
|
||||||
|
|
||||||
verbatim_targets = []
|
verbatim_targets = []
|
||||||
patch_list = []
|
patch_list = []
|
||||||
@@ -769,7 +790,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info):
|
|||||||
|
|
||||||
script.ShowProgress(0.1, 10)
|
script.ShowProgress(0.1, 10)
|
||||||
|
|
||||||
target_symlinks = CopySystemFiles(target_zip, None)
|
(target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None)
|
||||||
|
|
||||||
target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
|
target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
|
||||||
temp_script = script.MakeTemporary()
|
temp_script = script.MakeTemporary()
|
||||||
@@ -778,7 +799,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info):
|
|||||||
|
|
||||||
# Note that this call will mess up the tree of Items, so make sure
|
# Note that this call will mess up the tree of Items, so make sure
|
||||||
# we're done with it.
|
# we're done with it.
|
||||||
source_symlinks = CopySystemFiles(source_zip, None)
|
(source_symlinks, source_retouch_dummies) = CopySystemFiles(source_zip, None)
|
||||||
source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
|
source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
|
||||||
|
|
||||||
# Delete all the symlinks in source that aren't in target. This
|
# Delete all the symlinks in source that aren't in target. This
|
||||||
@@ -812,6 +833,10 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info):
|
|||||||
to_create.append((dest, link))
|
to_create.append((dest, link))
|
||||||
script.DeleteFiles([i[1] for i in to_create])
|
script.DeleteFiles([i[1] for i in to_create])
|
||||||
script.MakeSymlinks(to_create)
|
script.MakeSymlinks(to_create)
|
||||||
|
if OPTIONS.aslr_mode:
|
||||||
|
script.RetouchBinaries(target_retouch_files)
|
||||||
|
else:
|
||||||
|
script.UndoRetouchBinaries(target_retouch_files)
|
||||||
|
|
||||||
# Now that the symlinks are created, we can set all the
|
# Now that the symlinks are created, we can set all the
|
||||||
# permissions.
|
# permissions.
|
||||||
@@ -842,6 +867,8 @@ def main(argv):
|
|||||||
OPTIONS.omit_prereq = True
|
OPTIONS.omit_prereq = True
|
||||||
elif o in ("-e", "--extra_script"):
|
elif o in ("-e", "--extra_script"):
|
||||||
OPTIONS.extra_script = a
|
OPTIONS.extra_script = a
|
||||||
|
elif o in ("-a", "--use_aslr"):
|
||||||
|
OPTIONS.aslr_mode = True
|
||||||
elif o in ("--worker_threads"):
|
elif o in ("--worker_threads"):
|
||||||
OPTIONS.worker_threads = int(a)
|
OPTIONS.worker_threads = int(a)
|
||||||
else:
|
else:
|
||||||
@@ -849,14 +876,15 @@ def main(argv):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
args = common.ParseOptions(argv, __doc__,
|
args = common.ParseOptions(argv, __doc__,
|
||||||
extra_opts="b:k:i:d:wne:",
|
extra_opts="b:k:i:d:wne:a",
|
||||||
extra_long_opts=["board_config=",
|
extra_long_opts=["board_config=",
|
||||||
"package_key=",
|
"package_key=",
|
||||||
"incremental_from=",
|
"incremental_from=",
|
||||||
"wipe_user_data",
|
"wipe_user_data",
|
||||||
"no_prereq",
|
"no_prereq",
|
||||||
"extra_script=",
|
"extra_script=",
|
||||||
"worker_threads="],
|
"worker_threads=",
|
||||||
|
"use_aslr"],
|
||||||
extra_option_handler=option_handler)
|
extra_option_handler=option_handler)
|
||||||
|
|
||||||
if len(args) != 2:
|
if len(args) != 2:
|
||||||
|
@@ -188,9 +188,13 @@ int main(int argc, char **argv)
|
|||||||
else INFO("Not building symbol filter, filter file is empty.\n");
|
else INFO("Not building symbol filter, filter file is empty.\n");
|
||||||
}
|
}
|
||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
int prelinked = 0;
|
int prelinked = 0, retouched = 0;
|
||||||
int elf_little; /* valid if prelinked != 0 */
|
int elf_little; /* valid if prelinked != 0 */
|
||||||
long prelink_addr; /* valid if prelinked != 0 */
|
long prelink_addr; /* valid if prelinked != 0 */
|
||||||
|
#define RETOUCH_MAX_SIZE 500000
|
||||||
|
/* _cnt valid if retouched != 0 */
|
||||||
|
unsigned int retouch_byte_cnt = RETOUCH_MAX_SIZE;
|
||||||
|
char retouch_buf[RETOUCH_MAX_SIZE]; /* valid if retouched != 0 */
|
||||||
#endif
|
#endif
|
||||||
clone_elf(elf, newelf,
|
clone_elf(elf, newelf,
|
||||||
infile, outfile,
|
infile, outfile,
|
||||||
@@ -200,7 +204,10 @@ int main(int argc, char **argv)
|
|||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
, &prelinked,
|
, &prelinked,
|
||||||
&elf_little,
|
&elf_little,
|
||||||
&prelink_addr
|
&prelink_addr,
|
||||||
|
&retouched,
|
||||||
|
&retouch_byte_cnt,
|
||||||
|
retouch_buf
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
true, /* rebuild the section-header-strings table */
|
true, /* rebuild the section-header-strings table */
|
||||||
@@ -223,6 +230,13 @@ int main(int argc, char **argv)
|
|||||||
infile, strerror(errno), errno);
|
infile, strerror(errno), errno);
|
||||||
|
|
||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
|
if (retouched) {
|
||||||
|
INFO("File has retouch data, putting it back in place.\n");
|
||||||
|
retouch_dump(outfile != NULL ? outfile : infile,
|
||||||
|
elf_little,
|
||||||
|
retouch_byte_cnt,
|
||||||
|
retouch_buf);
|
||||||
|
}
|
||||||
if (prelinked) {
|
if (prelinked) {
|
||||||
INFO("File is prelinked, putting prelink TAG back in place.\n");
|
INFO("File is prelinked, putting prelink TAG back in place.\n");
|
||||||
setup_prelink_info(outfile != NULL ? outfile : infile,
|
setup_prelink_info(outfile != NULL ? outfile : infile,
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
|
#define RETOUCH_SUFFIX_SIZE 12
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t mmap_addr;
|
uint32_t mmap_addr;
|
||||||
char tag[4]; /* 'P', 'R', 'E', ' ' */
|
char tag[4]; /* 'P', 'R', 'E', ' ' */
|
||||||
@@ -28,7 +29,7 @@ static inline void set_prelink(long *prelink_addr,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Different endianness */
|
/* Different endianness */
|
||||||
*prelink_addr = switch_endianness(info->mmap_addr);
|
*prelink_addr = switch_endianness(info->mmap_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,10 +68,104 @@ int check_prelinked(const char *fname, int elf_little, long *prelink_addr)
|
|||||||
set_prelink(prelink_addr, elf_little, &info);
|
set_prelink(prelink_addr, elf_little, &info);
|
||||||
prelinked = 1;
|
prelinked = 1;
|
||||||
}
|
}
|
||||||
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
FAILIF(close(fd) < 0,
|
||||||
|
"close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||||||
return prelinked;
|
return prelinked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int check_retouched(const char *fname, int elf_little,
|
||||||
|
unsigned int *retouch_byte_cnt, char *retouch_buf) {
|
||||||
|
FAILIF(sizeof(prelink_info_t) != 8,
|
||||||
|
"Unexpected sizeof(prelink_info_t) == %d!\n",
|
||||||
|
sizeof(prelink_info_t));
|
||||||
|
int fd = open(fname, O_RDONLY);
|
||||||
|
FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n",
|
||||||
|
fname, strerror(errno), errno);
|
||||||
|
off_t end = lseek(fd, 0, SEEK_END);
|
||||||
|
int nr = sizeof(prelink_info_t);
|
||||||
|
off_t sz = lseek(fd, -nr-RETOUCH_SUFFIX_SIZE, SEEK_CUR);
|
||||||
|
ASSERT((long)(end - sz) == (long)(nr+RETOUCH_SUFFIX_SIZE));
|
||||||
|
FAILIF(sz == (off_t)-1,
|
||||||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
|
||||||
|
char retouch_meta[RETOUCH_SUFFIX_SIZE];
|
||||||
|
int num_read = read(fd, &retouch_meta, RETOUCH_SUFFIX_SIZE);
|
||||||
|
FAILIF(num_read < 0,
|
||||||
|
"read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
FAILIF(num_read != RETOUCH_SUFFIX_SIZE,
|
||||||
|
"read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as "
|
||||||
|
"expected (read %d)!\n",
|
||||||
|
fd, RETOUCH_SUFFIX_SIZE, num_read);
|
||||||
|
|
||||||
|
int retouched = 0;
|
||||||
|
if (!strncmp(retouch_meta, "RETOUCH ", 8)) {
|
||||||
|
unsigned int retouch_byte_cnt_meta;
|
||||||
|
if (!(elf_little ^ is_host_little()))
|
||||||
|
retouch_byte_cnt_meta = *(unsigned int *)(retouch_meta+8);
|
||||||
|
else
|
||||||
|
retouch_byte_cnt_meta =
|
||||||
|
switch_endianness(*(unsigned int *)(retouch_meta+8));
|
||||||
|
FAILIF(*retouch_byte_cnt < retouch_byte_cnt_meta,
|
||||||
|
"Retouch buffer too small at %d bytes (%d needed).",
|
||||||
|
*retouch_byte_cnt, retouch_byte_cnt_meta);
|
||||||
|
*retouch_byte_cnt = retouch_byte_cnt_meta;
|
||||||
|
off_t sz = lseek(fd,
|
||||||
|
-((long)*retouch_byte_cnt)-RETOUCH_SUFFIX_SIZE-nr,
|
||||||
|
SEEK_END);
|
||||||
|
ASSERT((long)(end - sz) ==
|
||||||
|
(long)(*retouch_byte_cnt+RETOUCH_SUFFIX_SIZE+nr));
|
||||||
|
FAILIF(sz == (off_t)-1,
|
||||||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
num_read = read(fd, retouch_buf, *retouch_byte_cnt);
|
||||||
|
FAILIF(num_read < 0,
|
||||||
|
"read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
FAILIF(num_read != *retouch_byte_cnt,
|
||||||
|
"read(%d, retouch_buf, %u): did not read %d bytes as "
|
||||||
|
"expected (read %d)!\n",
|
||||||
|
fd, *retouch_byte_cnt, *retouch_byte_cnt, num_read);
|
||||||
|
|
||||||
|
retouched = 1;
|
||||||
|
}
|
||||||
|
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||||||
|
return retouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
void retouch_dump(const char *fname, int elf_little,
|
||||||
|
unsigned int retouch_byte_cnt, char *retouch_buf) {
|
||||||
|
int fd = open(fname, O_WRONLY);
|
||||||
|
FAILIF(fd < 0,
|
||||||
|
"open(%s, O_WRONLY): %s (%d)\n",
|
||||||
|
fname, strerror(errno), errno);
|
||||||
|
off_t sz = lseek(fd, 0, SEEK_END);
|
||||||
|
FAILIF(sz == (off_t)-1,
|
||||||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
|
||||||
|
// The retouch blob ends with "RETOUCH XXXX", where XXXX is the 4-byte
|
||||||
|
// size of the retouch blob, in target endianness.
|
||||||
|
strncpy(retouch_buf+retouch_byte_cnt, "RETOUCH ", 8);
|
||||||
|
if (elf_little ^ is_host_little()) {
|
||||||
|
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
|
||||||
|
switch_endianness(retouch_byte_cnt);
|
||||||
|
} else {
|
||||||
|
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
|
||||||
|
retouch_byte_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_written = write(fd, retouch_buf, retouch_byte_cnt+12);
|
||||||
|
FAILIF(num_written < 0,
|
||||||
|
"write(%d, &info, sizeof(info)): %s (%d)\n",
|
||||||
|
fd, strerror(errno), errno);
|
||||||
|
FAILIF((retouch_byte_cnt+12) != num_written,
|
||||||
|
"Could not write %d bytes as expected (wrote %d bytes instead)!\n",
|
||||||
|
retouch_byte_cnt, num_written);
|
||||||
|
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||||||
|
}
|
||||||
|
|
||||||
void setup_prelink_info(const char *fname, int elf_little, long base)
|
void setup_prelink_info(const char *fname, int elf_little, long base)
|
||||||
{
|
{
|
||||||
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
|
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
|
||||||
@@ -92,7 +187,7 @@ void setup_prelink_info(const char *fname, int elf_little, long base)
|
|||||||
else {
|
else {
|
||||||
/* Different endianness */
|
/* Different endianness */
|
||||||
INFO("Host and ELF file [%s] have different endianness.\n", fname);
|
INFO("Host and ELF file [%s] have different endianness.\n", fname);
|
||||||
info.mmap_addr = switch_endianness(base);
|
info.mmap_addr = switch_endianness(base);
|
||||||
}
|
}
|
||||||
strncpy(info.tag, "PRE ", 4);
|
strncpy(info.tag, "PRE ", 4);
|
||||||
|
|
||||||
|
@@ -3,6 +3,10 @@
|
|||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
|
|
||||||
int check_prelinked(const char *fname, int elf_little, long *prelink_addr);
|
int check_prelinked(const char *fname, int elf_little, long *prelink_addr);
|
||||||
|
int check_retouched(const char *fname, int elf_little,
|
||||||
|
unsigned int *retouch_byte_cnt, char *retouch_buf);
|
||||||
|
void retouch_dump(const char *fname, int elf_little,
|
||||||
|
unsigned int retouch_byte_cnt, char *retouch_buf);
|
||||||
void setup_prelink_info(const char *fname, int elf_little, long base);
|
void setup_prelink_info(const char *fname, int elf_little, long base);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -27,7 +27,10 @@ void clone_elf(Elf *elf, Elf *newelf,
|
|||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
, int *prelinked,
|
, int *prelinked,
|
||||||
int *elf_little,
|
int *elf_little,
|
||||||
long *prelink_addr
|
long *prelink_addr,
|
||||||
|
int *retouched,
|
||||||
|
unsigned int *retouch_byte_cnt,
|
||||||
|
char *retouch_buf
|
||||||
#endif
|
#endif
|
||||||
, bool rebuild_shstrtab,
|
, bool rebuild_shstrtab,
|
||||||
bool strip_debug,
|
bool strip_debug,
|
||||||
@@ -70,6 +73,11 @@ void clone_elf(Elf *elf, Elf *newelf,
|
|||||||
ASSERT(elf_little);
|
ASSERT(elf_little);
|
||||||
*elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
|
*elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
|
||||||
*prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
|
*prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
|
||||||
|
ASSERT(retouched);
|
||||||
|
ASSERT(retouch_byte_cnt);
|
||||||
|
ASSERT(retouch_buf);
|
||||||
|
*retouched = check_retouched(elf_name, *elf_little,
|
||||||
|
retouch_byte_cnt, retouch_buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
INFO("\n\nCALCULATING MODIFICATIONS\n\n");
|
INFO("\n\nCALCULATING MODIFICATIONS\n\n");
|
||||||
|
@@ -23,7 +23,10 @@ void clone_elf(Elf *elf, Elf *newelf,
|
|||||||
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||||||
, int *prelinked,
|
, int *prelinked,
|
||||||
int *elf_little,
|
int *elf_little,
|
||||||
long *prelink_addr
|
long *prelink_addr,
|
||||||
|
int *retouched,
|
||||||
|
unsigned int *retouch_byte_cnt,
|
||||||
|
char *retouch_buf
|
||||||
#endif
|
#endif
|
||||||
, bool rebuild_shstrtab,
|
, bool rebuild_shstrtab,
|
||||||
bool strip_debug,
|
bool strip_debug,
|
||||||
|
Reference in New Issue
Block a user