1*7a9b709eSPawan Gupta#!/usr/bin/env python3 2*7a9b709eSPawan Gupta# SPDX-License-Identifier: GPL-2.0 3*7a9b709eSPawan Gupta# 4*7a9b709eSPawan Gupta# Copyright (c) 2025 Intel Corporation 5*7a9b709eSPawan Gupta# 6*7a9b709eSPawan Gupta# This contains kselftest framework adapted common functions for testing 7*7a9b709eSPawan Gupta# mitigation for x86 bugs. 8*7a9b709eSPawan Gupta 9*7a9b709eSPawan Guptaimport os, sys, re, shutil 10*7a9b709eSPawan Gupta 11*7a9b709eSPawan Guptasys.path.insert(0, '../../kselftest') 12*7a9b709eSPawan Guptaimport ksft 13*7a9b709eSPawan Gupta 14*7a9b709eSPawan Guptadef read_file(path): 15*7a9b709eSPawan Gupta if not os.path.exists(path): 16*7a9b709eSPawan Gupta return None 17*7a9b709eSPawan Gupta with open(path, 'r') as file: 18*7a9b709eSPawan Gupta return file.read().strip() 19*7a9b709eSPawan Gupta 20*7a9b709eSPawan Guptadef cpuinfo_has(arg): 21*7a9b709eSPawan Gupta cpuinfo = read_file('/proc/cpuinfo') 22*7a9b709eSPawan Gupta if arg in cpuinfo: 23*7a9b709eSPawan Gupta return True 24*7a9b709eSPawan Gupta return False 25*7a9b709eSPawan Gupta 26*7a9b709eSPawan Guptadef cmdline_has(arg): 27*7a9b709eSPawan Gupta cmdline = read_file('/proc/cmdline') 28*7a9b709eSPawan Gupta if arg in cmdline: 29*7a9b709eSPawan Gupta return True 30*7a9b709eSPawan Gupta return False 31*7a9b709eSPawan Gupta 32*7a9b709eSPawan Guptadef cmdline_has_either(args): 33*7a9b709eSPawan Gupta cmdline = read_file('/proc/cmdline') 34*7a9b709eSPawan Gupta for arg in args: 35*7a9b709eSPawan Gupta if arg in cmdline: 36*7a9b709eSPawan Gupta return True 37*7a9b709eSPawan Gupta return False 38*7a9b709eSPawan Gupta 39*7a9b709eSPawan Guptadef cmdline_has_none(args): 40*7a9b709eSPawan Gupta return not cmdline_has_either(args) 41*7a9b709eSPawan Gupta 42*7a9b709eSPawan Guptadef cmdline_has_all(args): 43*7a9b709eSPawan Gupta cmdline = read_file('/proc/cmdline') 44*7a9b709eSPawan Gupta for arg in args: 45*7a9b709eSPawan Gupta if arg not in cmdline: 46*7a9b709eSPawan Gupta return False 47*7a9b709eSPawan Gupta return True 48*7a9b709eSPawan Gupta 49*7a9b709eSPawan Guptadef get_sysfs(bug): 50*7a9b709eSPawan Gupta return read_file("/sys/devices/system/cpu/vulnerabilities/" + bug) 51*7a9b709eSPawan Gupta 52*7a9b709eSPawan Guptadef sysfs_has(bug, mitigation): 53*7a9b709eSPawan Gupta status = get_sysfs(bug) 54*7a9b709eSPawan Gupta if mitigation in status: 55*7a9b709eSPawan Gupta return True 56*7a9b709eSPawan Gupta return False 57*7a9b709eSPawan Gupta 58*7a9b709eSPawan Guptadef sysfs_has_either(bugs, mitigations): 59*7a9b709eSPawan Gupta for bug in bugs: 60*7a9b709eSPawan Gupta for mitigation in mitigations: 61*7a9b709eSPawan Gupta if sysfs_has(bug, mitigation): 62*7a9b709eSPawan Gupta return True 63*7a9b709eSPawan Gupta return False 64*7a9b709eSPawan Gupta 65*7a9b709eSPawan Guptadef sysfs_has_none(bugs, mitigations): 66*7a9b709eSPawan Gupta return not sysfs_has_either(bugs, mitigations) 67*7a9b709eSPawan Gupta 68*7a9b709eSPawan Guptadef sysfs_has_all(bugs, mitigations): 69*7a9b709eSPawan Gupta for bug in bugs: 70*7a9b709eSPawan Gupta for mitigation in mitigations: 71*7a9b709eSPawan Gupta if not sysfs_has(bug, mitigation): 72*7a9b709eSPawan Gupta return False 73*7a9b709eSPawan Gupta return True 74*7a9b709eSPawan Gupta 75*7a9b709eSPawan Guptadef bug_check_pass(bug, found): 76*7a9b709eSPawan Gupta ksft.print_msg(f"\nFound: {found}") 77*7a9b709eSPawan Gupta # ksft.print_msg(f"\ncmdline: {read_file('/proc/cmdline')}") 78*7a9b709eSPawan Gupta ksft.test_result_pass(f'{bug}: {found}') 79*7a9b709eSPawan Gupta 80*7a9b709eSPawan Guptadef bug_check_fail(bug, found, expected): 81*7a9b709eSPawan Gupta ksft.print_msg(f'\nFound:\t {found}') 82*7a9b709eSPawan Gupta ksft.print_msg(f'Expected:\t {expected}') 83*7a9b709eSPawan Gupta ksft.print_msg(f"\ncmdline: {read_file('/proc/cmdline')}") 84*7a9b709eSPawan Gupta ksft.test_result_fail(f'{bug}: {found}') 85*7a9b709eSPawan Gupta 86*7a9b709eSPawan Guptadef bug_status_unknown(bug, found): 87*7a9b709eSPawan Gupta ksft.print_msg(f'\nUnknown status: {found}') 88*7a9b709eSPawan Gupta ksft.print_msg(f"\ncmdline: {read_file('/proc/cmdline')}") 89*7a9b709eSPawan Gupta ksft.test_result_fail(f'{bug}: {found}') 90*7a9b709eSPawan Gupta 91*7a9b709eSPawan Guptadef basic_checks_sufficient(bug, mitigation): 92*7a9b709eSPawan Gupta if not mitigation: 93*7a9b709eSPawan Gupta bug_status_unknown(bug, "None") 94*7a9b709eSPawan Gupta return True 95*7a9b709eSPawan Gupta elif mitigation == "Not affected": 96*7a9b709eSPawan Gupta ksft.test_result_pass(bug) 97*7a9b709eSPawan Gupta return True 98*7a9b709eSPawan Gupta elif mitigation == "Vulnerable": 99*7a9b709eSPawan Gupta if cmdline_has_either([f'{bug}=off', 'mitigations=off']): 100*7a9b709eSPawan Gupta bug_check_pass(bug, mitigation) 101*7a9b709eSPawan Gupta return True 102*7a9b709eSPawan Gupta return False 103*7a9b709eSPawan Gupta 104*7a9b709eSPawan Guptadef get_section_info(vmlinux, section_name): 105*7a9b709eSPawan Gupta from elftools.elf.elffile import ELFFile 106*7a9b709eSPawan Gupta with open(vmlinux, 'rb') as f: 107*7a9b709eSPawan Gupta elffile = ELFFile(f) 108*7a9b709eSPawan Gupta section = elffile.get_section_by_name(section_name) 109*7a9b709eSPawan Gupta if section is None: 110*7a9b709eSPawan Gupta ksft.print_msg("Available sections in vmlinux:") 111*7a9b709eSPawan Gupta for sec in elffile.iter_sections(): 112*7a9b709eSPawan Gupta ksft.print_msg(sec.name) 113*7a9b709eSPawan Gupta raise ValueError(f"Section {section_name} not found in {vmlinux}") 114*7a9b709eSPawan Gupta return section['sh_addr'], section['sh_offset'], section['sh_size'] 115*7a9b709eSPawan Gupta 116*7a9b709eSPawan Guptadef get_patch_sites(vmlinux, offset, size): 117*7a9b709eSPawan Gupta import struct 118*7a9b709eSPawan Gupta output = [] 119*7a9b709eSPawan Gupta with open(vmlinux, 'rb') as f: 120*7a9b709eSPawan Gupta f.seek(offset) 121*7a9b709eSPawan Gupta i = 0 122*7a9b709eSPawan Gupta while i < size: 123*7a9b709eSPawan Gupta data = f.read(4) # s32 124*7a9b709eSPawan Gupta if not data: 125*7a9b709eSPawan Gupta break 126*7a9b709eSPawan Gupta sym_offset = struct.unpack('<i', data)[0] + i 127*7a9b709eSPawan Gupta i += 4 128*7a9b709eSPawan Gupta output.append(sym_offset) 129*7a9b709eSPawan Gupta return output 130*7a9b709eSPawan Gupta 131*7a9b709eSPawan Guptadef get_instruction_from_vmlinux(elffile, section, virtual_address, target_address): 132*7a9b709eSPawan Gupta from capstone import Cs, CS_ARCH_X86, CS_MODE_64 133*7a9b709eSPawan Gupta section_start = section['sh_addr'] 134*7a9b709eSPawan Gupta section_end = section_start + section['sh_size'] 135*7a9b709eSPawan Gupta 136*7a9b709eSPawan Gupta if not (section_start <= target_address < section_end): 137*7a9b709eSPawan Gupta return None 138*7a9b709eSPawan Gupta 139*7a9b709eSPawan Gupta offset = target_address - section_start 140*7a9b709eSPawan Gupta code = section.data()[offset:offset + 16] 141*7a9b709eSPawan Gupta 142*7a9b709eSPawan Gupta cap = init_capstone() 143*7a9b709eSPawan Gupta for instruction in cap.disasm(code, target_address): 144*7a9b709eSPawan Gupta if instruction.address == target_address: 145*7a9b709eSPawan Gupta return instruction 146*7a9b709eSPawan Gupta return None 147*7a9b709eSPawan Gupta 148*7a9b709eSPawan Guptadef init_capstone(): 149*7a9b709eSPawan Gupta from capstone import Cs, CS_ARCH_X86, CS_MODE_64, CS_OPT_SYNTAX_ATT 150*7a9b709eSPawan Gupta cap = Cs(CS_ARCH_X86, CS_MODE_64) 151*7a9b709eSPawan Gupta cap.syntax = CS_OPT_SYNTAX_ATT 152*7a9b709eSPawan Gupta return cap 153*7a9b709eSPawan Gupta 154*7a9b709eSPawan Guptadef get_runtime_kernel(): 155*7a9b709eSPawan Gupta import drgn 156*7a9b709eSPawan Gupta return drgn.program_from_kernel() 157*7a9b709eSPawan Gupta 158*7a9b709eSPawan Guptadef check_dependencies_or_skip(modules, script_name="unknown test"): 159*7a9b709eSPawan Gupta for mod in modules: 160*7a9b709eSPawan Gupta try: 161*7a9b709eSPawan Gupta __import__(mod) 162*7a9b709eSPawan Gupta except ImportError: 163*7a9b709eSPawan Gupta ksft.test_result_skip(f"Skipping {script_name}: missing module '{mod}'") 164*7a9b709eSPawan Gupta ksft.finished() 165