Illumos#16463 zfs_ioc_recv leaks nvlist
In https://www.illumos.org/issues/16463 it was observed that an nvlist was being leaked in zfs_ioc_recv() due a missing call to nvlist_free for "hidden_args". For OpenZFS the same issue exists in zfs_ioc_recv_new() and is addressed by this PR. This change also properly frees nvlists in the unlikely event that a call to get_nvlist() fails. Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Igor Kozhukhov <igor@dilos.org> Signed-off-by: Andy Fiddaman <illumos@fiddaman.net> Closes #16077
This commit is contained in:
parent
e5ddecd1a7
commit
44f337be30
|
@ -40,6 +40,7 @@
|
||||||
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
|
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
|
||||||
* Copyright (c) 2019, 2021, Klara Inc.
|
* Copyright (c) 2019, 2021, Klara Inc.
|
||||||
* Copyright (c) 2019, Allan Jude
|
* Copyright (c) 2019, Allan Jude
|
||||||
|
* Copyright 2024 Oxide Computer Company
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5345,8 +5346,9 @@ zfs_ioc_recv(zfs_cmd_t *zc)
|
||||||
|
|
||||||
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
|
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
|
||||||
strchr(zc->zc_value, '@') == NULL ||
|
strchr(zc->zc_value, '@') == NULL ||
|
||||||
strchr(zc->zc_value, '%'))
|
strchr(zc->zc_value, '%') != NULL) {
|
||||||
return (SET_ERROR(EINVAL));
|
return (SET_ERROR(EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
(void) strlcpy(tofs, zc->zc_value, sizeof (tofs));
|
(void) strlcpy(tofs, zc->zc_value, sizeof (tofs));
|
||||||
tosnap = strchr(tofs, '@');
|
tosnap = strchr(tofs, '@');
|
||||||
|
@ -5354,13 +5356,15 @@ zfs_ioc_recv(zfs_cmd_t *zc)
|
||||||
|
|
||||||
if (zc->zc_nvlist_src != 0 &&
|
if (zc->zc_nvlist_src != 0 &&
|
||||||
(error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
|
(error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
|
||||||
zc->zc_iflags, &recvdprops)) != 0)
|
zc->zc_iflags, &recvdprops)) != 0) {
|
||||||
return (error);
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (zc->zc_nvlist_conf != 0 &&
|
if (zc->zc_nvlist_conf != 0 &&
|
||||||
(error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
|
(error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
|
||||||
zc->zc_iflags, &localprops)) != 0)
|
zc->zc_iflags, &localprops)) != 0) {
|
||||||
return (error);
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (zc->zc_string[0])
|
if (zc->zc_string[0])
|
||||||
origin = zc->zc_string;
|
origin = zc->zc_string;
|
||||||
|
@ -5372,8 +5376,6 @@ zfs_ioc_recv(zfs_cmd_t *zc)
|
||||||
error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvdprops, localprops,
|
error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvdprops, localprops,
|
||||||
NULL, zc->zc_guid, B_FALSE, B_FALSE, zc->zc_cookie, &begin_record,
|
NULL, zc->zc_guid, B_FALSE, B_FALSE, zc->zc_cookie, &begin_record,
|
||||||
&zc->zc_cookie, &zc->zc_obj, &errors);
|
&zc->zc_cookie, &zc->zc_obj, &errors);
|
||||||
nvlist_free(recvdprops);
|
|
||||||
nvlist_free(localprops);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that all props, initial and delayed, are set, report the prop
|
* Now that all props, initial and delayed, are set, report the prop
|
||||||
|
@ -5389,7 +5391,10 @@ zfs_ioc_recv(zfs_cmd_t *zc)
|
||||||
error = SET_ERROR(EINVAL);
|
error = SET_ERROR(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
nvlist_free(errors);
|
nvlist_free(errors);
|
||||||
|
nvlist_free(recvdprops);
|
||||||
|
nvlist_free(localprops);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -5456,8 +5461,9 @@ zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
|
|
||||||
if (dataset_namecheck(snapname, NULL, NULL) != 0 ||
|
if (dataset_namecheck(snapname, NULL, NULL) != 0 ||
|
||||||
strchr(snapname, '@') == NULL ||
|
strchr(snapname, '@') == NULL ||
|
||||||
strchr(snapname, '%'))
|
strchr(snapname, '%') != NULL) {
|
||||||
return (SET_ERROR(EINVAL));
|
return (SET_ERROR(EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
(void) strlcpy(tofs, snapname, sizeof (tofs));
|
(void) strlcpy(tofs, snapname, sizeof (tofs));
|
||||||
tosnap = strchr(tofs, '@');
|
tosnap = strchr(tofs, '@');
|
||||||
|
@ -5481,15 +5487,15 @@ zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
/* we still use "props" here for backwards compatibility */
|
/* we still use "props" here for backwards compatibility */
|
||||||
error = nvlist_lookup_nvlist(innvl, "props", &recvprops);
|
error = nvlist_lookup_nvlist(innvl, "props", &recvprops);
|
||||||
if (error && error != ENOENT)
|
if (error && error != ENOENT)
|
||||||
return (error);
|
goto out;
|
||||||
|
|
||||||
error = nvlist_lookup_nvlist(innvl, "localprops", &localprops);
|
error = nvlist_lookup_nvlist(innvl, "localprops", &localprops);
|
||||||
if (error && error != ENOENT)
|
if (error && error != ENOENT)
|
||||||
return (error);
|
goto out;
|
||||||
|
|
||||||
error = nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args);
|
error = nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args);
|
||||||
if (error && error != ENOENT)
|
if (error && error != ENOENT)
|
||||||
return (error);
|
goto out;
|
||||||
|
|
||||||
error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvprops, localprops,
|
error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvprops, localprops,
|
||||||
hidden_args, force, heal, resumable, input_fd, begin_record,
|
hidden_args, force, heal, resumable, input_fd, begin_record,
|
||||||
|
@ -5499,9 +5505,11 @@ zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
fnvlist_add_uint64(outnvl, "error_flags", errflags);
|
fnvlist_add_uint64(outnvl, "error_flags", errflags);
|
||||||
fnvlist_add_nvlist(outnvl, "errors", errors);
|
fnvlist_add_nvlist(outnvl, "errors", errors);
|
||||||
|
|
||||||
|
out:
|
||||||
nvlist_free(errors);
|
nvlist_free(errors);
|
||||||
nvlist_free(recvprops);
|
nvlist_free(recvprops);
|
||||||
nvlist_free(localprops);
|
nvlist_free(localprops);
|
||||||
|
nvlist_free(hidden_args);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue