aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Fiddaman <illumos@fiddaman.net>2024-04-11 21:38:22 +0000
committerGitHub <noreply@github.com>2024-04-11 21:38:22 +0000
commit44f337be30e1502b32c8d381344044f15dd34674 (patch)
tree28a89aed92242d21f8e01a8850640c79709a6663
parente5ddecd1a7e33bc341e7b5e8dd25d2fe478de8f2 (diff)
downloadsrc-44f337be30e1502b32c8d381344044f15dd34674.tar.gz
src-44f337be30e1502b32c8d381344044f15dd34674.zip
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
-rw-r--r--module/zfs/zfs_ioctl.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index dca15f4b826d..2ac1e34dccec 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -40,6 +40,7 @@
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
* Copyright (c) 2019, 2021, Klara Inc.
* 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 ||
strchr(zc->zc_value, '@') == NULL ||
- strchr(zc->zc_value, '%'))
+ strchr(zc->zc_value, '%') != NULL) {
return (SET_ERROR(EINVAL));
+ }
(void) strlcpy(tofs, zc->zc_value, sizeof (tofs));
tosnap = strchr(tofs, '@');
@@ -5354,13 +5356,15 @@ zfs_ioc_recv(zfs_cmd_t *zc)
if (zc->zc_nvlist_src != 0 &&
(error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
- zc->zc_iflags, &recvdprops)) != 0)
- return (error);
+ zc->zc_iflags, &recvdprops)) != 0) {
+ goto out;
+ }
if (zc->zc_nvlist_conf != 0 &&
(error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
- zc->zc_iflags, &localprops)) != 0)
- return (error);
+ zc->zc_iflags, &localprops)) != 0) {
+ goto out;
+ }
if (zc->zc_string[0])
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,
NULL, zc->zc_guid, B_FALSE, B_FALSE, zc->zc_cookie, &begin_record,
&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
@@ -5389,7 +5391,10 @@ zfs_ioc_recv(zfs_cmd_t *zc)
error = SET_ERROR(EINVAL);
}
+out:
nvlist_free(errors);
+ nvlist_free(recvdprops);
+ nvlist_free(localprops);
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 ||
strchr(snapname, '@') == NULL ||
- strchr(snapname, '%'))
+ strchr(snapname, '%') != NULL) {
return (SET_ERROR(EINVAL));
+ }
(void) strlcpy(tofs, snapname, sizeof (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 */
error = nvlist_lookup_nvlist(innvl, "props", &recvprops);
if (error && error != ENOENT)
- return (error);
+ goto out;
error = nvlist_lookup_nvlist(innvl, "localprops", &localprops);
if (error && error != ENOENT)
- return (error);
+ goto out;
error = nvlist_lookup_nvlist(innvl, ZPOOL_HIDDEN_ARGS, &hidden_args);
if (error && error != ENOENT)
- return (error);
+ goto out;
error = zfs_ioc_recv_impl(tofs, tosnap, origin, recvprops, localprops,
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_nvlist(outnvl, "errors", errors);
+out:
nvlist_free(errors);
nvlist_free(recvprops);
nvlist_free(localprops);
+ nvlist_free(hidden_args);
return (error);
}