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/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 @@
              ",\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 @@
   -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.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 @@
   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 @@
                     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 @@
             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 @@
           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 @@
   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 @@
   """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 @@
       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 @@
 
   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 @@
 
   # 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 @@
       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 @@
       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 @@
     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: