• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import logging, os
6
7from autotest_lib.client.bin import utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.server import test
10
11class security_kASLR(test.test):
12    """Tests the kASLR entropy seen across many reboots of a device
13    """
14    version = 1
15    target_symbol = 'sys_exit'
16    reboot_count = 100
17    reboot_timeout = 60
18
19    def _reboot_machine(self):
20        """Reboot the client machine.
21
22        We'll wait until the client is down, then up again.
23        """
24        boot_id = self._client.get_boot_id()
25        self._client.run('reboot &')
26        self._client.wait_for_restart(old_boot_id=boot_id,
27                                      timeout=self.reboot_timeout,
28                                      down_timeout=self.reboot_timeout,
29                                      down_warning=self.reboot_timeout)
30
31    def _read_kallsyms(self, filename):
32        """Fetch /proc/kallsyms from client and return lines in the file
33
34        @param filename: The file to write 'cat /proc/kallsyms' into.
35        """
36
37        f = open(filename, 'w')
38        self._client.run('cat /proc/kallsyms', stdout_tee=f)
39        f.close()
40
41        return utils.read_file(filename)
42
43    def _parse_kallsyms(self, kallsyms):
44        """ Parse the contents of each line of kallsyms, extracting
45            symbol addresses into a returned hash.
46
47            @param kallsyms: string of kallsyms contents
48        """
49        symbols = {}
50        for line in kallsyms.splitlines():
51            addr, symtype, symbol = line.strip().split(' ', 2)
52            # Just keep regular text symbols for now.
53            if symtype != "T":
54                continue
55            symbols.setdefault(symbol, addr)
56        return symbols
57
58    def run_once(self, host=None):
59        """Run the test.
60
61        @param host: The client machine to connect to; should be a Host object.
62        """
63        assert host is not None, "The host must be specified."
64
65        self._client = host
66
67        # Report client configuration, to help debug any problems.
68        kernel_ver = self._client.run('uname -r').stdout.rstrip()
69        arch = utils.get_arch(self._client.run)
70        logging.info("Starting kASLR tests for '%s' on '%s'",
71                     kernel_ver, arch)
72
73        # Make sure we're expecting kernel ASLR at all.
74        if utils.compare_versions(kernel_ver, "3.8") < 0:
75            logging.info("kASLR not available on this kernel")
76            return
77        if arch.startswith('arm'):
78            logging.info("kASLR not available on this architecture")
79            return
80
81        kallsyms_filename = os.path.join(self.resultsdir, 'kallsyms')
82        address_count = {}
83
84        count = 0
85        while True:
86            kallsyms = self._read_kallsyms(kallsyms_filename)
87            symbols = self._parse_kallsyms(kallsyms)
88
89            assert symbols.has_key(self.target_symbol), \
90                   "The '%s' symbol is missing!?" % (self.target_symbol)
91
92            addr = symbols[self.target_symbol]
93            logging.debug("Reboot %d: Symbol %s @ %s", \
94                          count, self.target_symbol, addr)
95
96            address_count.setdefault(addr, 0)
97            address_count[addr] += 1
98
99            count += 1
100            if count == self.reboot_count:
101                break
102            self._reboot_machine()
103
104        unique = len(address_count)
105        logging.info("Unique kernel offsets: %d", unique)
106        highest = 0
107        for addr in address_count:
108            logging.debug("Address %s: %d", addr, address_count[addr])
109            if address_count[addr] > highest:
110                highest = address_count[addr]
111        if unique < 2:
112            raise error.TestFail("kASLR not functioning")
113        if unique < (self.reboot_count / 3):
114            raise error.TestFail("kASLR entropy seems very low")
115        if highest > (unique / 10):
116            raise error.TestFail("kASLR entropy seems to clump")
117