1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# Copyright (c) 2025 Intel Corporation 5# 6# Test for indirect target selection (ITS) cmdline permutations with other bugs 7# like spectre_v2 and retbleed. 8 9import os, sys, subprocess, itertools, re, shutil 10 11test_dir = os.path.dirname(os.path.realpath(__file__)) 12sys.path.insert(0, test_dir + '/../../kselftest') 13import ksft 14import common as c 15 16bug = "indirect_target_selection" 17mitigation = c.get_sysfs(bug) 18 19if not mitigation or "Not affected" in mitigation: 20 ksft.test_result_skip("Skipping its_permutations.py: not applicable") 21 ksft.finished() 22 23if shutil.which('vng') is None: 24 ksft.test_result_skip("Skipping its_permutations.py: virtme-ng ('vng') not found in PATH.") 25 ksft.finished() 26 27TEST = f"{test_dir}/its_sysfs.py" 28default_kparam = ['clearcpuid=hypervisor', 'panic=5', 'panic_on_warn=1', 'oops=panic', 'nmi_watchdog=1', 'hung_task_panic=1'] 29 30DEBUG = " -v " 31 32# Install dependencies 33# https://github.com/arighi/virtme-ng 34# apt install virtme-ng 35BOOT_CMD = f"vng --run {test_dir}/../../../../../arch/x86/boot/bzImage " 36#BOOT_CMD += DEBUG 37 38bug = "indirect_target_selection" 39 40input_options = { 41 'indirect_target_selection' : ['off', 'on', 'stuff', 'vmexit'], 42 'retbleed' : ['off', 'stuff', 'auto'], 43 'spectre_v2' : ['off', 'on', 'eibrs', 'retpoline', 'ibrs', 'eibrs,retpoline'], 44} 45 46def pretty_print(output): 47 OKBLUE = '\033[94m' 48 OKGREEN = '\033[92m' 49 WARNING = '\033[93m' 50 FAIL = '\033[91m' 51 ENDC = '\033[0m' 52 BOLD = '\033[1m' 53 54 # Define patterns and their corresponding colors 55 patterns = { 56 r"^ok \d+": OKGREEN, 57 r"^not ok \d+": FAIL, 58 r"^# Testing .*": OKBLUE, 59 r"^# Found: .*": WARNING, 60 r"^# Totals: .*": BOLD, 61 r"pass:([1-9]\d*)": OKGREEN, 62 r"fail:([1-9]\d*)": FAIL, 63 r"skip:([1-9]\d*)": WARNING, 64 } 65 66 # Apply colors based on patterns 67 for pattern, color in patterns.items(): 68 output = re.sub(pattern, lambda match: f"{color}{match.group(0)}{ENDC}", output, flags=re.MULTILINE) 69 70 print(output) 71 72combinations = list(itertools.product(*input_options.values())) 73ksft.print_header() 74ksft.set_plan(len(combinations)) 75 76logs = "" 77 78for combination in combinations: 79 append = "" 80 log = "" 81 for p in default_kparam: 82 append += f' --append={p}' 83 command = BOOT_CMD + append 84 test_params = "" 85 for i, key in enumerate(input_options.keys()): 86 param = f'{key}={combination[i]}' 87 test_params += f' {param}' 88 command += f" --append={param}" 89 command += f" -- {TEST}" 90 test_name = f"{bug} {test_params}" 91 pretty_print(f'# Testing {test_name}') 92 t = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 93 t.wait() 94 output, _ = t.communicate() 95 if t.returncode == 0: 96 ksft.test_result_pass(test_name) 97 else: 98 ksft.test_result_fail(test_name) 99 output = output.decode() 100 log += f" {output}" 101 pretty_print(log) 102 logs += output + "\n" 103 104# Optionally use tappy to parse the output 105# apt install python3-tappy 106with open("logs.txt", "w") as f: 107 f.write(logs) 108 109ksft.finished() 110