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
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 @@
             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 @@
 #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 @@
                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 @@
 		}
 		else {
 			/* Different endianness */
-			*prelink_addr = switch_endianness(info->mmap_addr);
+                        *prelink_addr = switch_endianness(info->mmap_addr);
 		}
 	}
 }
@@ -67,10 +68,104 @@
 		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 @@
     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 @@
 #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 @@
     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 @@
 #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,