Home | History | Annotate | Download | only in platform_StackProtector
      1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import os
      6 
      7 from autotest_lib.client.bin import test, utils
      8 from autotest_lib.client.common_lib import error
      9 
     10 class platform_StackProtector(test.test):
     11     version = 3
     12 
     13     def load_whitelist(self):
     14         wfile = open(os.path.join(self.bindir, 'whitelist'))
     15         whitelist = wfile.read().splitlines()
     16         wfile.close()
     17         return set(whitelist)
     18 
     19     # http://build.chromium.org/mirror/chromiumos/mirror/distfiles/
     20     # binutils-2.19.1.tar.bz2
     21     def setup(self, tarball="binutils-2.19.1.tar.bz2"):
     22         if os.path.exists(self.srcdir):
     23             utils.system("rm -rf %s" % self.srcdir)
     24 
     25         tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
     26         utils.extract_tarball_to_dir(tarball, self.srcdir)
     27 
     28         os.chdir(self.srcdir)
     29         utils.system("patch -p1 < ../binutils-2.19-arm.patch");
     30         utils.configure()
     31         utils.make()
     32 
     33 
     34     def run_once(self, rootdir="/"):
     35         """
     36         Do a find for all files on the system
     37         For each one, run objdump on them. We'll get either:
     38         * output containing stack_chk (good)
     39         * stderr containing 'not recognized' on e.g. shell scripts (ok)
     40         For those, the egrep -q exit(0)'s and there's no output.
     41         But, for files compiled without stack protector, the egrep will
     42         exit(1) and we'll note the name of those files.
     43 
     44         Check all current/future partitions unless known harmless (e.g. proc).
     45         Skip files < 512 bytes due to objdump false positive and test speed.
     46         """
     47         libc_glob = "/lib/libc-[0-9]*"
     48         os.chdir(self.srcdir)
     49         cmd = ("find '%s' -wholename %s -prune -o "
     50                " -wholename /proc -prune -o "
     51                " -wholename /dev -prune -o "
     52                " -wholename /sys -prune -o "
     53                " -wholename /mnt/stateful_partition -prune -o "
     54                " -wholename /usr/local -prune -o "
     55                # There are files in /home/chronos that cause false positives,
     56                # and since that's noexec anyways, it should be skipped.
     57                " -wholename '/home/chronos' -prune -o "
     58                # libc needs to be checked differently, skip here:
     59                " -wholename '%s' -prune -o "
     60                # The various gconv locale .so's don't count:
     61                " -wholename '/usr/lib/gconv/*' -prune -o"
     62                " -type f -size +511c -exec "
     63                "sh -c 'binutils/objdump -CR {} 2>&1 | "
     64                "egrep -q \"(stack_chk|Invalid|not recognized)\" || echo {}' ';'"
     65                )
     66         badfiles = utils.system_output(cmd % (rootdir, self.autodir, libc_glob))
     67 
     68         # Subtract any files that were on the whitelist.
     69         seen = set(badfiles.splitlines())
     70         diff = seen.difference(self.load_whitelist())
     71 
     72         # Special case check for libc, needs different objdump flags.
     73         cmd = "binutils/objdump -D %s | egrep -q stack_chk || echo %s"
     74         libc_stack_chk = utils.system_output(cmd % (libc_glob, libc_glob))
     75 
     76         if diff or libc_stack_chk:
     77             diff.add(libc_stack_chk)
     78             raise error.TestFail("Missing -fstack-protector:\n"
     79                                  + "\n".join(diff))
     80