Skip to content

libzfs zpool_find_vdev() overwrites pool config #4312

@don-brady

Description

@don-brady

In zfsonlinx, the libzfs zpool_find_vdev() function has the side-effect of overwriting the pool config associated with the pool handle. Found while integration zfs_mod.c from illumos.

code path of overwrite:

  1. zpool_find_vdev() grabs config nvlist from pool handle and extracts vdev tree
  2. calls into vdev_to_nvlist_iter() with vdev tree, visiting each vdev
  3. calls into zfs_strcmp_pathname() with 'path' string value
  4. calls strtok() on above string and path value is overwritten

an easy way to reproduce is (see actual code below):

$ gcc -m64 -lzfs -lnvpair -I/usr/include/libzfs/ -I/usr/include/libspl zpool_find_vdev.c -o zpool_find_vdev
$ sudo ./zpool_find_vdev serenity

config vdev paths before:
vdev 01123202461778220001: /dev/disk/by-id/scsi-350000394a8caede4-part1
vdev 11514177655449603062: /dev/disk/by-id/scsi-350000394a8cb11f0-part1
vdev 01435883551868357921: /dev/disk/by-id/scsi-350000394a8cb4d8c-part1
vdev 07294385912884184264: /dev/disk/by-id/scsi-350000394a8ca4fc4-part1
vdev 03405823394303353173: /dev/disk/by-id/scsi-350000394a8cb3d64-part1
vdev 06846423427570562778: /dev/disk/by-id/scsi-350000394a8ca4fbc-part1
vdev 12727135398764565842: /dev/disk/by-id/scsi-350000394a8cb2d3c-part1
vdev 12336940145533931721: /dev/disk/by-id/scsi-350000394a8ca4fc0-part1

config vdev paths after:
vdev 01123202461778220001: /dev
vdev 11514177655449603062: /dev
vdev 01435883551868357921: /dev
vdev 07294385912884184264: /dev
vdev 03405823394303353173: /dev
vdev 06846423427570562778: /dev
vdev 12727135398764565842: /dev
vdev 12336940145533931721: /dev

stand-alone code that repoduces the problem:

#include <stdio.h>
#include <libzfs/libnvpair.h>
#include <libzfs/libzfs.h>


static void
print_vdev_paths(zpool_handle_t *zhp, nvlist_t *nvl)
{
    char *path;
    uint_t c, children;
    nvlist_t **child;
    uint64_t guid;

    if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
        &child, &children) == 0) {
        for (c = 0; c < children; c++)
            print_vdev_paths(zhp, child[c]);
        return;
    }
    (void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid);
    (void) nvlist_lookup_string(nvl, ZPOOL_CONFIG_PATH, &path);

    if (guid && path)
        (void) fprintf(stdout, "vdev %020llu: %s\n", guid, path);
}

int
main(int argc, char **argv)
{
    libzfs_handle_t *zfshdl;
    zpool_handle_t *zhp;

    zfshdl = libzfs_init();

    if ((zhp = zpool_open(zfshdl, argv[1])) != NULL) {
        nvlist_t *config, *tree;
        boolean_t tmp;

        config = zpool_get_config(zhp, NULL);
        (void) nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree);

        (void) fprintf(stdout, "\nconfig vdev paths before:\n");
        print_vdev_paths(zhp, tree);

        (void) zpool_find_vdev(zhp, "anything", &tmp, &tmp, &tmp);

        (void) fprintf(stdout, "\nconfig vdev paths after:\n");
        print_vdev_paths(zhp, tree);

        zpool_close(zhp);
    }

    libzfs_fini(zfshdl);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions