# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import os import pwd import stat from autotest_lib.client.bin import test, utils from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.cros import chrome from autotest_lib.client.cros import cryptohome class security_ProfilePermissions(test.test): """Check permissions of files of logged in and guest user.""" version = 1 _HOMEDIR_MODE = 0710 def initialize(self, logged_in): self._logged_in = logged_in def check_owner_mode(self, path, expected_owner, expected_mode): """ Checks if the file/directory at 'path' is owned by 'expected_owner' with permissions matching 'expected_mode'. Returns True if they match, else False. Logs any mismatches to logging.error. @param path: file path to test. @param expected_owner: expected owner of the file. @param expected_mode: expected permission mode of the file. """ s = os.stat(path) actual_owner = pwd.getpwuid(s.st_uid).pw_name actual_mode = stat.S_IMODE(s.st_mode) if (expected_owner != actual_owner or expected_mode != actual_mode): logging.error("%s - Expected %s:%s, saw %s:%s", path, expected_owner, oct(expected_mode), actual_owner, oct(actual_mode)) return False else: return True def run_once(self): with chrome.Chrome(logged_in=self._logged_in) as cr: username = (cr.username if self._logged_in else cryptohome.GUEST_USER_NAME) """Check permissions within cryptohome for anything too permissive. """ passes = [] homepath = "/home/chronos" passes.append(self.check_owner_mode(homepath, "chronos", 0755)) user_mountpt = cryptohome.user_path(username) passes.append(self.check_owner_mode(user_mountpt, "chronos", self._HOMEDIR_MODE)) # TODO(benchan): Refactor the following code to use some helper # functions instead of find commands. # An array of shell commands, each representing a test that # passes if it emits no output. The first test is the main one. # In general, writable by anyone else is bad, as is owned by # anyone else. Any exceptions to that are pruned out of the # first test and checked individually by subsequent tests. cmds = [ ('find -L "%s" -path "%s" -o ' # Avoid false-positives on SingletonLock, SingletonCookie, etc. ' \\( -name "Singleton*" -a -type l \\) -o ' ' -path "%s/user" -prune -o ' ' -path "%s/Downloads" -prune -o ' ' -path "%s/flimflam" -prune -o ' ' -path "%s/shill" -prune -o ' ' -path "%s/.chaps" -prune -o ' ' -path "%s/u-*" -prune -o ' ' -path "%s/crash" -prune -o ' ' \\( -perm /022 -o \\! -user chronos \\) -ls') % (homepath, homepath, homepath, user_mountpt, user_mountpt, user_mountpt, user_mountpt, homepath, homepath), # /home/chronos/user and /home/chronos/user/Downloads are owned # by the chronos-access group and with a group execute # permission. 'find -L "%s" -maxdepth 0 \\( \\! -perm 710 ' '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' % user_mountpt, 'find -L "%s/Downloads" -maxdepth 0 \\( \\! -perm 710 ' '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' % user_mountpt, 'find -L "%s/flimflam" \\( -perm /077 -o \\! -user root \\) -ls' % user_mountpt, 'find -L "%s/shill" \\( -perm /077 -o \\! -user root \\) -ls' % user_mountpt, 'find -L "%s/.chaps -name auth_data_salt -prune -o ' '\\! -user chaps -o \\! -group chronos-access -o -perm /027 -ls' % user_mountpt, 'find -L "%s/.chaps -name auth_data_salt -a ' '\\( \\! -user root -o -perm /077 \\) -ls' % user_mountpt, ] for cmd in cmds: cmd_output = utils.system_output(cmd, ignore_status=True) if cmd_output: passes.append(False) logging.error(cmd_output) # This next section only applies if we have a real vault mounted # (ie, not a BWSI tmpfs). if cryptohome.is_permanent_vault_mounted(username): # Also check the permissions of the underlying vault and # supporting directory structure. mountpath = cryptohome.get_mounted_vault_path(username) # On ecryptfs backend, there's a 'vault' directory storing the # encrypted data. If it exists, check its ownership as well. vaultpath = os.path.join(mountpath, '../vault') if os.path.exists(vaultpath): passes.append(self.check_owner_mode(vaultpath, "root", 0700)) passes.append(self.check_owner_mode(mountpath, "root", 0700)) passes.append(self.check_owner_mode(mountpath + "/../master.0", "root", 0600)) passes.append(self.check_owner_mode(mountpath + "/../", "root", 0700)) passes.append(self.check_owner_mode(mountpath + "/../../", "root", 0700)) if False in passes: raise error.TestFail( 'Bad permissions found on cryptohome files')