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