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 5import logging 6import os 7 8from autotest_lib.client.bin import test, utils 9from autotest_lib.client.common_lib import error 10 11class security_SuidBinaries(test.test): 12 """ 13 Make sure no surprise binaries become setuid, setgid, or gain filesystem 14 capabilities without autotest noticing. 15 """ 16 version = 1 17 18 def load_baseline(self, bltype): 19 """ 20 Load the list of expected files for a given baseline type. 21 @param bltype the baseline to load. 22 """ 23 baseline_file = open(os.path.join(self.bindir, 'baseline.' + bltype)) 24 return set(l.strip() for l in baseline_file) 25 26 27 def run_once(self, baseline='suid'): 28 """ 29 Do a find on the system for setuid binaries, compare against baseline. 30 Fail if setuid binaries are found on the system but not on the baseline. 31 """ 32 exclude = [ '/proc', 33 '/dev', 34 '/sys', 35 '/run', 36 '/usr/local', 37 '/mnt/stateful_partition', 38 ] 39 cmd = 'find / ' 40 for item in exclude: 41 cmd += '-wholename %s -prune -o ' % (item) 42 cmd += '-type f ' 43 44 permmask = {'suid': '4000', 'sgid': '2000'} 45 46 if baseline in permmask: 47 cmd += '-a -perm /%s -print' % (permmask[baseline]) 48 elif baseline == 'fscap': 49 cmd += '-exec getcap {} +' 50 else: 51 raise error.TestFail("Unknown baseline '%s'!" % (baseline)) 52 53 cmd_output = utils.system_output(cmd, ignore_status=True) 54 observed_set = set(cmd_output.splitlines()) 55 baseline_set = self.load_baseline(baseline) 56 57 # Report observed set for debugging. 58 for line in observed_set: 59 logging.debug('%s: %s', baseline, line) 60 61 # Fail if we find new binaries. 62 new = observed_set.difference(baseline_set) 63 if len(new) > 0: 64 message = 'New %s binaries: %s' % (baseline, ', '.join(new)) 65 raise error.TestFail(message) 66 67 # Log but not fail if we find missing binaries. 68 missing = baseline_set.difference(observed_set) 69 if len(missing) > 0: 70 for filepath in missing: 71 logging.error('Missing %s binary: %s', baseline, filepath) 72 else: 73 logging.debug('OK: %s baseline matches system', baseline) 74