Home | History | Annotate | Download | only in security_DbusOwners
      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 import re
      8 from xml.dom import minidom
      9 
     10 from autotest_lib.client.bin import test
     11 from autotest_lib.client.common_lib import error
     12 
     13 class security_DbusOwners(test.test):
     14     version = 1
     15     _DBUS_CONFIG_DIR = '/etc/dbus-1/system.d/'
     16 
     17 
     18     def load_baseline(self):
     19         """Return a list of interface names to be owned by chronos."""
     20         bfile = open(os.path.join(self.bindir, 'baseline'))
     21         baseline_data = bfile.read()
     22         baseline_set = set(baseline_data.splitlines())
     23         bfile.close()
     24         return baseline_set
     25 
     26 
     27     def fetch_owners(self):
     28         """
     29         For every DBus interface XML, look for <policy user="chronos"> sections
     30         containing <allow own="InterfaceName">. Return the list of interfaces
     31         owned by chronos.
     32         """
     33         chronos_owned = []
     34         for root, dirs, files in os.walk(self._DBUS_CONFIG_DIR):
     35             for filename in files:
     36                 # Skip cruft like dotfiles
     37                 if not re.search('^[^.].*\.conf$', filename):
     38                     logging.debug('Skipping %s', filename)
     39                     continue
     40 
     41                 logging.debug('Parsing %s', filename)
     42                 xmldoc = minidom.parse(os.path.join(root,filename))
     43                 policies = xmldoc.getElementsByTagName('policy')
     44 
     45                 for policy in policies:
     46                     if (policy.hasAttribute('user') and
     47                         policy.getAttribute('user') == 'chronos'):
     48                         allows = policy.getElementsByTagName('allow')
     49 
     50                         for allow in allows:
     51                             if allow.hasAttribute('own'):
     52                                 chronos_owned.append(allow.getAttribute('own'))
     53         return set(chronos_owned)
     54 
     55 
     56     def run_once(self):
     57         """
     58         Enumerate all the DBus interfaces owned by chronos.
     59         Fail if it's not included in the expected set.
     60         """
     61         observed_set = self.fetch_owners()
     62         baseline_set = self.load_baseline()
     63 
     64         # We log but don't fail if we find missing interfaces.
     65         missing_ifaces = baseline_set.difference(observed_set)
     66         if len(missing_ifaces) > 0:
     67             for iface in missing_ifaces:
     68                 logging.error('Missing chronos-owned interface %s', iface)
     69 
     70         # We fail if we find new interfaces.
     71         new_ifaces = observed_set.difference(baseline_set)
     72         if len(new_ifaces) > 0:
     73             message = 'New chronos-owned interface(s): ' + ', '.join(new_ifaces)
     74             raise error.TestFail(message)
     75