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 7import re 8from xml.dom import minidom 9 10from autotest_lib.client.bin import test 11from autotest_lib.client.common_lib import error 12 13class 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