aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/os/freebsd/spl/sys/policy.h1
-rw-r--r--include/os/linux/zfs/sys/policy.h1
-rw-r--r--include/sys/dmu_recv.h1
-rw-r--r--include/sys/dsl_dataset.h4
-rw-r--r--include/sys/dsl_dir.h4
-rw-r--r--include/sys/zcp.h1
-rw-r--r--include/sys/zfs_context.h1
-rw-r--r--lib/libzpool/kernel.c6
-rw-r--r--module/os/freebsd/spl/spl_policy.c7
-rw-r--r--module/os/linux/zfs/policy.c53
-rw-r--r--module/zfs/dmu_objset.c8
-rw-r--r--module/zfs/dmu_recv.c17
-rw-r--r--module/zfs/dsl_dataset.c14
-rw-r--r--module/zfs/dsl_dir.c29
-rw-r--r--module/zfs/zcp.c1
-rw-r--r--module/zfs/zcp_synctask.c2
-rwxr-xr-xtests/test-runner/bin/zts-report.py2
17 files changed, 104 insertions, 48 deletions
diff --git a/include/os/freebsd/spl/sys/policy.h b/include/os/freebsd/spl/sys/policy.h
index 663720202..3a05da12b 100644
--- a/include/os/freebsd/spl/sys/policy.h
+++ b/include/os/freebsd/spl/sys/policy.h
@@ -37,6 +37,7 @@ struct vattr;
int secpolicy_nfs(cred_t *cr);
int secpolicy_zfs(cred_t *crd);
+int secpolicy_zfs_proc(cred_t *cr, proc_t *proc);
int secpolicy_sys_config(cred_t *cr, int checkonly);
int secpolicy_zinject(cred_t *cr);
int secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp);
diff --git a/include/os/linux/zfs/sys/policy.h b/include/os/linux/zfs/sys/policy.h
index a8327e02f..77a73ad14 100644
--- a/include/os/linux/zfs/sys/policy.h
+++ b/include/os/linux/zfs/sys/policy.h
@@ -48,6 +48,7 @@ int secpolicy_vnode_setid_retain(const cred_t *, boolean_t);
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t);
int secpolicy_zinject(const cred_t *);
int secpolicy_zfs(const cred_t *);
+int secpolicy_zfs_proc(const cred_t *, proc_t *);
void secpolicy_setid_clear(vattr_t *, cred_t *);
int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
const vattr_t *, cred_t *);
diff --git a/include/sys/dmu_recv.h b/include/sys/dmu_recv.h
index ed041ba70..dacc6b782 100644
--- a/include/sys/dmu_recv.h
+++ b/include/sys/dmu_recv.h
@@ -58,6 +58,7 @@ typedef struct dmu_recv_cookie {
uint64_t drc_ivset_guid;
void *drc_owner;
cred_t *drc_cred;
+ proc_t *drc_proc;
nvlist_t *drc_begin_nvl;
objset_t *drc_os;
diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h
index 9de9a88d8..77fa440f2 100644
--- a/include/sys/dsl_dataset.h
+++ b/include/sys/dsl_dataset.h
@@ -284,6 +284,7 @@ typedef struct dsl_dataset_promote_arg {
uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
nvlist_t *err_ds;
cred_t *cr;
+ proc_t *proc;
} dsl_dataset_promote_arg_t;
typedef struct dsl_dataset_rollback_arg {
@@ -298,6 +299,7 @@ typedef struct dsl_dataset_snapshot_arg {
nvlist_t *ddsa_props;
nvlist_t *ddsa_errors;
cred_t *ddsa_cr;
+ proc_t *ddsa_proc;
} dsl_dataset_snapshot_arg_t;
/*
@@ -445,7 +447,7 @@ int dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
void dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
dsl_dataset_t *origin_head, dmu_tx_t *tx);
int dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
- dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr);
+ dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr, proc_t *proc);
void dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
dmu_tx_t *tx);
diff --git a/include/sys/dsl_dir.h b/include/sys/dsl_dir.h
index 88fd61035..b894bcfff 100644
--- a/include/sys/dsl_dir.h
+++ b/include/sys/dsl_dir.h
@@ -180,11 +180,11 @@ int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
uint64_t reservation);
int dsl_dir_activate_fs_ss_limit(const char *);
int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
- cred_t *);
+ cred_t *, proc_t *);
void dsl_fs_ss_count_adjust(dsl_dir_t *, int64_t, const char *, dmu_tx_t *);
int dsl_dir_rename(const char *oldname, const char *newname);
int dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
- uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *);
+ uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *, proc_t *);
boolean_t dsl_dir_is_clone(dsl_dir_t *dd);
void dsl_dir_new_refreservation(dsl_dir_t *dd, struct dsl_dataset *ds,
uint64_t reservation, cred_t *cr, dmu_tx_t *tx);
diff --git a/include/sys/zcp.h b/include/sys/zcp.h
index 3d1480050..d7b1dfaa2 100644
--- a/include/sys/zcp.h
+++ b/include/sys/zcp.h
@@ -75,6 +75,7 @@ typedef struct zcp_run_info {
* rather than the 'current' thread's.
*/
cred_t *zri_cred;
+ proc_t *zri_proc;
/*
* The tx in which this channel program is running.
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
index ba6a1a2c9..95f963e73 100644
--- a/include/sys/zfs_context.h
+++ b/include/sys/zfs_context.h
@@ -709,6 +709,7 @@ extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
cred_t *cr);
extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
extern int secpolicy_zfs(const cred_t *cr);
+extern int secpolicy_zfs_proc(const cred_t *cr, proc_t *proc);
extern zoneid_t getzoneid(void);
/* SID stuff */
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index 59c5818de..aedcbfa66 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -909,6 +909,12 @@ secpolicy_zfs(const cred_t *cr)
return (0);
}
+int
+secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
+{
+ return (0);
+}
+
ksiddomain_t *
ksid_lookupdomain(const char *dom)
{
diff --git a/module/os/freebsd/spl/spl_policy.c b/module/os/freebsd/spl/spl_policy.c
index 53732836f..8ef4ca88b 100644
--- a/module/os/freebsd/spl/spl_policy.c
+++ b/module/os/freebsd/spl/spl_policy.c
@@ -53,6 +53,13 @@ secpolicy_zfs(cred_t *cr)
}
int
+secpolicy_zfs_proc(cred_t *cr, proc_t *proc)
+{
+
+ return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
+}
+
+int
secpolicy_sys_config(cred_t *cr, int checkonly __unused)
{
diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c
index 552530226..eaa5372f2 100644
--- a/module/os/linux/zfs/policy.c
+++ b/module/os/linux/zfs/policy.c
@@ -42,11 +42,9 @@
* all other cases this function must fail and return the passed err.
*/
static int
-priv_policy_ns(const cred_t *cr, int capability, boolean_t all, int err,
+priv_policy_ns(const cred_t *cr, int capability, int err,
struct user_namespace *ns)
{
- ASSERT3S(all, ==, B_FALSE);
-
if (cr != CRED() && (cr != kcred))
return (err);
@@ -61,13 +59,13 @@ priv_policy_ns(const cred_t *cr, int capability, boolean_t all, int err,
}
static int
-priv_policy(const cred_t *cr, int capability, boolean_t all, int err)
+priv_policy(const cred_t *cr, int capability, int err)
{
- return (priv_policy_ns(cr, capability, all, err, NULL));
+ return (priv_policy_ns(cr, capability, err, NULL));
}
static int
-priv_policy_user(const cred_t *cr, int capability, boolean_t all, int err)
+priv_policy_user(const cred_t *cr, int capability, int err)
{
/*
* All priv_policy_user checks are preceded by kuid/kgid_has_mapping()
@@ -76,9 +74,9 @@ priv_policy_user(const cred_t *cr, int capability, boolean_t all, int err)
* namespace.
*/
#if defined(CONFIG_USER_NS)
- return (priv_policy_ns(cr, capability, all, err, cr->user_ns));
+ return (priv_policy_ns(cr, capability, err, cr->user_ns));
#else
- return (priv_policy_ns(cr, capability, all, err, NULL));
+ return (priv_policy_ns(cr, capability, err, NULL));
#endif
}
@@ -89,7 +87,7 @@ priv_policy_user(const cred_t *cr, int capability, boolean_t all, int err)
int
secpolicy_nfs(const cred_t *cr)
{
- return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EPERM));
+ return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
}
/*
@@ -98,7 +96,7 @@ secpolicy_nfs(const cred_t *cr)
int
secpolicy_sys_config(const cred_t *cr, boolean_t checkonly)
{
- return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EPERM));
+ return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
}
/*
@@ -134,10 +132,10 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
return (EPERM);
#endif
- if (priv_policy_user(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0)
+ if (priv_policy_user(cr, CAP_DAC_OVERRIDE, EPERM) == 0)
return (0);
- if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0)
+ if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, EPERM) == 0)
return (0);
return (EPERM);
@@ -157,7 +155,7 @@ secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
return (EPERM);
#endif
- return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM));
+ return (priv_policy_user(cr, CAP_FOWNER, EPERM));
}
/*
@@ -166,7 +164,7 @@ secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
int
secpolicy_vnode_create_gid(const cred_t *cr)
{
- return (priv_policy(cr, CAP_SETGID, B_FALSE, EPERM));
+ return (priv_policy(cr, CAP_SETGID, EPERM));
}
/*
@@ -176,7 +174,7 @@ secpolicy_vnode_create_gid(const cred_t *cr)
int
secpolicy_vnode_remove(const cred_t *cr)
{
- return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
+ return (priv_policy(cr, CAP_FOWNER, EPERM));
}
/*
@@ -194,7 +192,7 @@ secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
return (EPERM);
#endif
- return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM));
+ return (priv_policy_user(cr, CAP_FOWNER, EPERM));
}
/*
@@ -208,7 +206,7 @@ secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
int
secpolicy_vnode_setid_retain(const cred_t *cr, boolean_t issuidroot)
{
- return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));
+ return (priv_policy_user(cr, CAP_FSETID, EPERM));
}
/*
@@ -222,7 +220,7 @@ secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid)
return (EPERM);
#endif
if (crgetfsgid(cr) != gid && !groupmember(gid, cr))
- return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));
+ return (priv_policy_user(cr, CAP_FSETID, EPERM));
return (0);
}
@@ -234,7 +232,7 @@ secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid)
int
secpolicy_zinject(const cred_t *cr)
{
- return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EACCES));
+ return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
}
/*
@@ -244,7 +242,20 @@ secpolicy_zinject(const cred_t *cr)
int
secpolicy_zfs(const cred_t *cr)
{
- return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EACCES));
+ return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
+}
+
+/*
+ * Equivalent to secpolicy_zfs(), but works even if the cred_t is not that of
+ * the current process. Takes both cred_t and proc_t so that this can work
+ * easily on all platforms.
+ */
+int
+secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
+{
+ if (!has_capability(proc, CAP_SYS_ADMIN))
+ return (EACCES);
+ return (0);
}
void
@@ -273,7 +284,7 @@ secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner)
return (EPERM);
#endif
- return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));
+ return (priv_policy_user(cr, CAP_FSETID, EPERM));
}
/*
diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
index dd72a7dc2..30be3c4f2 100644
--- a/module/zfs/dmu_objset.c
+++ b/module/zfs/dmu_objset.c
@@ -1096,6 +1096,7 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
typedef struct dmu_objset_create_arg {
const char *doca_name;
cred_t *doca_cred;
+ proc_t *doca_proc;
void (*doca_userfunc)(objset_t *os, void *arg,
cred_t *cr, dmu_tx_t *tx);
void *doca_userarg;
@@ -1140,7 +1141,7 @@ dmu_objset_create_check(void *arg, dmu_tx_t *tx)
}
error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
- doca->doca_cred);
+ doca->doca_cred, doca->doca_proc);
if (error != 0) {
dsl_dir_rele(pdd, FTAG);
return (error);
@@ -1268,6 +1269,7 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
doca.doca_name = name;
doca.doca_cred = CRED();
+ doca.doca_proc = curproc;
doca.doca_flags = flags;
doca.doca_userfunc = func;
doca.doca_userarg = arg;
@@ -1296,6 +1298,7 @@ typedef struct dmu_objset_clone_arg {
const char *doca_clone;
const char *doca_origin;
cred_t *doca_cred;
+ proc_t *doca_proc;
} dmu_objset_clone_arg_t;
/*ARGSUSED*/
@@ -1324,7 +1327,7 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
}
error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
- doca->doca_cred);
+ doca->doca_cred, doca->doca_proc);
if (error != 0) {
dsl_dir_rele(pdd, FTAG);
return (SET_ERROR(EDQUOT));
@@ -1383,6 +1386,7 @@ dmu_objset_clone(const char *clone, const char *origin)
doca.doca_clone = clone;
doca.doca_origin = origin;
doca.doca_cred = CRED();
+ doca.doca_proc = curproc;
int rv = dsl_sync_task(clone,
dmu_objset_clone_check, dmu_objset_clone_sync, &doca,
diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c
index 17ebeb682..2f3507914 100644
--- a/module/zfs/dmu_recv.c
+++ b/module/zfs/dmu_recv.c
@@ -126,6 +126,7 @@ typedef struct dmu_recv_begin_arg {
const char *drba_origin;
dmu_recv_cookie_t *drba_cookie;
cred_t *drba_cred;
+ proc_t *drba_proc;
dsl_crypto_params_t *drba_dcp;
} dmu_recv_begin_arg_t;
@@ -398,7 +399,7 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
* against that limit.
*/
error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT,
- NULL, drba->drba_cred);
+ NULL, drba->drba_cred, drba->drba_proc);
if (error != 0)
return (error);
@@ -679,14 +680,16 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
* filesystems and increment those counts during begin_sync).
*/
error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
- ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred);
+ ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+ drba->drba_cred, drba->drba_proc);
if (error != 0) {
dsl_dataset_rele(ds, FTAG);
return (error);
}
error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
- ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred);
+ ZFS_PROP_SNAPSHOT_LIMIT, NULL,
+ drba->drba_cred, drba->drba_proc);
if (error != 0) {
dsl_dataset_rele(ds, FTAG);
return (error);
@@ -1152,6 +1155,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
drc->drc_force = force;
drc->drc_resumable = resumable;
drc->drc_cred = CRED();
+ drc->drc_proc = curproc;
drc->drc_clone = (origin != NULL);
if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
@@ -1199,6 +1203,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
drba.drba_origin = origin;
drba.drba_cookie = drc;
drba.drba_cred = CRED();
+ drba.drba_proc = curproc;
if (drc->drc_featureflags & DMU_BACKUP_FEATURE_RESUMING) {
err = dsl_sync_task(tofs,
@@ -3133,7 +3138,8 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx)
return (error);
}
error = dsl_dataset_snapshot_check_impl(origin_head,
- drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ drc->drc_tosnap, tx, B_TRUE, 1,
+ drc->drc_cred, drc->drc_proc);
dsl_dataset_rele(origin_head, FTAG);
if (error != 0)
return (error);
@@ -3141,7 +3147,8 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx)
error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
} else {
error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
- drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ drc->drc_tosnap, tx, B_TRUE, 1,
+ drc->drc_cred, drc->drc_proc);
}
return (error);
}
diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c
index 4986bc449..c04f47d36 100644
--- a/module/zfs/dsl_dataset.c
+++ b/module/zfs/dsl_dataset.c
@@ -1465,7 +1465,7 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
int
dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
- dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr)
+ dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr, proc_t *proc)
{
int error;
uint64_t value;
@@ -1510,7 +1510,7 @@ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
*/
if (cnt != 0 && cr != NULL) {
error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
- ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr);
+ ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr, proc);
if (error != 0)
return (error);
}
@@ -1611,7 +1611,7 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
if (error == 0) {
error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
ZFS_PROP_SNAPSHOT_LIMIT, NULL,
- ddsa->ddsa_cr);
+ ddsa->ddsa_cr, ddsa->ddsa_proc);
dsl_dataset_rele(ds, FTAG);
}
@@ -1649,7 +1649,7 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
if (error == 0) {
/* passing 0/NULL skips dsl_fs_ss_limit_check */
error = dsl_dataset_snapshot_check_impl(ds,
- atp + 1, tx, B_FALSE, 0, NULL);
+ atp + 1, tx, B_FALSE, 0, NULL, NULL);
dsl_dataset_rele(ds, FTAG);
}
@@ -1927,6 +1927,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
ddsa.ddsa_props = props;
ddsa.ddsa_errors = errors;
ddsa.ddsa_cr = CRED();
+ ddsa.ddsa_proc = curproc;
if (error == 0) {
error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
@@ -1974,7 +1975,7 @@ dsl_dataset_snapshot_tmp_check(void *arg, dmu_tx_t *tx)
/* NULL cred means no limit check for tmp snapshot */
error = dsl_dataset_snapshot_check_impl(ds, ddsta->ddsta_snapname,
- tx, B_FALSE, 0, NULL);
+ tx, B_FALSE, 0, NULL, NULL);
if (error != 0) {
dsl_dataset_rele(ds, FTAG);
return (error);
@@ -3477,7 +3478,7 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
/* Check that there is enough space and limit headroom here */
err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir,
- 0, ss_mv_cnt, ddpa->used, ddpa->cr);
+ 0, ss_mv_cnt, ddpa->used, ddpa->cr, ddpa->proc);
if (err != 0)
goto out;
@@ -3904,6 +3905,7 @@ dsl_dataset_promote(const char *name, char *conflsnap)
ddpa.ddpa_clonename = name;
ddpa.err_ds = fnvlist_alloc();
ddpa.cr = CRED();
+ ddpa.proc = curproc;
error = dsl_sync_task(name, dsl_dataset_promote_check,
dsl_dataset_promote_sync, &ddpa,
diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
index 977600116..da6103b4b 100644
--- a/module/zfs/dsl_dir.c
+++ b/module/zfs/dsl_dir.c
@@ -749,7 +749,8 @@ typedef enum {
} enforce_res_t;
static enforce_res_t
-dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
+dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop,
+ cred_t *cr, proc_t *proc)
{
enforce_res_t enforce = ENFORCE_ALWAYS;
uint64_t obj;
@@ -764,7 +765,13 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
if (crgetzoneid(cr) != GLOBAL_ZONEID)
return (ENFORCE_ALWAYS);
- if (secpolicy_zfs(cr) == 0)
+ /*
+ * We are checking the saved credentials of the user process, which is
+ * not the current process. Note that we can't use secpolicy_zfs(),
+ * because it only works if the cred is that of the current process (on
+ * Linux).
+ */
+ if (secpolicy_zfs_proc(cr, proc) == 0)
return (ENFORCE_NEVER);
#endif
@@ -799,7 +806,7 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
*/
int
dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
- dsl_dir_t *ancestor, cred_t *cr)
+ dsl_dir_t *ancestor, cred_t *cr, proc_t *proc)
{
objset_t *os = dd->dd_pool->dp_meta_objset;
uint64_t limit, count;
@@ -819,7 +826,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
* are allowed to change the limit on the current dataset, but there
* is another limit in the tree above.
*/
- enforce = dsl_enforce_ds_ss_limits(dd, prop, cr);
+ enforce = dsl_enforce_ds_ss_limits(dd, prop, cr, proc);
if (enforce == ENFORCE_NEVER)
return (0);
@@ -871,7 +878,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
if (dd->dd_parent != NULL)
err = dsl_fs_ss_limit_check(dd->dd_parent, delta, prop,
- ancestor, cr);
+ ancestor, cr, proc);
return (err);
}
@@ -1840,6 +1847,7 @@ typedef struct dsl_dir_rename_arg {
const char *ddra_oldname;
const char *ddra_newname;
cred_t *ddra_cred;
+ proc_t *ddra_proc;
} dsl_dir_rename_arg_t;
typedef struct dsl_valid_rename_arg {
@@ -2018,7 +2026,8 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
}
error = dsl_dir_transfer_possible(dd->dd_parent,
- newparent, fs_cnt, ss_cnt, myspace, ddra->ddra_cred);
+ newparent, fs_cnt, ss_cnt, myspace,
+ ddra->ddra_cred, ddra->ddra_proc);
if (error != 0) {
dsl_dir_rele(newparent, FTAG);
dsl_dir_rele(dd, FTAG);
@@ -2138,6 +2147,7 @@ dsl_dir_rename(const char *oldname, const char *newname)
ddra.ddra_oldname = oldname;
ddra.ddra_newname = newname;
ddra.ddra_cred = CRED();
+ ddra.ddra_proc = curproc;
return (dsl_sync_task(oldname,
dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
@@ -2146,7 +2156,8 @@ dsl_dir_rename(const char *oldname, const char *newname)
int
dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
- uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *cr)
+ uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space,
+ cred_t *cr, proc_t *proc)
{
dsl_dir_t *ancestor;
int64_t adelta;
@@ -2160,11 +2171,11 @@ dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
return (SET_ERROR(ENOSPC));
err = dsl_fs_ss_limit_check(tdd, fs_cnt, ZFS_PROP_FILESYSTEM_LIMIT,
- ancestor, cr);
+ ancestor, cr, proc);
if (err != 0)
return (err);
err = dsl_fs_ss_limit_check(tdd, ss_cnt, ZFS_PROP_SNAPSHOT_LIMIT,
- ancestor, cr);
+ ancestor, cr, proc);
if (err != 0)
return (err);
diff --git a/module/zfs/zcp.c b/module/zfs/zcp.c
index 305d09239..793e0e4f0 100644
--- a/module/zfs/zcp.c
+++ b/module/zfs/zcp.c
@@ -1150,6 +1150,7 @@ zcp_eval(const char *poolname, const char *program, boolean_t sync,
runinfo.zri_outnvl = outnvl;
runinfo.zri_result = 0;
runinfo.zri_cred = CRED();
+ runinfo.zri_proc = curproc;
runinfo.zri_timed_out = B_FALSE;
runinfo.zri_canceled = B_FALSE;
runinfo.zri_sync = sync;
diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c
index d9b48a709..4e0fa0d85 100644
--- a/module/zfs/zcp_synctask.c
+++ b/module/zfs/zcp_synctask.c
@@ -186,6 +186,7 @@ zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
ddpa.ddpa_clonename = dsname;
ddpa.err_ds = err_details;
ddpa.cr = ri->zri_cred;
+ ddpa.proc = ri->zri_proc;
/*
* If there was a snapshot name conflict, then err_ds will be filled
@@ -269,6 +270,7 @@ zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
ddsa.ddsa_errors = NULL;
ddsa.ddsa_props = NULL;
ddsa.ddsa_cr = ri->zri_cred;
+ ddsa.ddsa_proc = ri->zri_proc;
ddsa.ddsa_snaps = fnvlist_alloc();
fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);
diff --git a/tests/test-runner/bin/zts-report.py b/tests/test-runner/bin/zts-report.py
index 0162248ed..4a9d08752 100755
--- a/tests/test-runner/bin/zts-report.py
+++ b/tests/test-runner/bin/zts-report.py
@@ -171,8 +171,6 @@ elif sys.platform.startswith('linux'):
'casenorm/mixed_formd_delete': ['FAIL', '7633'],
'casenorm/sensitive_formd_lookup': ['FAIL', '7633'],
'casenorm/sensitive_formd_delete': ['FAIL', '7633'],
- 'limits/filesystem_limit': ['FAIL', '8226'],
- 'limits/snapshot_limit': ['FAIL', '8226'],
'removal/removal_with_zdb': ['SKIP', known_reason],
})