Home | History | Annotate | Download | only in security_x86Registers
      1 # Copyright (c) 2013 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, time
      6 from autotest_lib.client.bin import test, utils
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.client.cros.power import power_utils
      9 from autotest_lib.client.cros.power import sys_power
     10 
     11 MSR_POSITIVE = {
     12     'Atom': {
     13         # VMX does not exist on Atom (so it reports as disabled).
     14         '0x3a':  [('2:0', 1)],
     15         },
     16     'Non-Atom': {
     17         # IA32_FEATURE_CONTROL[2:0]
     18         #   0 - Lock bit (1 = locked)
     19         #   1 - Enable VMX in SMX operation
     20         #   2 - Enable VMX outside SMX operation
     21         # Want value "1": VMX locked and disabled in all modes.
     22         '0x3a':  [('2:0', 1)],
     23         },
     24     'Stoney': {
     25         # VM_CR MSR (C001_0114h) with SVMDIS Bit 4
     26         # can be used to lock writes to EFER.SVME
     27         #   0 - writes to EFER.SVME are not blocked
     28         #   1 - writes to EFER treat EFER.SVME as MBZ
     29         '0xc0010114':  [('4', 0)],
     30         },
     31     }
     32 
     33 MSR_NEGATIVE = {
     34     'Atom': {
     35         # Inverted from positive case: none of these bits should be set.
     36         '0x3a':  [('2:0', 6)],
     37         },
     38     'Non-Atom': {
     39         # Inverted from positive case: none of these bits should be set.
     40         '0x3a':  [('2:0', 6)],
     41         },
     42     'Stoney': {
     43         # Inverted from positive case: none of these bits should be set.
     44         '0xc0010114':  [('4', 1)],
     45         },
     46     }
     47 
     48 RCBA_POSITIVE = {
     49     'Atom': {
     50         # GCS.BILD is not set on H2C UEFI Firmware. :(
     51         # https://code.google.com/p/chromium/issues/detail?id=269633
     52         '0x3410': [('0', 0)],
     53         },
     54     'Non-Atom': {
     55         # GCS (General Control and Status) register, BILD (BIOS Interface
     56         # Lock-Down) bit should be set.
     57         '0x3410': [('0', 1)],
     58         },
     59     'Stoney': {
     60         # Skipping this test as there is no register to change
     61         # reset vector on Stoney. NA for Stoney.
     62         },
     63     }
     64 
     65 RCBA_NEGATIVE = {
     66     'Atom': {
     67         # GCS register, BILD bit inverted from positive test.
     68         '0x3410': [('0', 1)],
     69         },
     70     'Non-Atom': {
     71         # GCS register, BILD bit inverted from positive test.
     72         '0x3410': [('0', 0)],
     73         },
     74     'Stoney': {
     75         },
     76     }
     77 
     78 class security_x86Registers(test.test):
     79     """
     80     Checks various CPU and firmware registers for security-sensitive safe
     81     settings.
     82     """
     83     version = 1
     84 
     85     def _check_negative_positive(self, name, func, match_neg, match_pos):
     86         errors = 0
     87 
     88         # Catch missing test conditions.
     89         if len(match_neg) == 0:
     90             logging.debug('No inverted %s tests defined!', name)
     91         if len(match_pos) == 0:
     92             logging.debug('No positive %s tests defined!', name)
     93         if len(match_neg) == 0 or len(match_pos) == 0:
     94             return errors
     95 
     96         # Negative tests; make sure infrastructure is working.
     97         logging.debug("=== BEGIN [expecting %s FAILs] ===", name)
     98         if func(match_neg) == 0:
     99             logging.error('BAD: inverted %s tests did not fail!', name)
    100             errors += 1
    101         logging.debug("=== END [expecting %s FAILs] ===", name)
    102 
    103         # Positive tests; make sure values are for real.
    104         logging.debug("=== BEGIN [expecting %s oks] ===", name)
    105         errors += func(match_pos)
    106         logging.debug("=== END [expecting %s oks] ===", name)
    107 
    108         logging.debug("%s errors found: %d", name, errors)
    109         return errors
    110 
    111     def _check_msr(self):
    112         return self._check_negative_positive('MSR',
    113                                              self._registers.verify_msr,
    114                                              MSR_NEGATIVE[self._cpu_type],
    115                                              MSR_POSITIVE[self._cpu_type])
    116 
    117     def _check_bios(self):
    118         return self._check_negative_positive('BIOS',
    119                                              self._registers.verify_rcba,
    120                                              RCBA_NEGATIVE[self._cpu_type],
    121                                              RCBA_POSITIVE[self._cpu_type])
    122 
    123     def _check_all(self):
    124         errors = 0
    125         errors += self._check_msr()
    126         errors += self._check_bios()
    127         return errors
    128 
    129     def run_once(self):
    130         errors = 0
    131 
    132         cpu_arch = power_utils.get_x86_cpu_arch()
    133         if not cpu_arch:
    134             cpu_arch = utils.get_cpu_arch()
    135             if cpu_arch == "arm":
    136                 logging.info('OK: skipping x86-only test on %s.', cpu_arch)
    137                 return
    138             raise error.TestNAError('Unknown CPU with arch "%s".' % (cpu_arch))
    139 
    140         if cpu_arch == 'Stoney':
    141             self._cpu_type = 'Stoney'
    142         elif cpu_arch == 'Atom':
    143             self._cpu_type = 'Atom'
    144         else:
    145             self._cpu_type = 'Non-Atom'
    146 
    147         self._registers = power_utils.Registers()
    148 
    149         # Check running machine.
    150         errors += self._check_all()
    151 
    152         # Pause briefly to make sure the RTC is ready for suspend/resume.
    153         time.sleep(3)
    154         # Suspend the system to RAM and return after 10 seconds.
    155         sys_power.do_suspend(10)
    156 
    157         # Check resumed machine.
    158         errors += self._check_all()
    159 
    160         if errors > 0:
    161             raise error.TestFail('x86 register mismatch detected')
    162