Skip to content

multipath-tools 0.15.1 - #160

Merged
mwilck merged 23 commits into
opensvc:masterfrom
openSUSE:queue
Aug 27, 2026
Merged

multipath-tools 0.15.1#160
mwilck merged 23 commits into
opensvc:masterfrom
openSUSE:queue

Conversation

@mwilck

@mwilck mwilck commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

multipath-tools 0.15.1, 2026/08

User-visible changes

  • The preferredip=parameter for the iet prioritizer has been generalized.
    The new syntax is
    preferredip=<CIDR>:<Prio>[,<CIDR>:<Prio>,...]
    
    where CIDR is an IPv4 address block in CIDR format, e.g. 192.168.1.0/24,
    and <Prio> is the numeric priority to assign to IP addresses in this
    block. See the multipath.conf(5) man page for details. The syntax
    preferredip=<IP> is still supported with the same semantics as before.

Vulnerability fixes

Bug fixes

  • Fix a use-after-free error introduced by the fix for
    #152 in 0.15.0.
    Fixes openSUSE#24.

  • When parsing the device-mapper table of a multipath device, the result for
    path arguments was not checked for NULL. This happens if the kernel
    returns an invalid table with missing path arguments. Fix it by adding
    a NULL check (commit ac9fe05).
    Fixes #155, #156.

Shortlog

@ahvlima (1):
libmultipath: iet: support multiple subnets in prio_args

@bmarzins (15):
.clang-format: Use ReflowComments: false instead of Never
multipathd: move dead_client before new_client
multipathd: limit the number of non-root uxlsnr clients
multipathd: check for POLLOUT in CLT_SEND state
multipathd: use non-blocking sockets for uxlsnr
libmultipath: check for buffer overruns in get_asymmetric_access_state
libmultipath: check for buffer overruns in alua_rtpg functions
libmultipath: skip pointless do_inquiry retry
multipathd: handle trailing percent in multipathd format commands
libmultipath: fix possible ana_log overflow on 32 bit machines
libmultipath: sanitize wwids in get_uid
kpartx: Fix read_lba and callers to check for errors
kpartx: Check that GPT header_size is valid
kpartx: simplify is_gpt_valid error path
libmpathutil: don't call pthread_testcancel as part of udev commands

@mwilck (6):
Update SECURITY.md with version support and reporting
README.md: add information about bug and reporting
Update NEWS.md
libmpathpersist: fix heap buffer overflow for PRIN_READ_FULL_STATUS
Update NEWS.md
libmultipath: bump version to 0.15.1

@wallycheng (1):
libmultipath: check get_word() result in disassemble_map()

mwilck and others added 20 commits August 25, 2026 13:11
Added support status for versions 0.10.x to 0.15.x and updated vulnerability reporting instructions.

Signed-off-by: Martn Wilck <mwilck@suse.com>
... and a link to SECURITY.md

Signed-off-by: Martin Wilck <mwilck@suse.com>
'Never' and 'false' are equivalent and 'false' works with earlier
versions fo clang-format

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
No functional change. A future commit will call dead_client() from
new_client().

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Multipathd only allows 16380 concurrent clients, and doesn't time out
clients waiting to send or recv data. It also allows non-root clients to
connect. This means any user could open 16380 socket connections to
multipathd, and just leave them open, stopping all other uxlsnr clients
from connecting.

Fix this by limiting the number of concurrent non-root uxlsnr clients to
256. multipathd will immediately close the connections of any new
non-root clients, if 256 have already connected.

Fixes: 8212a27 ("[multipathd] unix socket daemon control interface")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
When a uxlsnr client was in the CLT_SEND state, it was always trying to
send the reply, even if the socket wasn't in the POLLOUT state, meaning
that there was no space in the socket's send buffer. This can cause
the uxlsnr thread to block.

Fixes: 90167ec ("multipathd: uxlsnr: merge uxsock_trigger() into state machine")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
multipathd's uxlsnr thread doesn't currently use non-blocking sockets
and can block in multiple places. According to the accept man page, if
the initial listening socket is not non-blocking, there is a chance that
accept will block, even after ppoll() returns a readability event. To
fix this, ux_socket_listen() needs to use SOCK_NONBLOCK when creating
the socket. Also, multipathd.service needs to set NonBlocking=true so
that sockets passed in from socket activation are made nonblocking.

Also, POLLOUT only means that *some* data can be accepted. The send()
command can still block if it tries to write more than available space.
To avoid that, the actual client sockets are now created with accept4()
which adds the SOCK_NONBLOCK flag, so that send() will never block.

Fixes: 8212a27 ("[multipathd] unix socket daemon control interface")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
When get_asymmetric_access_state() calls do_rtpg(), it may return less
than buflen bytes. RTPG_FOR_EACH_PORT_GROUP() only checked that the next
port group descriptor started before the end of the buffer. Instead,
get_asymmetric_access_state() should check that there is enough space
for the entire port group descriptor in the data that was actually
returned by do_rtpg(). Since struct rtpg_tpg_dscr has a variable size,
it must first check if the base structure fits. Once it knows
that it's safe to access port_count, it can check if the port data
also fits.

Fixes: a3cbee5 ("[lib] merge libprio in libmultipath")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Both get_target_port_group_support() and get_target_port_group() can
overrun their buffers. do_inquiry() may return less than the requested
bytes, and the callers need to verify that it returned enough data.
Since struct vpd83_dscr has a variable size, get_target_port_group()
must first check if the base structure fits in the returned data. Once
it knows that it's safe to access length, it must also check if the
extra data also fits. Before getting the target port group, it must also
check that the data length is large enough to hold it.

Fixes: a3cbee5 ("[lib] merge libprio in libmultipath")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
get_target_port_group() will only use up to VPD_BUFLEN bytes from the
inquiry data it gets. It already passes a buffer big enough for this
into its first call to do_inquiry(). If it doesn't get enough data,
there isn't much point in increasing the buffer, since it was already
big enough to start with.

(mwilck) Note: Even if a device has name designators for LUN, target, and
target port, and uses SCSI name strings (the largest designator type) for
each, it'd need just 400 bytes for the VPD page 83. Target port group and
relative target port designators need another 16 bytes. Additional
designators will be less than 20 bytes each, so we could squeeze more than
20 of them into the remaining space if we just allocated 1kiB. Thus 4k should
be plenty for any real-world device.

Fixes: ed7dc96 ("libmultipath (coverity): fix tainted values in alua_rtpg.c")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
When using a multipathd command that accepts a format, if the user
enters a trailing '%', such as 'multipathd show maps format "%"',
multipathd will read past the end of the buffer. Check for this.

Fixes: 2f05df4 ("libmultipath: use strbuf in print.c")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
On 32bit machines, get_ana_info() and get_ana_state() can overflow on
32 bit machines. This can result in accessing memory outside of the
ana_log.

Fixes: daf9d58 ("multipath-tools: add ANA support for NVMe device")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Multipath can use the wwid as part of a pathname, so it shouldn't be "."
or ".." or contain slashes. If multipath uses the default uid_attribute,
udev should already replace any '/' in the value it got from the device,
but it's possible to use other attributes, where this isn't true.

Also, use strchop() to trim the wwid, since it handles all types of
trailing whitespace.

Fixes: 8d81e70 ("Strip trailing blanks from wwid")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
reab_lba() could return -1 because it was unable, possibly temporarily,
to read from the device. alloc_read_gpt_header() treated this as
success, and find_valid_gpt() never even checked the return value.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
The GPT header_size must be between 92 and the logical block size of the
device.
https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html#id14
alloc_read_gpt_header() guarantees that it returns a logical block sized
buffer of data. is_gpt_valid() needs to check that header_size is not
larger than the logical block size before it recalculates the CRC,
otherwise it could overrun the buffer.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Instead of duplicating the error path cleanup, just goto a failure
label to do the cleanup.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Commit 47a654f ("libmpathutil: udev: prevent interruption by thread
cancellation") added pthread_testcancel() calls to the udev command
wrappers. This makes these commands cancellation points (but only after
any waiting has already happened without cancellation), while the rest
of the code assumes that they are not.

This can cause problems like in uev_update_path() when multipathd first
calls udev_device_unref(pp->udev) and afterwards resets pp->udev. If the
thread is cancelled after unref'ing device in the udev_device_unref()
call, pp->udev will still point to the now-freed udev_device.

Fixes: 47a654f ("libmpathutil: udev: prevent interruption by thread cancellation")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
get_word() returns 0 and sets *word to NULL not only when calloc()
fails, but also when the input table is malformed(e.g, the last path
has no arguments). In both cases, dereferencing word later in
atoi(word) causes a NULL pointer dereference.

Add a check for !word and jump to out since word is already NULL,
matching the error-handling pattern used elsewhere in the function.

Fixes: opensvc#156
Signed-off-by: wallycheng <295412260@qq.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Extend the prio_args for the iet prioritizer as follows:

    preferredip=<CIDR>:<Prio>,<CIDR>:<Prio>,...

where CIDR is an IPv4 address block in CIDR format (o.o.o.o/p), e.g
192.168.1.0/24. If the prefix is not given, it's assumed to be 32. IP
addresses can be abbreviated by ommitting trailing zeroes, i.e. 10.2/16 is
equivalent to 10.2.0.0/16. <Prio> is a numeric priority to assign to paths
to iSCSI servers whose IP address is in the given block. If a a server IP
address matches multiple blocks, the one with the highest prefix takes
precedence.

The default block 0.0.0.0/0 matches every IP address and has priority 0 by
default.

For backward compatibility, the syntax

    preferredip=<IP>

(without a prefix and priority) simply assigns an increased priority to the
given server IP address; it's equivalent to

    preferredip=<IP>/32:20,0.0.0.0/0:10

Signed-off-by: Arnaldo Viegas de Lima <arnaldo@viegasdelima.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Acked-by: Benjamin Marzinsi <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
@mwilck
mwilck requested a review from bmarzins August 26, 2026 17:15

@bmarzins bmarzins left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

mwilck added 2 commits August 27, 2026 12:45
mpath_format_readfullstatus() did not check the size of the output
buffer for the PRIN descriptors and the respective pointers, causing
a possible buffer overflow by a malicious PRIN response to a
READ FULL STATUS command.

Fix it by adding proper bounds checking.

Link: GHSA-hj7j-qr9h-5fv6
Signed-off-by: Martin Wilck <mwilck@suse.com>
Acked-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
@mwilck
mwilck merged commit d53932b into opensvc:master Aug 27, 2026
174 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants