Linux Device Mapper development
 help / color / mirror / Atom feed
From: Benjamin Marzinski <bmarzins@redhat.com>
To: mwilck@suse.de
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>,
	dm-devel@lists.linux.dev, Martin Wilck <mwilck@suse.com>
Subject: Re: [PATCH 2/4] libmultipath: unmangle WWIDs if necessary
Date: Wed, 30 Sep 2026 20:04:53 -0400	[thread overview]
Message-ID: <ar2jpWLGvnezXeW5@redhat.com> (raw)
In-Reply-To: <20260925214014.2464499-3-mwilck@suse.de>

On Fri, Sep 25, 2026 at 11:40:07PM +0200, mwilck@suse.de wrote:
> From: Martin Wilck <mwilck@suse.com>
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index 344da19..66af333 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -37,6 +37,7 @@
>  #include "print.h"
>  #include "strbuf.h"
>  #include "pgpolicies.h"
> +#include "wwids.h"
>  
>  #define VPD_BUFLEN 4096
>  
> @@ -45,6 +46,97 @@ struct vpd_vendor_page vpd_vendor_pages[VPD_VP_ARRAY_SIZE] = {
>  	[VPD_VP_HP3PAR]	= { 0xc0, "hp3par" },
>  };
>  
> +/* from libdm/libdm-common.c; license: LGPL-2.1-only */
> +static bool _is_whitelisted_char(char c)
> +{
> +	/*
> +	 * Actually, DM supports any character in a device name.
> +	 * This whitelist is just for proper integration with udev.
> +	 */
> +	if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
> +	    (c >= 'a' && c <= 'z') || strchr("#+-.:=@_", c) != NULL)
> +		return true;
> +
> +	return false;
> +}
> +
> +size_t maybe_unmangle_wwid(char new_wwid[WWID_SIZE], const char *wwid)
> +{
> +	char buf[WWID_SIZE], *dst;
> +	const char *src;
> +	bool mangled = false, invalid = false;
> +	size_t rc, len;
> +
> +	if (!wwid) {
> +		*new_wwid = '\0';
> +		return 0;
> +	}
> +
> +	/* this might be > WWID_SIZE - 1 */
> +	len = strlen(wwid);
> +	/*
> +	 * A correctly mangled string doesn't contain invalid characters.
> +	 * In particular, if the original string contained `\xXY`, it will
> +	 * itself be mangled to '\x5cxXY`.
> +	 */
> +	/* clang-format off */
> +	for (src = wwid, dst = buf;
> +	     dst - buf < WWID_SIZE - 1 && *src;
> +	     src++, dst++) {
> +		/*clang-format on */
> +		if (_is_whitelisted_char(*src)) {
> +			*dst = *src;
> +			continue;
> +		}
> +		if (*src == '\\') {
> +			char hex[3], c;
> +
> +			/*
> +			 * udev mangling always outputs 2-digit hex numbers
> +			 * 1-digit would be unprintable, anyway
> +			 */
> +			if (src + 4 > wwid + len || *(src + 1) != 'x' ||
> +			    sscanf(src + 2, "%2[A-Fa-f0-9]", hex) == 0 ||
> +			    strlen(hex) != 2) {
> +				condlog(3, "%s: wwid \"%s\" contains invalid mangle sequence \"%s\"",
> +					__func__, wwid, src);
> +				invalid = true;
> +				break;
> +			}
> +			mangled = true;
> +			src += 1 + strlen(hex);
> +			c = strtol(hex, NULL, 16);
> +			/* Allow non-ascii unicode, but avoid non-printable characters */
> +			*dst = (c & 0x80) || isprint(c) ? c : '_';
> +		} else {
> +			condlog(3, "%s: wwid \"%s\" contains illegal character '%02x'",
> +				__func__, wwid, (unsigned char)*src);
> +			invalid = true;
> +			break;
> +		}
> +	}
> +
> +	/*
> +	 * 1. If we found an invalid character, it can't be mangled by udev,
> +	 *    use original WWID.
> +	 * 2. If we didn't found a `\xHH`, it isn't mangled, use original.
> +	 * 3. If the unmangled WWID is known, use it.
> +	 * 4. If the original WWID is known, use it.
> +	 * 5. If in doubt, use the unmangled WWID.
> +	 */
> +	if (!invalid && mangled &&

This check should use "buf" not "new_wwid".

> +	    (!check_wwids_file(new_wwid, 0) || check_wwids_file(wwid, 0))) {
> +		*dst = '\0';
> +		rc = strlcpy(new_wwid, buf, WWID_SIZE);
> +		condlog(3, "%s: unmangled WWID \"%s\" -> \"%s\"", __func__,
> +			wwid, new_wwid);
> +	} else {
> +		rc = strlcpy(new_wwid, wwid, WWID_SIZE);
> +		condlog(4, "%s: kept WWID \"%s\"", __func__, new_wwid);
> +	}

Nitpick: I think these conditionals would be easier to check against
rules as:

	if (invalid || !mangled || check_wwids_file(wwid, 0) == 0) {
		/* Keep original wwid */
	} else {
		/* Use unmangled wwid */
	}
> +	return rc;
> +}
> +
>  int
>  alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
>  			  const char *wwid, int flag, struct path **pp_ptr)
> @@ -65,8 +157,7 @@ alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
>  	if (!pp)
>  		return PATHINFO_FAILED;
>  
> -	if (wwid)
> -		strlcpy(pp->wwid, wwid, sizeof(pp->wwid));
> +	maybe_unmangle_wwid(pp->wwid, wwid);
>  
>  	if (safe_sprintf(pp->dev, "%s", devname)) {
>  		condlog(0, "pp->dev too small");
> @@ -2163,8 +2254,8 @@ get_udev_uid(struct path * pp, const char *uid_attribute, struct udev_device *ud
>  	value = udev_device_get_property_value(udev, uid_attribute);
>  	if ((!value || strlen(value) == 0) && pp->can_use_env_uid)
>  		value = getenv(uid_attribute);
> -	if (value && strlen(value)) {
> -		len = strlcpy(pp->wwid, value, WWID_SIZE);
> +	if (value && *value) {
> +		len = maybe_unmangle_wwid(pp->wwid, value);
>  		if (len >= WWID_SIZE) {
>  			len = fix_broken_nvme_wwid(pp, value, WWID_SIZE);
>  			if (len > 0)
> @@ -2224,7 +2315,7 @@ static ssize_t dasd_get_uid(struct path *pp)
>  	if (p)
>  		*p = '\0';
>  
> -	return strlcpy(pp->wwid, value, WWID_SIZE);
> +	return maybe_unmangle_wwid(pp->wwid, value);

We're reading this from sysfs, so I don't think this one needs to be
unmangled.

>  }
>  
>  static ssize_t uid_fallback(struct path *pp, int path_state,
> @@ -2254,6 +2345,8 @@ static ssize_t uid_fallback(struct path *pp, int path_state,
>  					   sizeof(value));
>  		if (!sysfs_attr_value_ok(len, sizeof(value)))
>  			return -1;
> +
> +		/* WWID read from sysfs, unmangling is not necessary */

I'm pretty sure that unmangling is unnecessary in all of the methods in
uid_fallback, so this comment is confusing.

-Ben


  reply	other threads:[~2026-10-01  0:05 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25 21:40 [PATCH 0/4] multipath-tools: unmangle WWIDs if necessary mwilck
2026-09-25 21:40 ` [PATCH 1/4] libmultipath: constify functions in wwid.c mwilck
2026-09-30 23:36   ` Benjamin Marzinski
2026-09-25 21:40 ` [PATCH 2/4] libmultipath: unmangle WWIDs if necessary mwilck
2026-10-01  0:04   ` Benjamin Marzinski [this message]
2026-09-25 21:40 ` [PATCH 3/4] multipath-tools tests: add test for WWID unmangling mwilck
2026-10-01  0:05   ` Benjamin Marzinski
2026-09-25 21:40 ` [PATCH 4/4] libmultipath: use mmap in lookup_wwid() mwilck
2026-10-01  0:06   ` Benjamin Marzinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ar2jpWLGvnezXeW5@redhat.com \
    --to=bmarzins@redhat.com \
    --cc=christophe.varoqui@opensvc.com \
    --cc=dm-devel@lists.linux.dev \
    --cc=mwilck@suse.com \
    --cc=mwilck@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox