All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Marzinski <bmarzins@redhat.com>
To: Martin Wilck <martin.wilck@suse.com>
Cc: Christophe Varoqui <christophe.varoqui@opensvc.com>,
	dm-devel@lists.linux.dev
Subject: Re: [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
Date: Thu, 11 Jul 2024 14:39:25 -0400	[thread overview]
Message-ID: <ZpAm3ZXvPx21XHHO@redhat.com> (raw)
In-Reply-To: <ed5136498c6ac428a5ee25d0c3af712ba57445d2.camel@suse.com>

On Thu, Jul 11, 2024 at 02:56:05PM +0200, Martin Wilck wrote:
> On Wed, 2024-07-10 at 23:38 -0400, Benjamin Marzinski wrote:
> > On Tue, Jul 09, 2024 at 11:39:22PM +0200, Martin Wilck wrote:
> > > Export it, as it will be used by multipathd and libmpathpersist.
> > > 
> > 
> > This is fine. But I was thinking that if you wanted to actually add
> > some optional flags to the flags argument of libmp_mapinfo(), this
> > would
> > be a good use. You could have a flag like DM_MAP_MPATH_WWID, which
> > would
> > verify that the device had a multipath UUID_PREFIX (and possibly
> > force a
> > check for a multipath target type) and then return the wwid without
> > the
> > multipath uuid prefix.
> > 
> > Just a thought.
> 
> Interesting idea. My thinking was that libmp_mapinfo() should only be
> an interface to libdevmapper, and should not interpret the data it
> returns in any way.
> 
> The only exception is the target type. In theory, the function could
> just have returned the target type, and left the interpretation to the
> caller. But then, it would have to perform several strdup()s for the
> results, and the caller would have to free() the data it wasn't
> interested in, which would lead to clumsy and inefficent code in the
> frequent case that we're just interested in "multipath" or "linear"
> targets. That's why I decided to pass the tgt_type field in, and return
> DMP_NO_MATCH if it didn't match, even though it's arguably odd in the
> mapinfo_t structure, which is otherwise only used for output fields.

I did wonder if it would make more sense to just pass a struct to
libmp_mapinfo() that contained all the input data, with the flags and
the identifiers (tgt_type just being an additional optional identier)
grouped together.  But I'm fine with the exiting interface so it didn't
seem worth commenting on.
 
> Your flag idea would work, too (an earlier version of this patch set
> used flags to indicate which output fields should be filled in; I
> discarded that because it was duplicated information, and more elegant
> to simply check it the respective output field was non-NULL).
> 
> Instead of tgt_type, we could also pass a "filter" callback function
> with which the caller could determine whether or not it was interested
> in a given map. But I wonder if that'd be over-engineered.
> 
> Whatever we eventually do, I think the is_mpath_uuid() helper will be
> useful. I am not sure whether we can unexport it even if we implement
> more sophisticated "filtering" in libmp_mapinfo().
> 
> In general, I wonder what multipath-tools should do if it encounters a
> map that has "multipath" target type, but the WWID of which doesn't
> conform to the mpath-XYZ convention, or vice versa. This can only
> happen if another tool like dmsetup had been used to create the map.
> IMO, if multipathd encounters such a situation, it should warn about it
> and keep its fingers off the map in question. But we might also play it
> simple and just assume that multipath maps always adhere to our
> convention. I don't think we currently behave consistently in this
> respect.

There was a time when there were users of the kernel multipath target
outside of the multipath-tools. To deal with them, the idea was that
multipathd would only manage devices that had a uuid with UUID_PREFIX.
That was a while ago, and we likely have been violating that condition,
but I haven't heard of any complaints. It might be worth auditing the
code to see if/where we aren't verifying new devices.

Obviously if we find a dm device that isn't a multipath target, we
shouldn't do anything with it, regardless of its UUID.
 
> AFAIU, both the WWID and the target type are immutable and can't be
> altered without destroying the map completely (because "multipath" is
> an "immutable target" in DM). Thus it should be sufficient to check the
> WWID when a map is first encountered.

Probably. Obviously, a multipath device could get removed outside of
multipathd and another device added with the same identifier that we're
using. There would be a window before we got the remove event where we
would be looking at the wrong device. But I can't really come up with
a way for this to happen that doesn't involve very creative stupidity on
the user's part, and since you need to be root to do this, I don't see
any security issues here.

This isn't exactly what you're asking about but the results are worse,
and I don't think there is a way to guarantee the following can't happen:

1. multipathd decides in needs to reload a multipath device that is not in
use and grabs the vecs lock so no events will get processed
2. user removes that device outside of multipathd (and likely outside of
multipath which should delegate the remove).
3. user creates a new multipath device outside of mulitpathd that has the
same name as the removed device. For this to happen by running multipath,
they either needed to be using user_friendly_names and haved removed the old
mapping from the bindings file, or they need to have editted multipath.conf
to set the alias of the new device to the alias of the old one.
4. multipathd reloads the table of the new device to point to old paths
5. user writes data to these old paths
6. multipathd gets the event and removes the device.

This results in data corruption, and there's no guarantee that
rechecking anything will always catch this. At some point we need to
just say "Sorry. You shot yourself in the foot."

But if we are just grabbing information about a device we already know
about, and it has switched so that its no longer a multipath device,
then multipathd can't really mess with it. All of our ioctls will fail,
and we will shortly clean it up anyway.

It's possible that we want to be more careful validating the WWID of
devices that we are looking up by major:minor, since it's much more
likely that a device got removed and a completey different dm device got
created and reused the same minor number, but I don't know why we would
ever be looking up a device we already know about by major:minor. So we
should always be checking these devices to verify that they are
multipath devices, and we currently are. 

> Thoughts?
> 
> Martin
> 
> > -Ben
> > 
> > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > ---
> > >  libmultipath/devmapper.c          | 13 +++++++++----
> > >  libmultipath/devmapper.h          |  2 ++
> > >  libmultipath/libmultipath.version |  1 +
> > >  3 files changed, 12 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > > index 806ffb8..5f6c0c8 100644
> > > --- a/libmultipath/devmapper.c
> > > +++ b/libmultipath/devmapper.c
> > > @@ -829,6 +829,11 @@ int dm_get_map(const char *name, unsigned long
> > > long *size, char **outparams)
> > >  	}
> > >  }
> > >  
> > > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
> > > +{
> > > +	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> > > +}
> > > +
> > >  /**
> > >   * dm_get_wwid(): return WWID for a multipath map
> > >   * @returns:
> > > @@ -845,7 +850,7 @@ int dm_get_wwid(const char *name, char *uuid,
> > > int uuid_len)
> > >  	if (rc != DMP_OK)
> > >  		return rc;
> > >  
> > > -	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	if (is_mpath_uuid(tmp))
> > >  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> > >  	else {
> > >  		uuid[0] = '\0';
> > > @@ -970,7 +975,7 @@ int dm_is_mpath(const char *name)
> > >  			       (mapid_t) { .str = name },
> > >  			       (mapinfo_t) { .uuid = uuid,
> > > .tgt_type = TGT_MPATH });
> > >  
> > > -	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX,
> > > UUID_PREFIX_LEN))
> > > +	if (rc != DMP_OK || !is_mpath_uuid(uuid))
> > >  		return DM_IS_MPATH_NO;
> > >  	else
> > >  		return DM_IS_MPATH_YES;
> > > @@ -1065,7 +1070,7 @@ int _dm_flush_map (const char *mapname, int
> > > flags, int retries)
> > >  				  .uuid = uuid,
> > >  				  .tgt_type = TGT_MPATH,
> > >  				  .target = &params }) != DMP_OK
> > > -	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	    || !is_mpath_uuid(uuid))
> > >  		return DM_FLUSH_OK; /* nothing to do */
> > >  
> > >  	/* if the device currently has no partitions, do not
> > > @@ -1309,7 +1314,7 @@ struct multipath *dm_get_multipath(const char
> > > *name)
> > >  			  }) != DMP_OK)
> > >  		return NULL;
> > >  
> > > -	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	if (!is_mpath_uuid(uuid))
> > >  		return NULL;
> > >  
> > >  	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp-
> > > >wwid));
> > > diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> > > index db5c5fd..a2b2837 100644
> > > --- a/libmultipath/devmapper.h
> > > +++ b/libmultipath/devmapper.h
> > > @@ -131,6 +131,8 @@ enum {
> > >  	DM_IS_MPATH_YES,
> > >  	DM_IS_MPATH_ERR,
> > >  };
> > > +
> > > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN]);
> > >  int dm_is_mpath(const char *name);
> > >  
> > >  enum {
> > > diff --git a/libmultipath/libmultipath.version
> > > b/libmultipath/libmultipath.version
> > > index 7d3ff63..5b8f9e0 100644
> > > --- a/libmultipath/libmultipath.version
> > > +++ b/libmultipath/libmultipath.version
> > > @@ -127,6 +127,7 @@ global:
> > >  	init_foreign;
> > >  	init_prio;
> > >  	io_err_stat_handle_pathfail;
> > > +	is_mpath_uuid;
> > >  	is_path_valid;
> > >  	libmp_dm_task_create;
> > >  	libmp_get_version;
> > > -- 
> > > 2.45.2
> > 


  reply	other threads:[~2024-07-11 18:39 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
2024-07-10  7:06   ` Martin Wilck
2024-07-09 21:38 ` [PATCH 02/44] multipath-tools CI: fix dmevents test for Debian Sid, arm/v7 Martin Wilck
2024-07-09 21:38 ` [PATCH 03/44] create-config.mk: use printf instead of /bin/echo Martin Wilck
2024-07-09 21:38 ` [PATCH 04/44] multipathd.service.in: use @BINDIR@ instead of /sbin Martin Wilck
2024-07-09 21:38 ` [PATCH 05/44] Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir) Martin Wilck
2024-07-09 21:38 ` [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx Martin Wilck
2024-07-10 16:30   ` Benjamin Marzinski
2024-07-10 20:15     ` Martin Wilck
2024-07-09 21:38 ` [PATCH 07/44] multipath-tools: Remove hard-coded paths to executables Martin Wilck
2024-07-09 21:38 ` [PATCH 08/44] multipath-tools: compile_commands.json fixes Martin Wilck
2024-07-09 21:39 ` [PATCH 09/44] multipath-tools: .gitignore: ignore o.wrap files for CI helpers Martin Wilck
2024-07-09 21:39 ` [PATCH 10/44] libmultipath: remove unused includes in devmapper.h Martin Wilck
2024-07-09 21:39 ` [PATCH 11/44] libmultipath: use DM_DEVICE_INFO in dm_mapname() Martin Wilck
2024-07-09 21:39 ` [PATCH 12/44] multipath-tools: don't call dm_task_no_open_count() Martin Wilck
2024-07-09 21:39 ` [PATCH 13/44] libmpathutil: export cleanup_udev_device() Martin Wilck
2024-07-09 21:39 ` [PATCH 14/44] libmpathutil: add cleanup_vector() Martin Wilck
2024-07-09 21:39 ` [PATCH 15/44] libmultipath: add cleanup helpers for struct multipath Martin Wilck
2024-07-09 21:39 ` [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c Martin Wilck
2024-07-10 20:12   ` Benjamin Marzinski
2024-07-10 20:18     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 17/44] libmultipath: add libmp_mapinfo() Martin Wilck
2024-07-10 22:53   ` Benjamin Marzinski
2024-07-11 11:00     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 18/44] libmultipath tests: add tests for libmp_mapinfo() Martin Wilck
2024-07-09 21:39 ` [PATCH 19/44] libmultipath: implement dm_get_info() and dm_map_present() with new API Martin Wilck
2024-07-09 21:39 ` [PATCH 20/44] libmultipath: remove dm_get_prefixed_uuid() Martin Wilck
2024-07-09 21:39 ` [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing Martin Wilck
2024-07-10 22:54   ` Benjamin Marzinski
2024-07-11 11:08     ` Martin Wilck
2024-07-11 17:01       ` Benjamin Marzinski
2024-07-11 17:41         ` Martin Wilck
2024-07-09 21:39 ` [PATCH 22/44] libmultipath: rename dm_get_uuid() -> dm_get_wwid() Martin Wilck
2024-07-09 21:39 ` [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic Martin Wilck
2024-07-10 23:34   ` Benjamin Marzinski
2024-07-11 12:25     ` Martin Wilck
2024-07-11 16:38       ` Benjamin Marzinski
2024-07-11 22:00       ` Martin Wilck
2024-07-09 21:39 ` [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API Martin Wilck
2024-07-10 23:41   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 25/44] libmultipath: reimplement dm_map_present_by_uuid() Martin Wilck
2024-07-09 21:39 ` [PATCH 26/44] libmultipath: reimplement dm_get_opencount() with new API Martin Wilck
2024-07-09 21:39 ` [PATCH 27/44] libmpathpersist: skip redundant dm_map_present() call Martin Wilck
2024-07-09 21:39 ` [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API Martin Wilck
2024-07-11  0:21   ` Benjamin Marzinski
2024-07-11 12:32     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 29/44] libmultipath: implement dm_get_multipath() " Martin Wilck
2024-07-09 21:39 ` [PATCH 30/44] libmultipath: use libmp_mapinfo() in _dm_flush_map() Martin Wilck
2024-07-09 21:39 ` [PATCH 31/44] libmultipath: add is_mpath_uuid() helper Martin Wilck
2024-07-11  3:38   ` Benjamin Marzinski
2024-07-11 12:56     ` Martin Wilck
2024-07-11 18:39       ` Benjamin Marzinski [this message]
2024-07-11 18:59         ` Martin Wilck
2024-07-09 21:39 ` [PATCH 32/44] libmultipath: add is_mpath_part_uuid() helper Martin Wilck
2024-07-09 21:39 ` [PATCH 33/44] libmultipath: add dmp_errstr() helper Martin Wilck
2024-07-09 21:39 ` [PATCH 34/44] libmultipath: use libmp_mapinfo() in do_foreach_partmaps() Martin Wilck
2024-07-09 21:39 ` [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table() Martin Wilck
2024-07-11  5:16   ` Benjamin Marzinski
2024-07-11 15:29     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 36/44] libmultipath: update mpp->dmi " Martin Wilck
2024-07-09 21:39 ` [PATCH 37/44] libmultipath: drop extra call to dm_map_present() in domap() Martin Wilck
2024-07-09 21:39 ` [PATCH 38/44] libmultipath: split off update_multipath_table__() Martin Wilck
2024-07-09 21:39 ` [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo() Martin Wilck
2024-07-11  5:38   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo() Martin Wilck
2024-07-11  6:11   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 41/44] libmultipath: simplify dm_get_maps() Martin Wilck
2024-07-09 21:39 ` [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended() Martin Wilck
2024-07-11  6:27   ` Benjamin Marzinski
2024-07-11 15:35     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec() Martin Wilck
2024-07-11  6:43   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 44/44] libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out() Martin Wilck
2024-07-11  6:55 ` [PATCH 00/44] multipath-tools: devmapper API refactored 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=ZpAm3ZXvPx21XHHO@redhat.com \
    --to=bmarzins@redhat.com \
    --cc=christophe.varoqui@opensvc.com \
    --cc=dm-devel@lists.linux.dev \
    --cc=martin.wilck@suse.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.