Home | History | Annotate | Download | only in kernel_ConfigVerify
      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