From 0fd65bf03efa3d18198b576609d703e3132d947d Mon Sep 17 00:00:00 2001 From: Narasimhan V <16101053+narasimhan-v@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:48:30 +0530 Subject: [PATCH] Adding SRSO Mitigation Test Added a test to check SRSO vulnerability and mitigation status. We also run the srso kernel selftest which verifies the same. Signed-off-by: Narasimhan V <16101053+narasimhan-v@users.noreply.github.com> --- kernel/srso_mitigation.py | 115 ++++++++++++++++++++++ kernel/srso_mitigation.py.data/Readme.txt | 32 ++++++ kernel/srso_mitigation.yaml | 1 + 3 files changed, 148 insertions(+) create mode 100644 kernel/srso_mitigation.py create mode 100644 kernel/srso_mitigation.py.data/Readme.txt create mode 100644 kernel/srso_mitigation.yaml diff --git a/kernel/srso_mitigation.py b/kernel/srso_mitigation.py new file mode 100644 index 000000000..7303992f5 --- /dev/null +++ b/kernel/srso_mitigation.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# +# Copyright: 2026 AMD +# Author: Narasimhan V + +import os +import shutil +import re + +from avocado import Test +from avocado.utils import build, process, download, distro, genio +from avocado.utils.software_manager.manager import SoftwareManager + + +class SRSOTest(Test): + """ + 1. SRSO Selftest available as a part of kernel source code. + run the selftest available at tools/testing/selftest/x86/srso.c + + 2. check the sysfs for vulnerability status. + + :see: https://docs.kernel.org/admin-guide/hw-vuln/srso.html + + :avocado: tags=kernel + """ + + def setUp(self): + """ + Setting the environment for the tests. + """ + if 'selftest' in str(self.name): + self.build_selftest() + + def build_selftest(self): + """ + Resolve the packages dependencies and build the selftest. + """ + smg = SoftwareManager() + url = 'https://raw.githubusercontent.com/torvalds/linux/refs/' \ + 'heads/master/tools/testing/selftests/x86/srso.c' + self.url = self.params.get('url', default=url) + + self.detected_distro = distro.detect() + if self.detected_distro.name == 'Ubuntu': + self.distro_ver = int(self.detected_distro.version.split('.')[0]) + else: + self.distro_ver = int(self.detected_distro.version) + deps = ['gcc', 'make', 'automake', 'autoconf', 'rsync'] + + for package in deps: + if not smg.check_installed(package) and not smg.install(package): + self.cancel("Fail to install %s package" % package) + + self.testfile = os.path.join(self.workdir, "srso.c") + try: + download.url_download(self.url, self.testfile) + except Exception as e: + self.cancel(f"{e}") + if build.make(self.workdir, extra_args='srso'): + self.cancel('Building the selftest failed') + + def test_sysfs(self): + """ + Check the vulnerability status from sysfs. + """ + filename = '/sys/devices/system/cpu/vulnerabilities/spec_rstack_overflow' + try: + content = genio.read_file(filename) + except PermissionError as err: + if 'Operation not permitted' not in str(err): + self.fail("%s file access not permitted." % filename) + + if 'Vulnerable' in content: + if 'no microcode' in content.lower(): + self.fail('Processor is vulnerable, and no mitigation applied') + else: + self.log.warn('Processor is partially vulnerable') + + # The vulnerability is mitigated via software microcode, but processor + # is still vulnerable. So, we warn the user. + if 'Mitigation' in content: + self.log.warn('Microcode addressing the mitigation has been applied') + + def test_srso_selftest(self): + """ + Execute the SRSO selftest + """ + os.chdir(self.workdir) + result = process.run('./srso', shell=True, ignore_status=True) + log_output = result.stdout.decode('utf-8') + results_path = os.path.join(self.outputdir, 'raw_output') + with open(results_path, 'w') as r_file: + r_file.write(log_output) + for line in open(results_path).readlines(): + if not line.startswith('RET'): + continue + match = re.search(r"\((\d+) retired <-> (\d+) mispredicted\)", + line) + if match: + retired_count = int(match.group(1)) + mispredicted_count = int(match.group(2)) + # The mispredicted and retired RETs should be almost equal if + # mitigation works. Safe value for the difference is considered + # to be 95% + if int(mispredicted_count * 100 / retired_count) <= 95: + self.fail("Retired: %s, Mispredicted: %s." + "The mitigation does not work correctly." + % (retired_count, mispredicted_count)) + else: + self.fail("The selftest run failed. Please check debug log") + + def tearDown(self): + self.log.info('Cleaning up') + if os.path.exists(self.workdir): + shutil.rmtree(self.workdir) diff --git a/kernel/srso_mitigation.py.data/Readme.txt b/kernel/srso_mitigation.py.data/Readme.txt new file mode 100644 index 000000000..b7aa6c459 --- /dev/null +++ b/kernel/srso_mitigation.py.data/Readme.txt @@ -0,0 +1,32 @@ +This is a mitigation for the speculative return stack overflow (SRSO) +vulnerability found on AMD processors. The mechanism is by now the +well known scenario of poisoning CPU functional units - the Branch +Target Buffer (BTB) and Return Address Predictor (RAP) in this +case - and then tricking the elevated privilege domain (the kernel) +into leaking sensitive data. + +AMD CPUs predict RET instructions using a Return Address Predictor +(aka Return Address Stack/Return Stack Buffer). In some cases, a +non-architectural CALL instruction (i.e., an instruction predicted +to be a CALL but is not actually a CALL) can create an entry in the +RAP which may be used to predict the target of a subsequent RET +instruction. + +The specific circumstances that lead to this varies by +microarchitecture but the concern is that an attacker can mis-train +the CPU BTB to predict non-architectural CALL instructions in kernel +space and use this to control the speculative target of a subsequent +kernel RET, potentially leading to information disclosure via a +speculative side-channel. + +Here, we test if the processor is mitigated from the vulnerability. + +1. SRSO Selftest available as a part of kernel source code. +We run the selftest available at tools/testing/selftest/x86/srso.c +2. Check the sysfs for vulnerability status. + +Ref: https://docs.kernel.org/admin-guide/hw-vuln/srso.html + +Parameters: + +url: The url for selftest srso.c diff --git a/kernel/srso_mitigation.yaml b/kernel/srso_mitigation.yaml new file mode 100644 index 000000000..05c6ce8a5 --- /dev/null +++ b/kernel/srso_mitigation.yaml @@ -0,0 +1 @@ +url: "https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/tools/testing/selftests/x86/srso.c"