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 5 import logging, os 6 from autotest_lib.client.bin import test, utils 7 from autotest_lib.client.common_lib import error 8 from autotest_lib.client.cros import kernel_config 9 10 class 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_AOUT', 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 'PROC_FS', 94 'SCSI_PROC_FS', 95 ], 96 'module': [ 97 'FAT_FS', 98 'FUSE_FS', 99 'HFSPLUS_FS', 100 'ISO9660_FS', 101 'UDF_FS', 102 'VFAT_FS', 103 ], 104 'missing': [ 105 # Sanity checks; one disabled, one does not exist. 106 'EXT2_FS', 107 'EXT3_FS', 108 'XFS_FS', 109 'IMPOSSIBLE_FS', 110 ], 111 }, 112 # Security; no surprise partition formats. 113 # MAC is for external drive formatted on Macintosh. 114 { 115 'regex': '.*_PARTITION$', 116 'builtin': [ 117 'EFI_PARTITION', 118 'MAC_PARTITION', 119 'MSDOS_PARTITION', 120 ], 121 'module': [ 122 ], 123 'missing': [ 124 # Sanity checks; one disabled, one does not exist. 125 'LDM_PARTITION', 126 'IMPOSSIBLE_PARTITION', 127 ], 128 }, 129 ] 130 131 def is_arm_family(self, arch): 132 return arch in ['armv7l', 'aarch64'] 133 134 def is_x86_family(self, arch): 135 return arch in ['i386', 'x86_64'] 136 137 def run_once(self): 138 # Cache the architecture to avoid redundant execs to "uname". 139 arch = utils.get_arch() 140 userspace_arch = utils.get_arch_userspace() 141 142 # Report the full uname for anyone reading logs. 143 logging.info('Running %s kernel, %s userspace: %s', 144 arch, userspace_arch, 145 utils.system_output('uname -a')) 146 147 # Load the list of kernel config variables. 148 config = kernel_config.KernelConfig() 149 config.initialize() 150 151 # Adjust for kernel-version-specific changes 152 kernel_ver = os.uname()[2] 153 if utils.compare_versions(kernel_ver, "3.10") >= 0: 154 for entry in self.IS_EXCLUSIVE: 155 if entry['regex'] == 'BINFMT_': 156 entry['builtin'].append('BINFMT_SCRIPT') 157 158 if utils.compare_versions(kernel_ver, "3.14") >= 0: 159 self.IS_MODULE.append('TEST_ASYNC_DRIVER_PROBE') 160 for entry in self.IS_EXCLUSIVE: 161 if entry['regex'] == 'BINFMT_': 162 entry['builtin'].append('BINFMT_MISC') 163 164 165 if utils.compare_versions(kernel_ver, "3.18") >= 0: 166 for entry in self.IS_EXCLUSIVE: 167 if entry['regex'] == '.*_FS$': 168 entry['builtin'].append('SND_PROC_FS') 169 170 if utils.compare_versions(kernel_ver, "4.4") < 0: 171 for entry in self.IS_EXCLUSIVE: 172 if entry['regex'] == '.*_FS$': 173 entry['builtin'].append('EXT4_USE_FOR_EXT23') 174 175 # Run the static checks. 176 map(config.has_builtin, self.IS_BUILTIN) 177 map(config.has_module, self.IS_MODULE) 178 map(config.is_enabled, self.IS_ENABLED) 179 map(config.is_missing, self.IS_MISSING) 180 map(config.is_exclusive, self.IS_EXCLUSIVE) 181 182 # Run the dynamic checks. 183 184 # Security; NULL-address hole should be as large as possible. 185 # Upstream kernel recommends 64k, which should be large enough to 186 # catch nearly all dereferenced structures. 187 wanted = '65536' 188 if self.is_arm_family(arch): 189 # ... except on ARM where it shouldn't be larger than 32k due 190 # to historical ELF load location. 191 wanted = '32768' 192 config.has_value('DEFAULT_MMAP_MIN_ADDR', [wanted]) 193 194 # Security; make sure NX page table bits are usable. 195 if self.is_x86_family(arch): 196 if arch == "i386": 197 config.has_builtin('X86_PAE') 198 else: 199 config.has_builtin('X86_64') 200 201 # Security; marks data segments as RO/NX, text as RO. 202 if (arch == 'armv7l' and 203 utils.compare_versions(kernel_ver, "3.8") < 0): 204 config.is_missing('DEBUG_RODATA') 205 config.is_missing('DEBUG_SET_MODULE_RONX') 206 else: 207 config.has_builtin('DEBUG_RODATA') 208 config.has_builtin('DEBUG_SET_MODULE_RONX') 209 210 if arch == 'aarch64': 211 config.has_builtin('DEBUG_ALIGN_RODATA') 212 213 # NaCl; allow mprotect+PROT_EXEC on noexec mapped files. 214 config.has_value('MMAP_NOEXEC_TAINT', ['0']) 215 216 # Kernel: make sure port 0xED is the one used for I/O delay 217 if self.is_x86_family(arch): 218 config.has_builtin('IO_DELAY_0XED') 219 needed = config.get('CONFIG_IO_DELAY_TYPE_0XED', None) 220 config.has_value('DEFAULT_IO_DELAY_TYPE', [needed]) 221 222 # Raise a failure if anything unexpected was seen. 223 if len(config.failures()): 224 raise error.TestFail((", ".join(config.failures()))) 225