zfs_ioc_snapshot: check user-prop permissions on snapshotted datasets

Previously, the permissions were checked on the pool which was obviously
incorrect.

After this change, zfs_check_userprops() only validates the properties
without any permission checks.  The permissions are checked individually
for each snapshotted dataset.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Matt Ahrens <mahrens@delphix.com>
Signed-off-by: Andriy Gapon <avg@FreeBSD.org>
Closes #9179
Closes #9180
This commit is contained in:
Andriy Gapon 2019-08-27 23:45:53 +03:00 committed by Tony Hutter
parent ea34735203
commit 931bef81c8

View File

@ -2744,10 +2744,9 @@ retry:
* Check that all the properties are valid user properties. * Check that all the properties are valid user properties.
*/ */
static int static int
zfs_check_userprops(const char *fsname, nvlist_t *nvl) zfs_check_userprops(nvlist_t *nvl)
{ {
nvpair_t *pair = NULL; nvpair_t *pair = NULL;
int error = 0;
while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) { while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
const char *propname = nvpair_name(pair); const char *propname = nvpair_name(pair);
@ -2756,10 +2755,6 @@ zfs_check_userprops(const char *fsname, nvlist_t *nvl)
nvpair_type(pair) != DATA_TYPE_STRING) nvpair_type(pair) != DATA_TYPE_STRING)
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if ((error = zfs_secpolicy_write_perms(fsname,
ZFS_DELEG_PERM_USERPROP, CRED())))
return (error);
if (strlen(propname) >= ZAP_MAXNAMELEN) if (strlen(propname) >= ZAP_MAXNAMELEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
@ -3473,19 +3468,18 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
nvpair_t *pair; nvpair_t *pair;
(void) nvlist_lookup_nvlist(innvl, "props", &props); (void) nvlist_lookup_nvlist(innvl, "props", &props);
if ((error = zfs_check_userprops(poolname, props)) != 0)
return (error);
if (!nvlist_empty(props) && if (!nvlist_empty(props) &&
zfs_earlier_version(poolname, SPA_VERSION_SNAP_PROPS)) zfs_earlier_version(poolname, SPA_VERSION_SNAP_PROPS))
return (SET_ERROR(ENOTSUP)); return (SET_ERROR(ENOTSUP));
if ((error = zfs_check_userprops(props)) != 0)
return (error);
snaps = fnvlist_lookup_nvlist(innvl, "snaps"); snaps = fnvlist_lookup_nvlist(innvl, "snaps");
poollen = strlen(poolname); poollen = strlen(poolname);
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) { pair = nvlist_next_nvpair(snaps, pair)) {
const char *name = nvpair_name(pair); const char *name = nvpair_name(pair);
const char *cp = strchr(name, '@'); char *cp = strchr(name, '@');
/* /*
* The snap name must contain an @, and the part after it must * The snap name must contain an @, and the part after it must
@ -3502,6 +3496,18 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
(name[poollen] != '/' && name[poollen] != '@')) (name[poollen] != '/' && name[poollen] != '@'))
return (SET_ERROR(EXDEV)); return (SET_ERROR(EXDEV));
/*
* Check for permission to set the properties on the fs.
*/
if (!nvlist_empty(props)) {
*cp = '\0';
error = zfs_secpolicy_write_perms(name,
ZFS_DELEG_PERM_USERPROP, CRED());
*cp = '@';
if (error != 0)
return (error);
}
/* This must be the only snap of this fs. */ /* This must be the only snap of this fs. */
for (nvpair_t *pair2 = nvlist_next_nvpair(snaps, pair); for (nvpair_t *pair2 = nvlist_next_nvpair(snaps, pair);
pair2 != NULL; pair2 = nvlist_next_nvpair(snaps, pair2)) { pair2 != NULL; pair2 = nvlist_next_nvpair(snaps, pair2)) {