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, os
6from autotest_lib.client.bin import test, utils
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.cros import kernel_config
9
10class kernel_ConfigVerify(test.test):
11    """Examine a kernel build CONFIG list to make sure various things are
12    present, missing, built as modules, etc.
13    """
14    version = 1
15    IS_BUILTIN = [
16        # Sanity checks; should be present in builds as builtins.
17        'INET',
18        'MMU',
19        'MODULES',
20        'PRINTK',
21        'SECURITY',
22        # Security; adds stack buffer overflow protections.
23        'CC_STACKPROTECTOR',
24        # Security; enables the SECCOMP application API.
25        'SECCOMP',
26        # Security; blocks direct physical memory access.
27        'STRICT_DEVMEM',
28        # Security; provides some protections against SYN flooding.
29        'SYN_COOKIES',
30        # Security; make sure PID_NS, NET_NS, and USER_NS are enabled for
31        # chrome's layer 1 sandbox.
32        'PID_NS',
33        'NET_NS',
34        'USER_NS',
35        # Security; perform additional validation of credentials.
36        'DEBUG_CREDENTIALS',
37        # Security; make sure the Chrome OS LSM is in use.
38        'SECURITY_CHROMIUMOS',
39    ]
40    IS_MODULE = [
41        # Sanity checks; should be present in builds as modules.
42        'BLK_DEV_SR',
43        'BT',
44        'TUN',
45        # Useful modules for users that should not be removed
46        'USB_SERIAL_OTI6858',
47    ]
48    IS_ENABLED = [
49        # Either module or enabled, depending on platform.
50        'VIDEO_V4L2',
51    ]
52    IS_MISSING = [
53        # Sanity checks.
54        'M386',                 # Never going to optimize to this CPU.
55        'CHARLIE_THE_UNICORN',  # Config not in real kernel config var list.
56        # Dangerous; allows direct physical memory writing.
57        'ACPI_CUSTOM_METHOD',
58        # Dangerous; disables brk ASLR.
59        'COMPAT_BRK',
60        # Dangerous; disables VDSO ASLR.
61        'COMPAT_VDSO',
62        # Dangerous; allows direct kernel memory writing.
63        'DEVKMEM',
64        # Dangerous; allows replacement of running kernel.
65        'KEXEC',
66        # Dangerous; allows replacement of running kernel.
67        'HIBERNATION',
68        # Assists heap memory attacks; best to keep interface disabled.
69        'INET_DIAG',
70    ]
71    IS_EXCLUSIVE = [
72        # Security; no surprise binary formats.
73        {
74            'regex': 'BINFMT_',
75            'builtin': [
76                'BINFMT_ELF',
77            ],
78            'module': [
79            ],
80            'missing': [
81                # Sanity checks; one disabled, one does not exist.
82                'BINFMT_MISC',
83                'BINFMT_IMPOSSIBLE',
84            ],
85        },
86        # Security; no surprise filesystem formats.
87        {
88            'regex': '.*_FS$',
89            'builtin': [
90                'DEBUG_FS',
91                'ECRYPT_FS',
92                'EXT4_FS',
93                'EXT4_USE_FOR_EXT23',
94                'PROC_FS',
95                'SCSI_PROC_FS',
96            ],
97            'module': [
98                'FAT_FS',
99                'FUSE_FS',
100                'HFSPLUS_FS',
101                'ISO9660_FS',
102                'UDF_FS',
103                'VFAT_FS',
104            ],
105            'missing': [
106                # Sanity checks; one disabled, one does not exist.
107                'EXT2_FS',
108                'EXT3_FS',
109                'XFS_FS',
110                'IMPOSSIBLE_FS',
111            ],
112        },
113        # Security; no surprise partition formats.
114        # MAC is for external drive formatted on Macintosh.
115        {
116            'regex': '.*_PARTITION$',
117            'builtin': [
118                'EFI_PARTITION',
119                'MAC_PARTITION',
120                'MSDOS_PARTITION',
121            ],
122            'module': [
123            ],
124            'missing': [
125                # Sanity checks; one disabled, one does not exist.
126                'LDM_PARTITION',
127                'IMPOSSIBLE_PARTITION',
128            ],
129        },
130    ]
131
132    def is_arm_family(self, arch):
133      return arch in ['armv7l', 'aarch64']
134
135    def is_x86_family(self, arch):
136      return arch in ['i386', 'x86_64']
137
138    def run_once(self):
139        # Cache the architecture to avoid redundant execs to "uname".
140        arch = utils.get_arch()
141        userspace_arch = utils.get_arch_userspace()
142
143        # Report the full uname for anyone reading logs.
144        logging.info('Running %s kernel, %s userspace: %s',
145                     arch, userspace_arch,
146                     utils.system_output('uname -a'))
147
148        # Load the list of kernel config variables.
149        config = kernel_config.KernelConfig()
150        config.initialize()
151
152        # Adjust for kernel-version-specific changes
153        kernel_ver = os.uname()[2]
154        if utils.compare_versions(kernel_ver, "3.10") >= 0:
155            for entry in self.IS_EXCLUSIVE:
156                if entry['regex'] == 'BINFMT_':
157                    entry['builtin'].append('BINFMT_SCRIPT')
158
159        if utils.compare_versions(kernel_ver, "3.14") >= 0:
160            self.IS_MODULE.append('TEST_ASYNC_DRIVER_PROBE')
161
162        if utils.compare_versions(kernel_ver, "3.18") >= 0:
163            for entry in self.IS_EXCLUSIVE:
164                if entry['regex'] == '.*_FS$':
165                    entry['builtin'].append('SND_PROC_FS')
166
167        # Run the static checks.
168        map(config.has_builtin, self.IS_BUILTIN)
169        map(config.has_module, self.IS_MODULE)
170        map(config.is_enabled, self.IS_ENABLED)
171        map(config.is_missing, self.IS_MISSING)
172        map(config.is_exclusive, self.IS_EXCLUSIVE)
173
174        # Run the dynamic checks.
175
176        # Security; NULL-address hole should be as large as possible.
177        # Upstream kernel recommends 64k, which should be large enough to
178        # catch nearly all dereferenced structures.
179        wanted = '65536'
180        if self.is_arm_family(arch):
181            # ... except on ARM where it shouldn't be larger than 32k due
182            # to historical ELF load location.
183            wanted = '32768'
184        config.has_value('DEFAULT_MMAP_MIN_ADDR', [wanted])
185
186        # Security; make sure NX page table bits are usable.
187        if self.is_x86_family(arch):
188            if arch == "i386":
189                config.has_builtin('X86_PAE')
190            else:
191                config.has_builtin('X86_64')
192
193        # Security; marks data segments as RO/NX, text as RO.
194        if (arch == 'armv7l' and
195            utils.compare_versions(kernel_ver, "3.8") < 0):
196            config.is_missing('DEBUG_RODATA')
197            config.is_missing('DEBUG_SET_MODULE_RONX')
198        else:
199            config.has_builtin('DEBUG_RODATA')
200            config.has_builtin('DEBUG_SET_MODULE_RONX')
201
202            if arch == 'aarch64':
203                config.has_builtin('DEBUG_ALIGN_RODATA')
204
205        # NaCl; allow mprotect+PROT_EXEC on noexec mapped files.
206        config.has_value('MMAP_NOEXEC_TAINT', ['0'])
207
208        # Kernel: make sure port 0xED is the one used for I/O delay
209        if self.is_x86_family(arch):
210            config.has_builtin('IO_DELAY_0XED')
211            needed = config.get('CONFIG_IO_DELAY_TYPE_0XED', None)
212            config.has_value('DEFAULT_IO_DELAY_TYPE', [needed])
213
214        # Raise a failure if anything unexpected was seen.
215        if len(config.failures()):
216            raise error.TestFail((", ".join(config.failures())))
217