system.py 10.2 KB
Newer Older
A
air9 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/env python
# coding: utf-8

# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01

import os
import sys
import re
import argparse

20
from hwcompatible.test import Test
C
cuixucui 已提交
21
from hwcompatible.command import Command
22 23 24
from hwcompatible.sysinfo import SysInfo
from hwcompatible.env import CertEnv
from hwcompatible.document import Document
A
air9 已提交
25 26 27


class SystemTest(Test):
C
cuixucui 已提交
28 29 30
    """
    System Test
    """
A
air9 已提交
31 32 33 34
    def __init__(self):
        Test.__init__(self)
        self.pri = 1
        self.sysinfo = SysInfo(CertEnv.releasefile)
C
cuixucui 已提交
35 36
        self.args = None
        self.logdir = None
A
air9 已提交
37 38

    def setup(self, args=None):
C
cuixucui 已提交
39 40 41 42 43
        """
        Initialization before test
        :param args:
        :return:
        """
A
air9 已提交
44 45 46 47
        self.args = args or argparse.Namespace()
        self.logdir = getattr(args, "logdir", None)

    def test(self):
C
cuixucui 已提交
48 49 50 51
        """
        test case
        :return:
        """
A
air9 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
        os.system("uname -a")
        print("")
        os.system("lsmod")
        print("")
        os.system("dmidecode")
        sys.stdout.flush()

        return_code = True
        if not self.check_certrpm():
            return_code = False

        if not self.check_kernel():
            return_code = False

        if not self.check_selinux():
            return_code = False

        return return_code

C
cuixucui 已提交
71 72
    @staticmethod
    def check_certrpm():
C
cuixucui 已提交
73 74 75 76
        """
        Check installed cert package
        :return:
        """
A
air9 已提交
77 78 79 80 81 82 83 84 85
        print("\nChecking installed cert package...")
        return_code = True
        for cert_package in ["oec-hardware"]:
            rpm_verify = Command("rpm -V --nomtime --nomode --nocontexts %s" % cert_package)
            try:
                rpm_verify.echo()
                sys.stdout.flush()
                if rpm_verify.output and len(rpm_verify.output) > 0:
                    return_code = False
C
cuixucui 已提交
86
            except:
A
air9 已提交
87 88 89 90 91
                print("Error: files in %s have been tampered." % cert_package)
                return_code = False
        return return_code

    def check_kernel(self):
C
cuixucui 已提交
92 93 94 95
        """
        Check kernel
        :return:
        """
A
air9 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
        print("\nChecking kernel...")
        kernel_rpm = self.sysinfo.kernel_rpm
        os_version = self.sysinfo.product + " " + self.sysinfo.get_version()
        print("Kernel RPM: %s" % kernel_rpm)
        print("OS Version: %s" % os_version)
        print("")
        return_code = True
        if self.sysinfo.debug_kernel:
            print("Error: debug kernel.")
            return_code = False

        kernel_dict = Document(CertEnv.kernelinfo)
        if not kernel_dict.load():
            print("Error: get kernel info fail.")
            return False

        try:
            if kernel_dict.document[os_version] != self.sysinfo.kernel_version:
                print("Error: kernel %s check GA status fail." % self.sysinfo.kernel_version)
                return_code = False
C
cuixucui 已提交
116
        except:
A
air9 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
            print("Error: %s is not supported." % os_version)
            return_code = False

        try:
            tainted_file = open("/proc/sys/kernel/tainted", "r")
            tainted = int(tainted_file.readline())
            if tainted != 0:
                print("Warning: kernel is tainted (value = %u)." % tainted)
                if tainted & 1:
                    print("Error: module with a non-GPL license has been loaded.")
                    return_code = False
                    modules = self.get_modules("P")
                    print("Non-GPL modules:")
                    for module in modules:
                        print(module)
                    print("")

C
cuixucui 已提交
134
                if tainted & (1 << 12):
A
air9 已提交
135 136 137 138
                    modules = self.get_modules("O")
                    print("Out-of-tree modules:")
                    for module in modules:
                        print(module)
C
cuixucui 已提交
139
                        # self.abi_check(module)
A
air9 已提交
140 141 142
                        return_code = False
                    print("")

C
cuixucui 已提交
143
                if tainted & (1 << 13):
A
air9 已提交
144 145 146 147 148 149 150
                    modules = self.get_modules("E")
                    print("Unsigned modules:")
                    for module in modules:
                        print(module)
                    print("")

            tainted_file.close()
C
cuixucui 已提交
151
        except Exception as e:
A
air9 已提交
152 153 154 155 156 157 158 159 160 161 162 163
            print(e)
            print("Error: could not determine if kernel is tainted.")
            return_code = False

        if not os.system("rpm -V --nomtime --nomode --nocontexts %s" % kernel_rpm) is 0:
            print("Error: files from %s were modified." % kernel_rpm)
            print("")
            return_code = False

        try:
            params = Command("cat /proc/cmdline").get_str()
            print("Boot Parameters: %s" % params)
C
cuixucui 已提交
164
        except Exception as e:
A
air9 已提交
165 166 167 168 169 170
            print(e)
            print("Error: could not determine boot parameters.")
            return_code = False

        return return_code

C
cuixucui 已提交
171 172
    @staticmethod
    def get_modules(sign):
C
cuixucui 已提交
173 174 175 176 177
        """
        Get the module with signs character
        :param sign:
        :return:
        """
C
cuixucui 已提交
178
        pattern = re.compile(r"^(?P<mod_name>\w+)[\s\S]+\((?P<signs>[A-Z]+)\)")
A
air9 已提交
179 180 181 182 183 184 185 186 187 188 189
        proc_modules = open("/proc/modules")
        modules = list()
        for line in proc_modules.readlines():
            match = pattern.match(line)
            if match:
                if sign in match.group("signs"):
                    modules.append(match.group("mod_name"))
        proc_modules.close()
        return modules

    def abi_check(self, module):
C
cuixucui 已提交
190 191 192 193 194
        """
        Check abi whitelist
        :param module:
        :return:
        """
A
air9 已提交
195
        whitelist_path = [("/lib/modules/kabi-current/kabi_whitelist_" + self.sysinfo.arch),
C
cuixucui 已提交
196 197 198 199
                          ("/lib/modules/kabi/kabi_whitelist_" + self.sysinfo.arch),
                          ("/usr/src/kernels/%s/kabi_whitelist" % self.sysinfo.kernel)
                          ]
        whitelist = ""
A
air9 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
        for whitelist in whitelist_path:
            if os.path.exists(whitelist):
                break

        if not os.path.exists(whitelist):
            print("Error: could not find whitelist file in any of the following locations:")
            print("\n".join(whitelist_path))
            return False

        whitelist_symbols = self.read_abi_whitelist(whitelist)
        if not whitelist_symbols:
            return False
        module_symbols = self.read_module(module)
        if not module_symbols:
            return False
        extra_symbols = list()
        for symbol in module_symbols:
            if symbol not in whitelist_symbols:
                extra_symbols.append(symbol)

        black_symbols = list()
        if extra_symbols:
            greylist = "/usr/share/doc/kmod-%s/greylist.txt" % module
            if os.path.exists(greylist):
                print("checking greylist for %s" % module)
                greylist_symbols = self.read_abi_whitelist(greylist)
                for symbol in extra_symbols:
                    if symbol not in greylist_symbols:
                        black_symbols.append(symbol)
            else:
                black_symbols = extra_symbols

        if black_symbols:
            print("Error: The following symbols are used by %s are not on the ABI whitelist." % module)
            for symbol in black_symbols:
                print(symbol)
            return False

        print("")
        return True

C
cuixucui 已提交
241 242
    @staticmethod
    def read_abi_whitelist(whitelist):
C
cuixucui 已提交
243 244 245 246 247
        """
        Read abi whitelist
        :param whitelist:
        :return:
        """
A
air9 已提交
248 249 250 251 252
        symbols = list()
        if not os.path.isfile(whitelist):
            print("Error: Cannot read whitelist file")
            return None

C
cuixucui 已提交
253
        whitelistfile = open(whitelist, "r")
A
air9 已提交
254
        while True:
C
cuixucui 已提交
255
            line = whitelistfile.readline()
A
air9 已提交
256 257 258 259 260 261
            if line == "":
                break
            if line == "\n":
                continue
            line.split()
            if line[0] == '[':
C
cuixucui 已提交
262
                # group = line[1:-2]
A
air9 已提交
263
                continue
C
cuixucui 已提交
264
            symbol = line.strip()
A
air9 已提交
265 266 267 268 269
            symbols.append(symbol)

        return symbols

    def read_module(self, module):
C
cuixucui 已提交
270 271 272 273 274
        """
        Read module
        :param module:
        :return:
        """
A
air9 已提交
275
        symbols = list()
C
cuixucui 已提交
276
        module_file = self.get_modulefile(module)
A
air9 已提交
277

C
cuixucui 已提交
278
        if not module_file:
A
air9 已提交
279 280
            print("Error: Can not find module file for %s" % module)
            return None
C
cuixucui 已提交
281 282
        if not os.path.isfile(module_file):
            print("Error: Cannot read module file %s" % module_file)
A
air9 已提交
283 284
            return None

C
cuixucui 已提交
285 286
        if module_file[-2:] == "ko":
            nm = os.popen('modprobe --dump-modversions ' + module_file)
A
air9 已提交
287
        else:
C
cuixucui 已提交
288
            nm = open(module_file, "r")
A
air9 已提交
289 290 291 292 293 294 295 296 297 298

        while True:
            line = nm.readline()
            if line == "":
                break
            symbols.append(line)

        nm.close()
        return self.readSymbols(symbols)

C
cuixucui 已提交
299 300
    @staticmethod
    def get_modulefile(module):
C
cuixucui 已提交
301 302 303 304 305
        """
        Get module file
        :param module:
        :return:
        """
A
air9 已提交
306 307 308 309 310
        try:
            modulefile = Command("modinfo -F filename %s" % module).get_str()
            if os.path.islink(modulefile):
                modulefile = os.readlink(modulefile)
            return modulefile
C
cuixucui 已提交
311
        except:
A
air9 已提交
312 313 314
            print("Error: could no find module file for %s:" % module)
            return None

C
cuixucui 已提交
315 316
    @staticmethod
    def check_selinux():
C
cuixucui 已提交
317 318 319 320
        """
        check selinux
        :return:
        """
A
air9 已提交
321 322 323 324 325 326 327 328 329 330
        print("\nChecking selinux...")
        status = os.system("/usr/sbin/sestatus | grep 'SELinux status' | grep -qw 'enabled'")
        mode = os.system("/usr/sbin/sestatus | grep 'Current mode' | grep -qw 'enforcing'")
        if mode == 0 and status == 0:
            print("SElinux is enforcing.")
            return True
        else:
            print("SElinux is not enforcing.")
            os.system("/usr/sbin/sestatus")
            return False