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 <asomers@gmail.com>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Allan Jude <allan@klarasystems.com>
Reviewed-by: George Wilson <gwilson@delphix.com>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
This commit is contained in:
Alan Somers 2024-08-07 14:44:55 -06:00 committed by GitHub
parent bd949b10be
commit 1f5bf91a85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -529,9 +529,10 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
zpool_prop_t prop; zpool_prop_t prop;
const char *strval; const char *strval;
uint64_t intval; uint64_t intval;
const char *slash, *check; const char *check;
struct stat64 statbuf; struct stat64 statbuf;
zpool_handle_t *zhp; zpool_handle_t *zhp;
char *parent, *slash;
char report[1024]; char report[1024];
if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 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; 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 || if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
strcmp(slash, "/..") == 0) { strcmp(slash, "/..") == 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 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); (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
free(parent);
goto error; goto error;
} }
*(char *)slash = '\0'; *slash = '\0';
if (strval[0] != '\0' && if (parent[0] != '\0' &&
(stat64(strval, &statbuf) != 0 || (stat64(parent, &statbuf) != 0 ||
!S_ISDIR(statbuf.st_mode))) { !S_ISDIR(statbuf.st_mode))) {
*(char *)slash = '/';
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' is not a valid directory"), "'%s' is not a valid directory"),
strval); parent);
(void) zfs_error(hdl, EZFS_BADPATH, errbuf); (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
free(parent);
goto error; goto error;
} }
free(parent);
*(char *)slash = '/';
break; break;
case ZPOOL_PROP_COMPATIBILITY: case ZPOOL_PROP_COMPATIBILITY: