diff options
author | Hristo Bojinov <hristo@google.com> | 2010-08-02 10:26:17 -0700 |
---|---|---|
committer | Hristo Bojinov <hristo@google.com> | 2010-08-02 14:25:01 -0700 |
commit | 96be7205dce97977909e93b73f48779fcce3bc65 (patch) | |
tree | ae0cf3b9f076c1ed41893e5ec81abcd46c6b85e3 | |
parent | 778c2b690025a91b55b2e841921605c55baf652c (diff) | |
download | build-96be7205dce97977909e93b73f48779fcce3bc65.zip build-96be7205dce97977909e93b73f48779fcce3bc65.tar.gz build-96be7205dce97977909e93b73f48779fcce3bc65.tar.bz2 |
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
-rw-r--r-- | tools/apriori/apriori.c | 204 | ||||
-rw-r--r-- | tools/apriori/source.h | 3 | ||||
-rw-r--r-- | tools/releasetools/edify_generator.py | 14 | ||||
-rwxr-xr-x | tools/releasetools/ota_from_target_files | 56 | ||||
-rw-r--r-- | tools/soslim/main.c | 18 | ||||
-rw-r--r-- | tools/soslim/prelink_info.c | 101 | ||||
-rw-r--r-- | tools/soslim/prelink_info.h | 4 | ||||
-rw-r--r-- | tools/soslim/soslim.c | 10 | ||||
-rw-r--r-- | tools/soslim/soslim.h | 5 |
9 files changed, 378 insertions, 37 deletions
diff --git a/tools/apriori/apriori.c b/tools/apriori/apriori.c index d1807b3..b25ac2b 100644 --- a/tools/apriori/apriori.c +++ b/tools/apriori/apriori.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <common.h> #include <debug.h> #include <libelf.h> @@ -54,6 +55,154 @@ extern int verbose_flag; 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 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)); } + /* Save some of the info; needed for retouching (ASLR). */ + retouch_init(); + source->newelf_fd = open(source->output, O_RDWR | O_CREAT, 0666); @@ -615,15 +767,15 @@ static source_t* init_source(const char *full_path, strerror(errno), errno); - FAILIF(fstat(source->elf_fd, &source->elf_file_info) < 0, - "fstat(%s(fd %d)): %s (%d)\n", - source->name, - source->elf_fd, - strerror(errno), - errno); - INFO("File [%s]'s size is %lld bytes!\n", - source->name, - source->elf_file_info.st_size); + FAILIF(fstat(source->elf_fd, &source->elf_file_info) < 0, + "fstat(%s(fd %d)): %s (%d)\n", + source->name, + source->elf_fd, + strerror(errno), + errno); + INFO("File [%s]'s size is %lld bytes!\n", + source->name, + source->elf_file_info.st_size); INFO("Calling elf_begin(%s)...\n", full_path); @@ -775,6 +927,11 @@ static void destroy_source(source_t *source) function setup_prelink_info() below. */ INFO("%s: setting up prelink tag at end of file.\n", 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, source->elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB, source->base); @@ -785,6 +942,7 @@ static void destroy_source(source_t *source) #endif/*SUPPORT_ANDROID_PRELINK_TAGS*/ do_destroy_source(source); + if (retouch_buf != NULL) { free(retouch_buf); retouch_buf = NULL; } if (source->shstrtab_data != NULL) FREEIF(source->shstrtab_data->d_buf); /* adjust_elf */ @@ -1226,8 +1384,11 @@ static int do_prelink(source_t *source, rel->r_offset, found_sym->st_value, 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; + } } num_relocations++; break; @@ -1240,8 +1401,15 @@ static int do_prelink(source_t *source, sname, symname ?: "(symbol has no name)", rel->r_offset, *dest, source->base); - if (!dry_run) + if (!dry_run) { *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++; break; case R_ARM_COPY: @@ -1352,15 +1520,21 @@ static int do_prelink(source_t *source, ASSERT(data->d_buf != NULL); ASSERT(data->d_size >= rel->r_offset - shdr_mem.sh_addr); - if (!dry_run) - memcpy(dest, src, found_sym->st_size); + if (!dry_run) { + PRINT("WARNING: Relocation type not supported " + "for retouching!"); + memcpy(dest, src, found_sym->st_size); + } } else { ASSERT(src == NULL); ASSERT(elf_ndxscn(src_scn) == elf_ndxscn(sym_source->bss.scn)); - if (!dry_run) - memset(dest, 0, found_sym->st_size); + if (!dry_run) { + PRINT("WARNING: Relocation type not supported " + "for retouching!"); + memset(dest, 0, found_sym->st_size); + } } } } diff --git a/tools/apriori/source.h b/tools/apriori/source.h index a5d96bd..5381a29 100644 --- a/tools/apriori/source.h +++ b/tools/apriori/source.h @@ -62,7 +62,8 @@ struct source_t { Elf_Data *shstrtab_data; int elf_fd; 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; size_t shstrndx; int shnum; /* number of sections */ diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py index 390bd4b..328700f 100644 --- a/tools/releasetools/edify_generator.py +++ b/tools/releasetools/edify_generator.py @@ -235,6 +235,20 @@ class EdifyGenerator(object): ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");") 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): """Append text verbatim to the output script.""" self.script.append(extra) diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files index 8cd1941..d249214 100755 --- a/tools/releasetools/ota_from_target_files +++ b/tools/releasetools/ota_from_target_files @@ -44,6 +44,8 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package -e (--extra_script) <file> 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 @@ -75,6 +77,7 @@ OPTIONS.patch_threshold = 0.95 OPTIONS.wipe_user_data = False OPTIONS.omit_prereq = False OPTIONS.extra_script = None +OPTIONS.aslr_mode = False OPTIONS.worker_threads = 3 def MostPopularKey(d, default): @@ -91,6 +94,10 @@ def IsSymlink(info): symlink.""" 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: @@ -246,13 +253,15 @@ def CopySystemFiles(input_zip, output_zip=None, substitute=None): """Copies files underneath system/ in the input zip to the output 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 - skipped (but the other side effects still happen). substitute is an - optional dict of {output filename: contents} to be output instead of - certain input files. + list of symlinks as well as a list of files that will be retouched. + output_zip may be None, in which case the copy is skipped (but the + other side effects still happen). substitute is an optional dict + of {output filename: contents} to be output instead of certain input + files. """ symlinks = [] + retouch_files = [] for info in input_zip.infolist(): if info.filename.startswith("SYSTEM/"): @@ -270,6 +279,9 @@ def CopySystemFiles(input_zip, output_zip=None, data = substitute[fn] else: 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) if fn.endswith("/"): Item.Get(fn[:-1], dir=True) @@ -277,7 +289,7 @@ def CopySystemFiles(input_zip, output_zip=None, Item.Get(fn, dir=False) symlinks.sort() - return symlinks + return (symlinks, retouch_files) 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("system", "/system") - symlinks = CopySystemFiles(input_zip, output_zip) + (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip) script.MakeSymlinks(symlinks) + if OPTIONS.aslr_mode: + script.RetouchBinaries(retouch_files) + else: + script.UndoRetouchBinaries(retouch_files) boot_img = File("boot.img", common.BuildBootableImage( 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 ZipFile, and return a dict of {filename: File object}.""" out = {} + retouch_files = [] for info in z.infolist(): 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) 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 = { @@ -600,9 +621,9 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info): metadata=metadata) print "Loading target..." - target_data = LoadSystemFiles(target_zip) + (target_data, target_retouch_files) = LoadSystemFiles(target_zip) print "Loading source..." - source_data = LoadSystemFiles(source_zip) + (source_data, source_retouch_files) = LoadSystemFiles(source_zip) verbatim_targets = [] patch_list = [] @@ -769,7 +790,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info): 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]) 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 # 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]) # 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)) script.DeleteFiles([i[1] for i in 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 # permissions. @@ -842,6 +867,8 @@ def main(argv): OPTIONS.omit_prereq = True elif o in ("-e", "--extra_script"): OPTIONS.extra_script = a + elif o in ("-a", "--use_aslr"): + OPTIONS.aslr_mode = True elif o in ("--worker_threads"): OPTIONS.worker_threads = int(a) else: @@ -849,14 +876,15 @@ def main(argv): return True 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=", "package_key=", "incremental_from=", "wipe_user_data", "no_prereq", "extra_script=", - "worker_threads="], + "worker_threads=", + "use_aslr"], extra_option_handler=option_handler) if len(args) != 2: diff --git a/tools/soslim/main.c b/tools/soslim/main.c index dd8a60b..e23fbce 100644 --- a/tools/soslim/main.c +++ b/tools/soslim/main.c @@ -188,9 +188,13 @@ int main(int argc, char **argv) else INFO("Not building symbol filter, filter file is empty.\n"); } #ifdef SUPPORT_ANDROID_PRELINK_TAGS - int prelinked = 0; + int prelinked = 0, retouched = 0; int elf_little; /* 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 clone_elf(elf, newelf, infile, outfile, @@ -200,7 +204,10 @@ int main(int argc, char **argv) #ifdef SUPPORT_ANDROID_PRELINK_TAGS , &prelinked, &elf_little, - &prelink_addr + &prelink_addr, + &retouched, + &retouch_byte_cnt, + retouch_buf #endif , true, /* rebuild the section-header-strings table */ @@ -223,6 +230,13 @@ int main(int argc, char **argv) infile, strerror(errno), errno); #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) { INFO("File is prelinked, putting prelink TAG back in place.\n"); setup_prelink_info(outfile != NULL ? outfile : infile, diff --git a/tools/soslim/prelink_info.c b/tools/soslim/prelink_info.c index 81d5de3..2600ac7 100644 --- a/tools/soslim/prelink_info.c +++ b/tools/soslim/prelink_info.c @@ -11,6 +11,7 @@ #include <debug.h> #include <common.h> +#define RETOUCH_SUFFIX_SIZE 12 typedef struct { uint32_t mmap_addr; char tag[4]; /* 'P', 'R', 'E', ' ' */ @@ -28,7 +29,7 @@ static inline void set_prelink(long *prelink_addr, } else { /* 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); 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; } +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) { 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 { /* Different endianness */ 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); diff --git a/tools/soslim/prelink_info.h b/tools/soslim/prelink_info.h index e2787cb..efa84fd 100644 --- a/tools/soslim/prelink_info.h +++ b/tools/soslim/prelink_info.h @@ -3,6 +3,10 @@ #ifdef SUPPORT_ANDROID_PRELINK_TAGS 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); #endif diff --git a/tools/soslim/soslim.c b/tools/soslim/soslim.c index 125e29e..33b1ee7 100644 --- a/tools/soslim/soslim.c +++ b/tools/soslim/soslim.c @@ -27,7 +27,10 @@ void clone_elf(Elf *elf, Elf *newelf, #ifdef SUPPORT_ANDROID_PRELINK_TAGS , int *prelinked, int *elf_little, - long *prelink_addr + long *prelink_addr, + int *retouched, + unsigned int *retouch_byte_cnt, + char *retouch_buf #endif , bool rebuild_shstrtab, bool strip_debug, @@ -70,6 +73,11 @@ void clone_elf(Elf *elf, Elf *newelf, ASSERT(elf_little); *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB); *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 INFO("\n\nCALCULATING MODIFICATIONS\n\n"); diff --git a/tools/soslim/soslim.h b/tools/soslim/soslim.h index dfcb085..952c960 100644 --- a/tools/soslim/soslim.h +++ b/tools/soslim/soslim.h @@ -23,7 +23,10 @@ void clone_elf(Elf *elf, Elf *newelf, #ifdef SUPPORT_ANDROID_PRELINK_TAGS , int *prelinked, int *elf_little, - long *prelink_addr + long *prelink_addr, + int *retouched, + unsigned int *retouch_byte_cnt, + char *retouch_buf #endif , bool rebuild_shstrtab, bool strip_debug, |