Home | History | Annotate | Download | only in security_SuidBinaries
      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 logging
      6 import os
      7 
      8 from autotest_lib.client.bin import test, utils
      9 from autotest_lib.client.common_lib import error
     10 
     11 class 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