diff options
-rw-r--r-- | include/os/freebsd/spl/sys/policy.h | 1 | ||||
-rw-r--r-- | include/os/linux/zfs/sys/policy.h | 1 | ||||
-rw-r--r-- | include/sys/dmu_recv.h | 1 | ||||
-rw-r--r-- | include/sys/dsl_dataset.h | 4 | ||||
-rw-r--r-- | include/sys/dsl_dir.h | 4 | ||||
-rw-r--r-- | include/sys/zcp.h | 1 | ||||
-rw-r--r-- | include/sys/zfs_context.h | 1 | ||||
-rw-r--r-- | lib/libzpool/kernel.c | 6 | ||||
-rw-r--r-- | module/os/freebsd/spl/spl_policy.c | 7 | ||||
-rw-r--r-- | module/os/linux/zfs/policy.c | 53 | ||||
-rw-r--r-- | module/zfs/dmu_objset.c | 8 | ||||
-rw-r--r-- | module/zfs/dmu_recv.c | 17 | ||||
-rw-r--r-- | module/zfs/dsl_dataset.c | 14 | ||||
-rw-r--r-- | module/zfs/dsl_dir.c | 29 | ||||
-rw-r--r-- | module/zfs/zcp.c | 1 | ||||
-rw-r--r-- | module/zfs/zcp_synctask.c | 2 | ||||
-rwxr-xr-x | tests/test-runner/bin/zts-report.py | 2 |
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], }) |