security_ProfilePermissions.py revision 16634c8a6f794824688592a12b0b986bf49e96db
1# Copyright (c) 2011 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 pwd
8import stat
9
10from autotest_lib.client.bin import utils
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.cros import constants, cros_ui_test, cryptohome, login
13
14
15class security_ProfilePermissions(cros_ui_test.UITest):
16    version = 2
17    _HOMEDIR_MODE = 0710
18
19    def check_owner_mode(self, path, expected_owner, expected_mode):
20        """
21        Checks if the file/directory at 'path' is owned by 'expected_owner'
22        with permissions matching 'expected_mode'.
23        Returns True if they match, else False.
24        Logs any mismatches to logging.error.
25        """
26        s = os.stat(path)
27        actual_owner = pwd.getpwuid(s.st_uid).pw_name
28        actual_mode = stat.S_IMODE(s.st_mode)
29        if (expected_owner != actual_owner or
30            expected_mode != actual_mode):
31            logging.error("%s - Expected %s:%s, saw %s:%s" %
32                          (path, expected_owner, oct(expected_mode),
33                           actual_owner, oct(actual_mode)))
34            return False
35        else:
36            return True
37
38
39    def run_once(self):
40        """Check permissions within cryptohome for anything too permissive."""
41        passes = []
42        login.wait_for_initial_chrome_window()
43
44        homepath = "/home/chronos"
45        passes.append(self.check_owner_mode(homepath, "chronos", 0755))
46
47        user_mountpt = constants.CRYPTOHOME_MOUNT_PT
48        # TODO(jimhebert) homedir mode check excluded from BWSI right now.
49        # Once crosbug.com/16425 is fixed, remove the is_mounted() check.
50        if cryptohome.is_mounted():
51            passes.append(self.check_owner_mode(user_mountpt, "chronos",
52                                                self._HOMEDIR_MODE))
53
54        # TODO(benchan): Refactor the following code to use some helper
55        # functions instead of find commands.
56
57        # An array of shell commands, each representing a test that
58        # passes if it emits no output. The first test is the main one.
59        # In general, writable by anyone else is bad, as is owned by
60        # anyone else. Any exceptions to that are pruned out of the
61        # first test and checked individually by subsequent tests.
62        cmds = [
63            ('find -L "%s" -path "%s" -o '
64             # Avoid false-positives on SingletonLock, SingletonCookie, etc.
65             ' \\( -name "Singleton*" -a -type l \\) -o '
66             ' -path "%s/Downloads" -prune -o '
67             ' -path "%s/flimflam" -prune -o '
68             ' -path "%s/.tpm" -prune -o '
69             ' \\( -perm /022 -o \\! -user chronos \\) -ls') %
70            (homepath, homepath, user_mountpt, user_mountpt, user_mountpt),
71            # /home/chronos/user and /home/chronos/user/Downloads are owned by
72            # the chronos-access group and with a group execute permission.
73            'find -L "%s" -maxdepth 0 \\( \\! -perm 710 '
74            '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' %
75            user_mountpt,
76            'find -L "%s/Downloads" -maxdepth 0 \\( \\! -perm 710 '
77            '-o \\! -user chronos -o \\! -group chronos-access \\) -ls' %
78            user_mountpt,
79            'find -L "%s/flimflam" \\( -perm /077 -o \\! -user root \\) -ls' %
80            user_mountpt,
81            # TODO(jimhebert) Uncomment after crosbug.com/16425 is fixed.
82            #('find -L "%s/.tpm" \\( -perm /007 -o \\! -user chronos '
83            # ' -o \\! -group pkcs11 \\) -ls') % user_mountpt,
84        ]
85
86        for cmd in cmds:
87            cmd_output = utils.system_output(cmd, ignore_status=True)
88            if cmd_output:
89                passes.append(False)
90                logging.error(cmd_output)
91
92        # This next section only applies if we have a real vault mounted
93        # (ie, not a BWSI tmpfs).
94        if cryptohome.is_mounted():
95            # Also check the permissions of the underlying vault and
96            # supporting directory structure.
97            vaultpath = cryptohome.current_mounted_vault()
98
99            passes.append(self.check_owner_mode(vaultpath, "root", 0700))
100            passes.append(self.check_owner_mode(vaultpath + "/../master.0",
101                                                "root", 0600))
102            passes.append(self.check_owner_mode(vaultpath + "/../",
103                                                "root", 0700))
104            passes.append(self.check_owner_mode(vaultpath + "/../../",
105                                                "root", 0700))
106
107        if False in passes:
108            raise error.TestFail('Bad permissions found on cryptohome files')
109