Fix segfault in dm_get_map() on null device-mapper parameters
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
multipath-tools (Ubuntu) |
Fix Released
|
Undecided
|
Unassigned | ||
Focal |
Fix Released
|
Medium
|
Mauricio Faria de Oliveira | ||
Jammy |
Fix Released
|
Medium
|
Mauricio Faria de Oliveira | ||
Lunar |
Fix Released
|
Medium
|
Mauricio Faria de Oliveira | ||
Mantic |
Fix Released
|
Undecided
|
Unassigned | ||
Noble |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
[Impact]
* There are corner cases in which multipathd
might segfault if device-mapper parameters
for a multipath map are returned as NULL.
* This is apparently a rare error condition,
but it's been reported and fixed upstream:
commit 7439a41 ("dm_get_map: fix segfault
when can't found target") [1]
* The SRU in bug 2039719 (Focal) needs this,
so we take it individually as separete SRU
to perform synthetic tests on the commit
and verify correct behavior.
* Focal does not segfault if params are NULL
since it uses `snprintf(..., "%s", params)`,
which handles a string NULL pointer well,
while newer releases use `strdup(params)`,
which does not.
However, Focal should still get the patch
since a multipath map _without parameters_
is _invalid_, and should not be passed on
within multipathd (might lead to issues).
Details: the device-mapper multipath target
_requires_ 4 parameters: features, hardware
handler, path groups, and next path group;
linux/
Without parameters:
$ sudo dmsetup create mpath-test --table '0 1048576 multipath'
device-mapper: reload ioctl on mpath-test (253:3) failed: Invalid argument
Command failed.
With 4 parameters:
$ sudo dmsetup create mpath-test --table '0 1048576 multipath 0 0 0 0'
$ sudo dmsetup table --target multipath
mpath-test: 0 1048576 multipath 0 0 0 0
$ sudo dmsetup remove mpath-test
[Test Steps]
* Synthetic reproducer available with GDB,
(comments #1 and #2).
* Create a VM with a multipath disk.
* Attach GDB to multipathd.
* Break on the device-mapper function
that returns a map's info/parameters.
* Let it finish that function, and set
parameters to NULL.
* Let multipathd run.
Jammy/Lunar:
* Expected: multipathd continues to run.
* Actual: multipathd hits a segfault.
Focal:
* Expected: map without parameters returns error.
* Actual: map without parameters returns normally.
[Regression Potential]
* The change is just a NULL pointer check,
which returns early from the function
(with the same error code as already used
previously in that function).
* Theoretically, regressions would manifest
in the dm_get_map() function, and likely
show as incomplete information on status
of multipath maps or paths.
* It's not expected to regress to another
segmentation fault, as the function path
is shorter if the condition happens, and
only accesses memory that was initialized
and checked before (the dm_task variable).
* Any regression should be easy to catch,
as dm_get_map() runs periodically on the
path checkers in multipathd (the daemon)
and commands in multipath (the cli tool).
[Other Info]
* The commit [1] is present in Mantic and later.
$ git describe --contains 7439a41
0.9.0^2~8
$ rmadison -a source multipath-tools
...
multipath-tools | 0.8.8-1ubuntu2.2 | lunar-proposed | source
multipath-tools | 0.9.4-5ubuntu3 | mantic | source
multipath-tools | 0.9.4-5ubuntu3 | noble | source
[1] https:/
Synthetic reproducer on Lunar
===
Ubuntu Server cloud image:
---
SERIES=lunar
wget https:/ /cloud- images. ubuntu. com/$SERIES/ current/ ${SERIES} -server- cloudimg- amd64.img -server- cloudimg- amd64.img -f qcow2 $SERIES.qcow2 8G
qemu-img create -F qcow2 -b ${SERIES}
cloud-init image:
---
echo 'local-hostname: test' >meta-data
PUBKEY=$(cat $HOME/. ssh/id_ rsa.pub)
cat <<EOF >user-data authorized- keys: ["$PUBKEY"] ssh/sshd_ config
#cloud-config
users:
- name: ubuntu
ssh-
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: sudo
shell: /bin/bash
runcmd:
- echo 'AllowUsers ubuntu' >>/etc/
- restart ssh
EOF
genisoimage -output test-cidata.iso -volid cidata -joliet -rock user-data meta-data
QEMU VM:
---
- multipath disk on virtio-scsi:
- host forwarding for ssh login:
truncate -s 1G multipath.img
qemu-system-x86_64 \ ::22222- :22 \ cidata. iso,media= cdrom \ scsi,id= scsi1 \ img,if= none,cache= none,format= file,locking= off,id= path0 \ bus=scsi1. 0,serial= helloworld, drive=path0 \ img,if= none,cache= none,format= file,locking= off,id= path1 \ bus=scsi1. 0,serial= helloworld, drive=path1
-machine q35 -accel kvm -cpu host -m 2048 \
-nodefaults -no-user-config \
-nographic -serial stdio \
\
-net nic -net user,hostfwd=
\
-drive file=$SERIES.qcow2 \
-drive file=test-
\
-device virtio-
\
-drive file=multipath.
-device scsi-hd,
\
-drive file=multipath.
-device scsi-hd,
$ ssh ubuntu@127.0.0.1 -p 22222
$ sudo multipath -l QEMU_HARDDISK_ helloworld) dm-0 QEMU,QEMU HARDDISK 'service- time 0' prio=0 status=active 'service- time 0' prio=0 status=enabled
mpatha (0QEMU_
size=1.0G features='0' hwhandler='0' wp=rw
|-+- policy=
| `- 0:0:0:0 sda 8:0 active undef running
`-+- policy=
`- 0:0:1:0 sdb 8:16 active undef running
Latest version:
---
sudo add-apt-repository -yp proposed tools/lunar- proposed
sudo apt install -y multipath-
sudo systemctl restart multipathd.service
$ dpkg -s multipath-tools | grep Version:
Version: 0.8.8-1ubuntu2.2
Debug symbols
---
V1=$(dpkg-query -Wf '${Version}' multipath-tools)
V2=$(dpkg-query -Wf '${Version}' libdevmapper1.02.1 | cut -d: -f2-)
wget https:/ /launchpad. net/ubuntu/ +archive/ primary/ +files/ multipath- tools-dbgsym_ ${V1}_amd64.ddeb /launchpad. net/ubuntu/ +archive/ primary/ +files/ libdevmapper1. 02.1-dbgsym_ ${V2}_amd64.ddeb
wget https:/
sudo dpkg -i ./multipath- tools-dbgsym_ ${V1}_amd64. ddeb ./libdevmapper1 .02.1-dbgsym_ ${V2}_amd64. ddeb
Debugger
---
sudo apt install -y gdb
sudo gdb -p $(pidof multipathd)
(gdb) b dm_get_map a4fa0 "mpatha", ...
Breakpoint 1 at ...
(gdb) c
Thread 6 "multipathd" hit Breakpoint 1, dm_get_map (name=0x5599c32
(gdb) b dm_get_next_target
Breakpoint 2 at ...
(gdb) c
Thread 6 "multipathd" hit Breakpoint 2, dm_get_next_target (...
(gdb) finish
Run till exit from #0 dm_get_next_target (...
Value returned is $1 = (void *) 0x0
(gdb) p params
$2 = 0x7fed68004c60 "0 0 2 1 service-time 0 1 2 8:0 1 1 service-time 0 1 2 8:16 1 1 "
(gdb) set params = 0
(gdb) p params
$3 = 0x0
(gdb) disable breakpoints
(gdb) c
Thread 6 "multipathd" received signal SIGSEGV, Segmentation fault.
...
(gdb) q
$ sudo systemctl status multipathd.service | grep -e Active: -e Process:
Active: failed (Result: cor...