From 1f5bf91a85e93afa17bc9c03fe7fade0852da046 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 7 Aug 2024 14:44:55 -0600 Subject: [PATCH] Fix memory corruption during parallel zpool import with -o cachefile (#16419) When importing multiple pools, the nvlist of properties given with "-o" is shared amongst the several threads. So no thread should modify it. Previously, in the course of validating the cachefile property, the zpool_valid_proplist function would temporarily modify the value, and then change it back. Now it will operate on a clone of the value. Sponsored by: Axcient Fixes #16405 Signed-off-by: Alan Somers Reviewed-by: Tony Hutter Reviewed-by: Allan Jude Reviewed-by: George Wilson Reviewed-by: Alexander Motin --- lib/libzfs/libzfs_pool.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index b9ddd75f0d..8a043aa0f8 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -529,9 +529,10 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, zpool_prop_t prop; const char *strval; uint64_t intval; - const char *slash, *check; + const char *check; struct stat64 statbuf; zpool_handle_t *zhp; + char *parent, *slash; char report[1024]; if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { @@ -785,30 +786,36 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, goto error; } - slash = strrchr(strval, '/'); + parent = strdup(strval); + if (parent == NULL) { + (void) zfs_error(hdl, EZFS_NOMEM, errbuf); + goto error; + } + slash = strrchr(parent, '/'); if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || strcmp(slash, "/..") == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "'%s' is not a valid file"), strval); + "'%s' is not a valid file"), parent); (void) zfs_error(hdl, EZFS_BADPATH, errbuf); + free(parent); goto error; } - *(char *)slash = '\0'; + *slash = '\0'; - if (strval[0] != '\0' && - (stat64(strval, &statbuf) != 0 || + if (parent[0] != '\0' && + (stat64(parent, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))) { - *(char *)slash = '/'; zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is not a valid directory"), - strval); + parent); (void) zfs_error(hdl, EZFS_BADPATH, errbuf); + free(parent); goto error; } + free(parent); - *(char *)slash = '/'; break; case ZPOOL_PROP_COMPATIBILITY: