[PATCH 4/4] libmultipath: fix over-long NVME WWIDs
Benjamin Marzinski
bmarzins at redhat.com
Fri Jul 14 15:38:02 PDT 2017
ACK, with one small nit below.
-Ben
On Fri, Jul 14, 2017 at 01:32:09PM +0200, Martin Wilck wrote:
> Fix for NVME wwids looking like this:
> nvme.0000-3163653363666438366239656630386200-4c696e75780000000000000000000000000000000000000000000000000000000000000000000000-00000002
> which are encountered in some combinations of Linux NVME host and target,
> where the 2nd field represents the serial number (SN) and the 3rd the
> model number (MN).
>
> The device mapper allows map names only up to 128 characters.
> Strip the "00" sequences at the end of the serial and model field,
> they are hex-encoded 0-bytes which are forbidden by the NVME spec
> anyway.
>
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
> libmultipath/discovery.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 79 insertions(+)
>
> diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
> index 9951af84..f46b9b17 100644
> --- a/libmultipath/discovery.c
> +++ b/libmultipath/discovery.c
> @@ -1598,6 +1598,82 @@ get_prio (struct path * pp)
> return 0;
> }
>
> +/*
> + * Mangle string of length *len starting at start
> + * by removing character sequence "00" (hex for a 0 byte),
> + * starting at end, backwards.
> + * Changes the value of *len if characters were removed.
> + * Returns a pointer to the position where "end" was moved to.
> + */
> +static char
> +*skip_zeroes_backward(char* start, int *len, char *end)
> +{
> + char *p = end;
> +
> + while (p >= start + 2 && *(p - 1) == '0' && *(p - 2) == '0')
> + p -= 2;
> +
> + if (p == end)
> + return p;
> +
> + memmove(p, end, start + *len + 1 - end);
> + *len -= end - p;
> +
> + return p;
> +}
> +
> +/*
> + * Fix for NVME wwids looking like this:
> + * nvme.0000-3163653363666438366239656630386200-4c696e75780000000000000000000000000000000000000000000000000000000000000000000000-00000002
> + * which are encountered in some combinations of Linux NVME host and target.
> + * The '00' are hex-encoded 0-bytes which are forbidden in the serial (SN)
> + * and model (MN) fields. Discard them.
> + * If a WWID of the above type is found, sets pp->wwid and returns a value > 0.
> + * Otherwise, returns 0.
> + */
> +static int
> +fix_broken_nvme_wwid(struct path *pp, const char *value, int size)
> +{
> + static const char _nvme[] = "nvme.";
> + int len, i;
> + char mangled[256];
> + char *p;
> +
> + len = strlen(value);
> + if (len >= sizeof(mangled) || len + 1 < size)
> + return 0;
Don't we check (len + 1 < size) before calling this? It seems odd to
return that we can't do anything when in reality, we simply don't need
to do anything.
-Ben
> +
> + /* Check that value starts with "nvme.%04x-" */
> + if (memcmp(value, _nvme, sizeof(_nvme) - 1) || value[9] != '-')
> + return 0;
> + for (i = 5; i < 9; i++)
> + if (!isxdigit(value[i]))
> + return 0;
> +
> + memcpy(mangled, value, len + 1);
> +
> + /* search end of "model" part and strip trailing '00' */
> + p = memrchr(mangled, '-', len);
> + if (p == NULL)
> + return 0;
> +
> + p = skip_zeroes_backward(mangled, &len, p);
> +
> + /* search end of "serial" part */
> + p = memrchr(mangled, '-', p - mangled);
> + if (p == NULL || memrchr(mangled, '-', p - mangled) != mangled + 9)
> + /* We expect exactly 3 '-' in the value */
> + return 0;
> +
> + p = skip_zeroes_backward(mangled, &len, p);
> + if (len >= size)
> + return 0;
> +
> + memcpy(pp->wwid, mangled, len + 1);
> + condlog(2, "%s: over-long WWID shortened to %s", pp->dev, pp->wwid);
> + return len;
> +}
> +
> static int
> get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
> {
> @@ -1609,6 +1685,9 @@ get_udev_uid(struct path * pp, char *uid_attribute, struct udev_device *udev)
> value = getenv(uid_attribute);
> if (value && strlen(value)) {
> if (strlen(value) + 1 > WWID_SIZE) {
> + len = fix_broken_nvme_wwid(pp, value, WWID_SIZE);
> + if (len > 0)
> + return len;
> condlog(0, "%s: wwid overflow", pp->dev);
> len = WWID_SIZE;
> } else {
> --
> 2.13.2
More information about the Linux-nvme
mailing list