common.py 4.7 KB

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