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(2) 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         # We don't need to provide access to *all* symbols in /proc/kallsyms.
     71         'KALLSYMS_ALL',
     72         # bpf(2) syscall can be used to generate code patterns in kernel memory.
     73         'BPF_SYSCALL',
     74         # This callback can be subverted to point to arbitrary programs.  We
     75         # require firmware to be in the rootfs at normal locations which lets
     76         # the kernel locate things itself.
     77         'FW_LOADER_USER_HELPER',
     78         'FW_LOADER_USER_HELPER_FALLBACK',
     79     ]
     80     IS_EXCLUSIVE = [
     81         # Security; no surprise binary formats.
     82         {
     83             'regex': 'BINFMT_',
     84             'builtin': [
     85                 'BINFMT_ELF',
     86             ],
     87             'module': [
     88             ],
     89             'missing': [
     90                 # Sanity checks; one disabled, one does not exist.
     91                 'BINFMT_AOUT',
     92                 'BINFMT_IMPOSSIBLE',
     93             ],
     94         },
     95         # Security; no surprise filesystem formats.
     96         {
     97             'regex': '.*_FS$',
     98             'builtin': [
     99                 'DEBUG_FS',
    100                 'ECRYPT_FS',
    101                 'EXT4_FS',
    102                 'PROC_FS',
    103                 'SCSI_PROC_FS',
    104             ],
    105             'module': [
    106                 'FAT_FS',
    107                 'FUSE_FS',
    108                 'HFSPLUS_FS',
    109                 'ISO9660_FS',
    110                 'UDF_FS',
    111                 'VFAT_FS',
    112             ],
    113             'missing': [
    114                 # Sanity checks; one disabled, one does not exist.
    115                 'EXT2_FS',
    116                 'EXT3_FS',
    117                 'XFS_FS',
    118                 'IMPOSSIBLE_FS',
    119             ],
    120         },
    121         # Security; no surprise partition formats.
    122         # MAC is for external drive formatted on Macintosh.
    123         {
    124             'regex': '.*_PARTITION$',
    125             'builtin': [
    126                 'EFI_PARTITION',
    127                 'MAC_PARTITION',
    128                 'MSDOS_PARTITION',
    129             ],
    130             'module': [
    131             ],
    132             'missing': [
    133                 # Sanity checks; one disabled, one does not exist.
    134                 'LDM_PARTITION',
    135                 'IMPOSSIBLE_PARTITION',
    136             ],
    137         },
    138     ]
    139 
    140     def is_x86_family(self, arch):
    141       """
    142       Returns true if the architecture is x86 family.
    143       """
    144       return arch in ['i386', 'x86_64']
    145 
    146     def run_once(self):
    147         """
    148         The actual test.
    149         """
    150         # Cache the architecture to avoid redundant execs to "uname".
    151         arch = utils.get_arch()
    152         userspace_arch = utils.get_arch_userspace()
    153 
    154         # Report the full uname for anyone reading logs.
    155         logging.info('Running %s kernel, %s userspace: %s',
    156                      arch, userspace_arch,
    157                      utils.system_output('uname -a'))
    158 
    159         # Load the list of kernel config variables.
    160         config = kernel_config.KernelConfig()
    161         config.initialize()
    162 
    163         # Adjust for kernel-version-specific changes
    164         kernel_ver = os.uname()[2]
    165         if utils.compare_versions(kernel_ver, "3.10") >= 0:
    166             for entry in self.IS_EXCLUSIVE:
    167                 if entry['regex'] == 'BINFMT_':
    168                     entry['builtin'].append('BINFMT_SCRIPT')
    169 
    170         if utils.compare_versions(kernel_ver, "3.14") >= 0:
    171             self.IS_MODULE.append('TEST_ASYNC_DRIVER_PROBE')
    172             for entry in self.IS_EXCLUSIVE:
    173                 if entry['regex'] == 'BINFMT_':
    174                     entry['builtin'].append('BINFMT_MISC')
    175                 if entry['regex'] == '.*_FS$':
    176                     entry['module'].append('NFS_FS')
    177 
    178         if utils.compare_versions(kernel_ver, "3.18") >= 0:
    179             for entry in self.IS_EXCLUSIVE:
    180                 if entry['regex'] == '.*_FS$':
    181                     entry['builtin'].append('SND_PROC_FS')
    182 
    183         if utils.compare_versions(kernel_ver, "4.4") < 0:
    184             for entry in self.IS_EXCLUSIVE:
    185                 if entry['regex'] == '.*_FS$':
    186                     entry['builtin'].append('EXT4_USE_FOR_EXT23')
    187 
    188         if utils.compare_versions(kernel_ver, "4.4") >= 0 and \
    189             utils.compare_versions(kernel_ver, "4.12") < 0:
    190             for entry in self.IS_EXCLUSIVE:
    191                 if entry['regex'] == '.*_FS$':
    192                     entry['builtin'].append('ESD_FS')
    193                     entry['builtin'].append('CONFIGFS_FS')
    194 
    195         if utils.compare_versions(kernel_ver, "3.14") >= 0:
    196             self.IS_MISSING.remove('INET_DIAG')
    197 
    198         # Run the static checks.
    199         map(config.has_builtin, self.IS_BUILTIN)
    200         map(config.has_module, self.IS_MODULE)
    201         map(config.is_enabled, self.IS_ENABLED)
    202         map(config.is_missing, self.IS_MISSING)
    203         map(config.is_exclusive, self.IS_EXCLUSIVE)
    204 
    205         # Run the dynamic checks.
    206 
    207         # Security; NULL-address hole should be as large as possible.
    208         # Upstream kernel recommends 64k, which should be large enough
    209         # to catch nearly all dereferenced structures. For
    210         # compatibility with ARM binaries (even on x86) this needs to
    211         # be 32k.
    212         wanted = '32768'
    213         config.has_value('DEFAULT_MMAP_MIN_ADDR', [wanted])
    214 
    215         # Security; make sure NX page table bits are usable.
    216         if self.is_x86_family(arch):
    217             if arch == "i386":
    218                 config.has_builtin('X86_PAE')
    219             else:
    220                 config.has_builtin('X86_64')
    221 
    222         # Security; marks data segments as RO/NX, text as RO.
    223         if utils.compare_versions(kernel_ver, "4.11") < 0:
    224             config.has_builtin('DEBUG_RODATA')
    225             config.has_builtin('DEBUG_SET_MODULE_RONX')
    226         else:
    227             config.has_builtin('STRICT_KERNEL_RWX')
    228             config.has_builtin('STRICT_MODULE_RWX')
    229 
    230         if arch == 'aarch64':
    231             config.has_builtin('DEBUG_ALIGN_RODATA')
    232 
    233         # NaCl; allow mprotect+PROT_EXEC on noexec mapped files.
    234         config.has_value('MMAP_NOEXEC_TAINT', ['0'])
    235 
    236         # Kernel: make sure port 0xED is the one used for I/O delay.
    237         if self.is_x86_family(arch):
    238             config.has_builtin('IO_DELAY_0XED')
    239             needed = config.get('CONFIG_IO_DELAY_TYPE_0XED', None)
    240             config.has_value('DEFAULT_IO_DELAY_TYPE', [needed])
    241 
    242         # Raise a failure if anything unexpected was seen.
    243         if len(config.failures()):
    244             raise error.TestFail((", ".join(config.failures())))
    245