** Description changed:
+ [ Impact ]
+
+ * Running rdmsr or wrmsr with the -a (all processors) flag
+ when the msr kernel module is not loaded causes an immediate
+ Segmentation Fault.
+
+ * The utilities use scandir() to list CPU device nodes under /dev/cpu.
+ When the msr module is absent, /dev/cpu does not exist on the filesystem,
+ causing scandir() to return -1. Neither utility checks for a negative
+ return value and proceeds directly into a loop, dereferencing an
+ uninitialized namelist pointer (namelist[-2]).
+
+ * Users or automation scripts querying hardware registers across all CPU
+ cores on bare-metal systems encounter unhandled crashes instead of an
+ informative error message.
+
+ * The fix adds error handling after the scandir() call in both rdmsr.c
+ and wrmsr.c. If /dev/cpu is missing or unreadable, the utilities print
+ a clean diagnostic message advising the user to load the msr driver
+ and exit gracefully with status 1.
+
+ [ Test Plan ]
+
+ * [0] msr-tools will be tested in the following environments:
+ - Stonking (26.10 LTS)
+ - Resolute (26.04 LTS)
+ - Noble (24.04 LTS)
+ - Jammy (22.04 LTS)
+
+ You can reproduce this in a bare metal machine
+ (or an environment where MSR access is supported).
+
+ I reproduced this on a Multipass VM, e.g.
+ multipass launch \
+ --cpus 4 \
+ --memory 8GB \
+ --disk 25GB \
+ --name sandbox-stonking \
+ stonking
+
+ * [1] Install msr-tools:
+ sudo apt update && sudo apt install -y msr-tools
+
+ * [2] Unload the msr module:
+ sudo rmmod msr
+
+ * [3] Verify that /dev/cpu is not available:
+ ls -ld /dev/cpu
+
+ * [4] Trigger the segfault:
+ sudo rdmsr -a 0x10
+ sudo -a 0x8b 0
+
+ The output will look something like:
+ Segmentation fault (core dumped) sudo rdmsr -a 0xe2
+ Segmentation fault (core dumped) sudo wrmsr -a 0xe2 123
+
+ * [5] Install the updated package containing the fix.
+
+ * [6] Run sudo rdmsr -a 0x10 and sudo wrmsr -a 0x8b 0 again
+
+ This time, it should print and error message without crashing:
+ rdmsr: may need to load msr module to populate /dev/cpu
+
+
+ [ Where problems could occur ]
+
+ * The fix changes the behavior of rdmsr and wrmsr when /dev/cpu cannot
+ be accessed. Instead of continuing and potentially crashing, the command
+ now exits with status 1 and display an error message. This should not
+ affect normal usage when /dev/cpu is available, but could possibly affect
+ scripts that expect a different exit status.
+
+
+ [ Other Info ]
+
+ * The workaround to this issue is to manually load the msr kernel module
+ (sudo modprobe msr) before using rdmsr or wrmsr with the -a flag.
+
+ * Upstream project (https://github.com/intel/msr-tools) is archived and
+ in read only mode.
+
+ * Filed and forwarded a bug to Debian:
+ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1144405
+
+ -------------------------
+ ORIGINAL BUG DESCRIPTION
+
+
Description:
------------
The rdmsr and wrmsr utilities from msr-tools get a segmentation fault
when invoked with the -a (all processors) flag while the msr kernel
module is not loaded, which means the /dev/cpu directory is not
available.
Looking at the upstream source code, the vulnerability lies in both
rdmsr.c and wrmsr.c inside the rdmsr_on_all_cpus and wrmsr_on_all_cpus
functions, respectively.
The code uses the scandir() function to read the /dev/cpu directory:
https://github.com/intel/msr-tools/blob/7d78c80d66463ac598bcc8bf1dc260418788dfda/rdmsr.c#L106
https://github.com/intel/msr-tools/blob/7d78c80d66463ac598bcc8bf1dc260418788dfda/wrmsr.c#L67
When /dev/cpu does not exist, scandir() returns -1 to indicate an error,
and the namelist pointer remains uninitialized. However, the code does
not check if dir_entries < 0. Because dir_entries is -1, it evaluates as
true in the while (dir_entries--) condition, decrements to -2, and
immediately attempts to access namelist[-2]->d_name. Attempting to
dereference this uninitialized pointer at a negative offset causes the
segmentation fault.
Reproducer:
-----------
In a bare metal machine (or an environment where MSR access is supported):
Unload the msr module if it is currently loaded:
sudo rmmod msr
Verify that /dev/cpu is not available:
ls -l /dev/cpu
ls: cannot access '/dev/cpu': No such file or directory
Run rdmsr or wrmsr querying all CPUs to trigger the segfault:
sudo rdmsr -a 0xe2
Segmentation fault
sudo wrmsr -a 0xe2 123
Segmentation fault
Workaround:
-----------
Manually load the msr kernel module before using rdmsr or wrmsr with the -a
flag. Loading the module populates /dev/cpu and its child CPU nodes, preventing
the scandir failure.
sudo modprobe msr
sudo rdmsr -a 0xe2
74008008
74008008
Additional Info:
----------------
Upstream project is in read only mode.
This was tested in Jammy, Noble and Resolute. All of them have the same
issue.
** Changed in: msr-tools (Ubuntu Jammy)
Status: New => In Progress
** Changed in: msr-tools (Ubuntu Noble)
Status: New => In Progress
** Changed in: msr-tools (Ubuntu Resolute)
Status: New => In Progress
** Changed in: msr-tools (Ubuntu Stonking)
Status: New => In Progress
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2163089
Title:
rdmsr and wrmsr segfault when invoked with -a without the msr module
loaded
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/msr-tools/+bug/2163089/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs