system.py 10.1 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
    def check_certrpm(self):
C
cuixucui 已提交
72 73 74 75
        """
        Check installed cert package
        :return:
        """
A
air9 已提交
76 77 78 79 80 81 82 83 84
        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 已提交
85
            except:
A
air9 已提交
86 87 88 89 90
                print("Error: files in %s have been tampered." % cert_package)
                return_code = False
        return return_code

    def check_kernel(self):
C
cuixucui 已提交
91 92 93 94
        """
        Check kernel
        :return:
        """
A
air9 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
        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 已提交
115
        except:
A
air9 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
            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 已提交
133
                if tainted & (1 << 12):
A
air9 已提交
134 135 136 137
                    modules = self.get_modules("O")
                    print("Out-of-tree modules:")
                    for module in modules:
                        print(module)
C
cuixucui 已提交
138
                        # self.abi_check(module)
A
air9 已提交
139 140 141
                        return_code = False
                    print("")

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

            tainted_file.close()
C
cuixucui 已提交
150
        except Exception as e:
A
air9 已提交
151 152 153 154 155 156 157 158 159 160 161 162
            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 已提交
163
        except Exception as e:
A
air9 已提交
164 165 166 167 168 169
            print(e)
            print("Error: could not determine boot parameters.")
            return_code = False

        return return_code

C
cuixucui 已提交
170
    def get_modules(self, sign):
C
cuixucui 已提交
171 172 173 174 175
        """
        Get the module with signs character
        :param sign:
        :return:
        """
C
cuixucui 已提交
176
        pattern = re.compile(r"^(?P<mod_name>\w+)[\s\S]+\((?P<signs>[A-Z]+)\)")
A
air9 已提交
177 178 179 180 181 182 183 184 185 186 187
        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 已提交
188 189 190 191 192
        """
        Check abi whitelist
        :param module:
        :return:
        """
A
air9 已提交
193
        whitelist_path = [("/lib/modules/kabi-current/kabi_whitelist_" + self.sysinfo.arch),
C
cuixucui 已提交
194 195 196 197
                          ("/lib/modules/kabi/kabi_whitelist_" + self.sysinfo.arch),
                          ("/usr/src/kernels/%s/kabi_whitelist" % self.sysinfo.kernel)
                          ]
        whitelist = ""
A
air9 已提交
198 199 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
        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 已提交
239
    def read_abi_whitelist(self, whitelist):
C
cuixucui 已提交
240 241 242 243 244
        """
        Read abi whitelist
        :param whitelist:
        :return:
        """
A
air9 已提交
245 246 247 248 249
        symbols = list()
        if not os.path.isfile(whitelist):
            print("Error: Cannot read whitelist file")
            return None

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

        return symbols

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

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

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

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

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

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

C
cuixucui 已提交
311
    def check_selinux(self):
C
cuixucui 已提交
312 313 314 315
        """
        check selinux
        :return:
        """
A
air9 已提交
316 317 318 319 320 321 322 323 324 325
        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