Home | History | Annotate | Download | only in security_ProfilePermissions
      1 # Copyright (c) 2012 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 pwd
      8 import stat
      9 
     10 from autotest_lib.client.bin import test, utils
     11 from autotest_lib.client.common_lib import error
     12 from autotest_lib.client.common_lib.cros import chrome
     13 from autotest_lib.client.cros import cryptohome
     14 
     15 
     16 class security_ProfilePermissions(test.test):
     17     """Check permissions of files of logged in and guest user."""
     18     version = 1
     19     _HOMEDIR_MODE = 0710
     20 
     21     def initialize(self, logged_in):
     22         self._logged_in = logged_in
     23 
     24     def check_owner_mode(self, path, expected_owner, expected_mode):
     25         """
     26         Checks if the file/directory at 'path' is owned by 'expected_owner'
     27         with permissions matching 'expected_mode'.
     28         Returns True if they match, else False.
     29         Logs any mismatches to logging.error.
     30 
     31         @param path: file path to test.
     32         @param expected_owner: expected owner of the file.
     33         @param expected_mode: expected permission mode of the file.
     34 
     35         """
     36         s = os.stat(path)
     37         actual_owner = pwd.getpwuid(s.st_uid).pw_name
     38         actual_mode = stat.S_IMODE(s.st_mode)
     39         if (expected_owner != actual_owner or
     40             expected_mode != actual_mode):
     41             logging.error("%s - Expected %s:%s, saw %s:%s",
     42                          path, expected_owner, oct(expected_mode),
     43                          actual_owner, oct(actual_mode))
     44             return False
     45         else:
     46             return True
     47 
     48 
     49     def run_once(self):
     50         with chrome.Chrome(logged_in=self._logged_in) as cr:
     51             username = (cr.username if self._logged_in
     52                                     else cryptohome.GUEST_USER_NAME)
     53 
     54             """Check permissions within cryptohome for anything too permissive.
     55             """
     56             passes = []
     57 
     58             homepath = "/home/chronos"
     59             passes.append(self.check_owner_mode(homepath, "chronos", 0755))
     60 
     61             user_mountpt = cryptohome.user_path(username)
     62             passes.append(self.check_owner_mode(user_mountpt, "chronos",
     63                                                 self._HOMEDIR_MODE))
     64 
     65             # TODO(benchan): Refactor the following code to use some helper
     66             # functions instead of find commands.
     67 
     68             # An array of shell commands, each representing a test that
     69             # passes if it emits no output. The first test is the main one.
     70             # In general, writable by anyone else is bad, as is owned by
     71             # anyone else. Any exceptions to that are pruned out of the
     72             # first test and checked individually by subsequent tests.
     73             cmds = [
     74                 ('find -L "%s" -path "%s" -o '
     75                  # Avoid false-positives on SingletonLock, SingletonCookie, etc.
     76                  ' \\( -name "Singleton*" -a -type l \\) -o '
     77                  ' -path "%s/user" -prune -o '
     78                  ' -path "%s/Downloads" -prune -o '
     79                  ' -path "%s/flimflam" -prune -o '
     80                  ' -path "%s/shill" -prune -o '
     81                  ' -path "%s/.chaps" -prune -o '
     82                  ' -path "%s/u-*" -prune -o '
     83                  ' -path "%s/crash" -prune -o '
     84                  ' \\( -perm /022 -o \\! -user chronos \\) -ls') %
     85                 (homepath, homepath, homepath, user_mountpt, user_mountpt,
     86                 user_mountpt, user_mountpt, homepath, homepath),
     87                 # /home/chronos/user and /home/chronos/user/Downloads are owned
     88                 # by the chronos-access group and with a group execute
     89                 # permission.
     90                 'find -L "%s" -maxdepth 0 \\( \\! -perm 710 '
     91                 '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' %
     92                 user_mountpt,
     93                 'find -L "%s/Downloads" -maxdepth 0 \\( \\! -perm 710 '
     94                 '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' %
     95                 user_mountpt,
     96                 'find -L "%s/flimflam" \\( -perm /077 -o \\! -user root \\) -ls'
     97                 % user_mountpt,
     98                 'find -L "%s/shill" \\( -perm /077 -o \\! -user root \\) -ls' %
     99                 user_mountpt,
    100                 'find -L "%s/.chaps -name auth_data_salt -prune -o '
    101                 '\\! -user chaps -o \\! -group chronos-access -o -perm /027 -ls'
    102                 % user_mountpt,
    103                 'find -L "%s/.chaps -name auth_data_salt -a '
    104                 '\\( \\! -user root -o -perm /077 \\) -ls' % user_mountpt,
    105             ]
    106 
    107             for cmd in cmds:
    108                 cmd_output = utils.system_output(cmd, ignore_status=True)
    109                 if cmd_output:
    110                     passes.append(False)
    111                     logging.error(cmd_output)
    112 
    113             # This next section only applies if we have a real vault mounted
    114             # (ie, not a BWSI tmpfs).
    115             if cryptohome.is_permanent_vault_mounted(username):
    116                 # Also check the permissions of the underlying vault and
    117                 # supporting directory structure.
    118                 mountpath = cryptohome.get_mounted_vault_path(username)
    119 
    120                 # On ecryptfs backend, there's a 'vault' directory storing the
    121                 # encrypted data. If it exists, check its ownership as well.
    122                 vaultpath = os.path.join(mountpath, '../vault')
    123                 if os.path.exists(vaultpath):
    124                     passes.append(self.check_owner_mode(vaultpath,
    125                                                         "root", 0700))
    126                 passes.append(self.check_owner_mode(mountpath, "root", 0700))
    127                 passes.append(self.check_owner_mode(mountpath + "/../master.0",
    128                                                     "root", 0600))
    129                 passes.append(self.check_owner_mode(mountpath + "/../",
    130                                                     "root", 0700))
    131                 passes.append(self.check_owner_mode(mountpath + "/../../",
    132                                                     "root", 0700))
    133 
    134             if False in passes:
    135                 raise error.TestFail(
    136                     'Bad permissions found on cryptohome files')
    137