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