diff --git a/include/os/freebsd/spl/sys/policy.h b/include/os/freebsd/spl/sys/policy.h index 639ade831..48bc4f3d5 100644 --- a/include/os/freebsd/spl/sys/policy.h +++ b/include/os/freebsd/spl/sys/policy.h @@ -39,7 +39,6 @@ struct znode; 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 77d0cdef5..8fa6ab01d 100644 --- a/include/os/linux/zfs/sys/policy.h +++ b/include/os/linux/zfs/sys/policy.h @@ -52,7 +52,6 @@ int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zidmap_t *, struct user_namespace *); 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 *, zidmap_t *, struct user_namespace *); diff --git a/include/sys/dmu_recv.h b/include/sys/dmu_recv.h index cd292d924..ffb2b602d 100644 --- a/include/sys/dmu_recv.h +++ b/include/sys/dmu_recv.h @@ -60,7 +60,6 @@ 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 624f3ddde..681294593 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -284,7 +284,6 @@ 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 { @@ -299,7 +298,6 @@ 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; typedef struct dsl_dataset_rename_snapshot_arg { @@ -459,7 +457,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, proc_t *proc); + dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr); 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 6135835fc..d2e9e2282 100644 --- a/include/sys/dsl_dir.h +++ b/include/sys/dsl_dir.h @@ -185,11 +185,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 *, proc_t *); + cred_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 *, proc_t *); + uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_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 96279deae..5fcfb6219 100644 --- a/include/sys/zcp.h +++ b/include/sys/zcp.h @@ -76,7 +76,6 @@ 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 549f54c09..b3d48e257 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -632,6 +632,9 @@ extern void delay(clock_t ticks); #define kcred NULL #define CRED() NULL +#define crhold(cr) ((void)cr) +#define crfree(cr) ((void)cr) + #define ptob(x) ((x) * PAGESIZE) #define NN_DIVISOR_1000 (1U << 0) @@ -744,7 +747,6 @@ 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 653380149..e397fc851 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -918,13 +918,6 @@ secpolicy_zfs(const cred_t *cr) return (0); } -int -secpolicy_zfs_proc(const cred_t *cr, proc_t *proc) -{ - (void) cr, (void) 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 aad3ef2fa..7fc93648c 100644 --- a/module/os/freebsd/spl/spl_policy.c +++ b/module/os/freebsd/spl/spl_policy.c @@ -52,13 +52,6 @@ secpolicy_zfs(cred_t *cr) return (priv_check_cred(cr, PRIV_VFS_MOUNT)); } -int -secpolicy_zfs_proc(cred_t *cr, proc_t *proc) -{ - - return (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 c50ffcfe6..4396a5d9e 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -24,6 +24,7 @@ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013, Joyent, Inc. All rights reserved. * Copyright (C) 2016 Lawrence Livermore National Security, LLC. + * Copyright (c) 2025, Rob Norris * * For Linux the vast majority of this enforcement is already handled via * the standard Linux VFS permission checks. However certain administrative @@ -35,28 +36,32 @@ #include #include -/* - * The passed credentials cannot be directly verified because Linux only - * provides and interface to check the *current* process credentials. In - * order to handle this the capable() test is only run when the passed - * credentials match the current process credentials or the kcred. In - * all other cases this function must fail and return the passed err. - */ static int priv_policy_ns(const cred_t *cr, int capability, int err, struct user_namespace *ns) { - if (cr != CRED() && (cr != kcred)) - return (err); + /* + * The passed credentials cannot be directly verified because Linux + * only provides an interface to check the *current* process + * credentials. In order to handle this we check if the passed in + * creds match the current process credentials or the kcred. If not, + * we swap the passed credentials into the current task, perform the + * check, and then revert it before returning. + */ + const cred_t *old = + (cr != CRED() && cr != kcred) ? override_creds(cr) : NULL; #if defined(CONFIG_USER_NS) - if (!(ns ? ns_capable(ns, capability) : capable(capability))) + if (ns ? ns_capable(ns, capability) : capable(capability)) #else - if (!capable(capability)) + if (capable(capability)) #endif - return (err); + err = 0; - return (0); + if (old) + revert_creds(old); + + return (err); } static int @@ -249,19 +254,6 @@ secpolicy_zfs(const cred_t *cr) 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 secpolicy_setid_clear(vattr_t *vap, cred_t *cr) { diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index f22a236a6..6ab4304fa 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -34,6 +34,7 @@ * Copyright (c) 2019, Klara Inc. * Copyright (c) 2019, Allan Jude * Copyright (c) 2022 Hewlett Packard Enterprise Development LP. + * Copyright (c) 2025, Rob Norris */ /* Portions Copyright 2010 Robert Milkowski */ @@ -68,6 +69,7 @@ #include #include #include +#include /* * Needed to close a window in dnode_move() that allows the objset to be freed @@ -1179,7 +1181,6 @@ 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; @@ -1223,7 +1224,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_proc); + doca->doca_cred); if (error != 0) { dsl_dir_rele(pdd, FTAG); return (error); @@ -1350,9 +1351,11 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags, dmu_objset_create_arg_t doca; dsl_crypto_params_t tmp_dcp = { 0 }; + cred_t *cr = CRED(); + crhold(cr); + doca.doca_name = name; - doca.doca_cred = CRED(); - doca.doca_proc = curproc; + doca.doca_cred = cr; doca.doca_flags = flags; doca.doca_userfunc = func; doca.doca_userarg = arg; @@ -1374,6 +1377,9 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags, if (rv == 0) zvol_create_minor(name); + + crfree(cr); + return (rv); } @@ -1381,7 +1387,6 @@ 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; static int @@ -1409,7 +1414,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_proc); + doca->doca_cred); if (error != 0) { dsl_dir_rele(pdd, FTAG); return (SET_ERROR(EDQUOT)); @@ -1465,10 +1470,12 @@ dmu_objset_clone(const char *clone, const char *origin) { dmu_objset_clone_arg_t doca; + cred_t *cr = CRED(); + crhold(cr); + doca.doca_clone = clone; doca.doca_origin = origin; - doca.doca_cred = CRED(); - doca.doca_proc = curproc; + doca.doca_cred = cr; int rv = dsl_sync_task(clone, dmu_objset_clone_check, dmu_objset_clone_sync, &doca, @@ -1477,6 +1484,8 @@ dmu_objset_clone(const char *clone, const char *origin) if (rv == 0) zvol_create_minor(clone); + crfree(cr); + return (rv); } diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c index a636ae73b..6d27dabc2 100644 --- a/module/zfs/dmu_recv.c +++ b/module/zfs/dmu_recv.c @@ -30,6 +30,7 @@ * Copyright (c) 2019, Allan Jude * Copyright (c) 2019 Datto Inc. * Copyright (c) 2022 Axcient. + * Copyright (c) 2025, Rob Norris */ #include @@ -68,6 +69,7 @@ #include #endif #include +#include static uint_t zfs_recv_queue_length = SPA_MAXBLOCKSIZE; static uint_t zfs_recv_queue_ff = 20; @@ -145,7 +147,6 @@ 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; @@ -411,7 +412,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, drba->drba_proc); + NULL, drba->drba_cred); if (error != 0) return (error); @@ -750,16 +751,14 @@ 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, drba->drba_proc); + ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred); 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, drba->drba_proc); + ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred); if (error != 0) { dsl_dataset_rele(ds, FTAG); return (error); @@ -1265,6 +1264,9 @@ dmu_recv_begin(const char *tofs, const char *tosnap, dmu_recv_begin_arg_t drba = { 0 }; int err = 0; + cred_t *cr = CRED(); + crhold(cr); + memset(drc, 0, sizeof (dmu_recv_cookie_t)); drc->drc_drr_begin = drr_begin; drc->drc_drrb = &drr_begin->drr_u.drr_begin; @@ -1273,8 +1275,7 @@ dmu_recv_begin(const char *tofs, const char *tosnap, drc->drc_force = force; drc->drc_heal = heal; drc->drc_resumable = resumable; - drc->drc_cred = CRED(); - drc->drc_proc = curproc; + drc->drc_cred = cr; drc->drc_clone = (origin != NULL); if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { @@ -1286,6 +1287,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap, (void) fletcher_4_incremental_native(drr_begin, sizeof (dmu_replay_record_t), &drc->drc_cksum); } else { + crfree(cr); + drc->drc_cred = NULL; return (SET_ERROR(EINVAL)); } @@ -1302,9 +1305,11 @@ dmu_recv_begin(const char *tofs, const char *tosnap, * upper limit. Systems with less than 1GB of RAM will see a lower * limit from `arc_all_memory() / 4`. */ - if (payloadlen > (MIN((1U << 28), arc_all_memory() / 4))) - return (E2BIG); - + if (payloadlen > (MIN((1U << 28), arc_all_memory() / 4))) { + crfree(cr); + drc->drc_cred = NULL; + return (SET_ERROR(E2BIG)); + } if (payloadlen != 0) { void *payload = vmem_alloc(payloadlen, KM_SLEEP); @@ -1320,6 +1325,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap, payload); if (err != 0) { vmem_free(payload, payloadlen); + crfree(cr); + drc->drc_cred = NULL; return (err); } err = nvlist_unpack(payload, payloadlen, &drc->drc_begin_nvl, @@ -1328,6 +1335,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap, if (err != 0) { kmem_free(drc->drc_next_rrd, sizeof (*drc->drc_next_rrd)); + crfree(cr); + drc->drc_cred = NULL; return (err); } } @@ -1337,8 +1346,7 @@ dmu_recv_begin(const char *tofs, const char *tosnap, drba.drba_origin = origin; drba.drba_cookie = drc; - drba.drba_cred = CRED(); - drba.drba_proc = curproc; + drba.drba_cred = drc->drc_cred; if (drc->drc_featureflags & DMU_BACKUP_FEATURE_RESUMING) { err = dsl_sync_task(tofs, @@ -1373,6 +1381,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap, if (err != 0) { kmem_free(drc->drc_next_rrd, sizeof (*drc->drc_next_rrd)); nvlist_free(drc->drc_begin_nvl); + crfree(cr); + drc->drc_cred = NULL; } return (err); } @@ -3527,6 +3537,8 @@ out: */ dmu_recv_cleanup_ds(drc); nvlist_free(drc->drc_keynvl); + crfree(drc->drc_cred); + drc->drc_cred = NULL; } objlist_destroy(drc->drc_ignore_objlist); @@ -3601,8 +3613,7 @@ 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_proc); + drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); dsl_dataset_rele(origin_head, FTAG); if (error != 0) return (error); @@ -3610,8 +3621,7 @@ 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_proc); + drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); } return (error); } @@ -3823,6 +3833,10 @@ dmu_recv_end(dmu_recv_cookie_t *drc, void *owner) zvol_create_minor(snapname); kmem_strfree(snapname); } + + crfree(drc->drc_cred); + drc->drc_cred = NULL; + return (error); } diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 6f467fc0d..e4113c604 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -32,6 +32,7 @@ * Copyright (c) 2019, Klara Inc. * Copyright (c) 2019, Allan Jude * Copyright (c) 2020 The FreeBSD Foundation [1] + * Copyright (c) 2025, Rob Norris * * [1] Portions of this software were developed by Allan Jude * under sponsorship from the FreeBSD Foundation. @@ -1518,7 +1519,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, proc_t *proc) + dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr) { int error; uint64_t value; @@ -1563,7 +1564,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, proc); + ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr); if (error != 0) return (error); } @@ -1664,7 +1665,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_proc); + ddsa->ddsa_cr); dsl_dataset_rele(ds, FTAG); } @@ -1702,7 +1703,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, NULL); + atp + 1, tx, B_FALSE, 0, NULL); dsl_dataset_rele(ds, FTAG); } @@ -1976,11 +1977,13 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors) } } + cred_t *cr = CRED(); + crhold(cr); + ddsa.ddsa_snaps = snaps; ddsa.ddsa_props = props; ddsa.ddsa_errors = errors; - ddsa.ddsa_cr = CRED(); - ddsa.ddsa_proc = curproc; + ddsa.ddsa_cr = cr; if (error == 0) { error = dsl_sync_task(firstname, dsl_dataset_snapshot_check, @@ -1988,6 +1991,8 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors) fnvlist_num_pairs(snaps) * 3, ZFS_SPACE_CHECK_NORMAL); } + crfree(cr); + if (suspended != NULL) { for (pair = nvlist_next_nvpair(suspended, NULL); pair != NULL; pair = nvlist_next_nvpair(suspended, pair)) { @@ -2028,7 +2033,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, NULL); + tx, B_FALSE, 0, NULL); if (error != 0) { dsl_dataset_rele(ds, FTAG); return (error); @@ -3496,7 +3501,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, ddpa->proc); + 0, ss_mv_cnt, ddpa->used, ddpa->cr); if (err != 0) goto out; @@ -3932,15 +3937,19 @@ dsl_dataset_promote(const char *name, char *conflsnap) if (error != 0) return (error); + cred_t *cr = CRED(); + crhold(cr); + ddpa.ddpa_clonename = name; ddpa.err_ds = fnvlist_alloc(); - ddpa.cr = CRED(); - ddpa.proc = curproc; + ddpa.cr = cr; error = dsl_sync_task(name, dsl_dataset_promote_check, dsl_dataset_promote_sync, &ddpa, 2 + numsnaps, ZFS_SPACE_CHECK_RESERVED); + crfree(cr); + /* * Return the first conflicting snapshot found. */ diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index a23486008..8c59fbf60 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -28,6 +28,7 @@ * Copyright (c) 2016 Actifio, Inc. All rights reserved. * Copyright (c) 2018, loli10K . All rights reserved. * Copyright (c) 2023 Hewlett Packard Enterprise Development LP. + * Copyright (c) 2025, Rob Norris */ #include @@ -759,7 +760,7 @@ typedef enum { static enforce_res_t dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, - cred_t *cr, proc_t *proc) + cred_t *cr) { enforce_res_t enforce = ENFORCE_ALWAYS; uint64_t obj; @@ -774,16 +775,8 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, if (crgetzoneid(cr) != GLOBAL_ZONEID) return (ENFORCE_ALWAYS); - /* - * 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) + if (secpolicy_zfs(cr) == 0) return (ENFORCE_NEVER); -#else - (void) proc; #endif if ((obj = dsl_dir_phys(dd)->dd_head_dataset_obj) == 0) @@ -817,7 +810,7 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, */ int dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop, - dsl_dir_t *ancestor, cred_t *cr, proc_t *proc) + dsl_dir_t *ancestor, cred_t *cr) { objset_t *os = dd->dd_pool->dp_meta_objset; uint64_t limit, count; @@ -849,7 +842,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, proc); + enforce = dsl_enforce_ds_ss_limits(dd, prop, cr); if (enforce == ENFORCE_NEVER) return (0); @@ -893,7 +886,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, proc); + ancestor, cr); return (err); } @@ -1916,7 +1909,6 @@ 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 { @@ -2095,8 +2087,7 @@ 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, ddra->ddra_proc); + newparent, fs_cnt, ss_cnt, myspace, ddra->ddra_cred); if (error != 0) { dsl_dir_rele(newparent, FTAG); dsl_dir_rele(dd, FTAG); @@ -2213,22 +2204,27 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx) int dsl_dir_rename(const char *oldname, const char *newname) { + cred_t *cr = CRED(); + crhold(cr); + dsl_dir_rename_arg_t ddra; ddra.ddra_oldname = oldname; ddra.ddra_newname = newname; - ddra.ddra_cred = CRED(); - ddra.ddra_proc = curproc; + ddra.ddra_cred = cr; - return (dsl_sync_task(oldname, + int err = dsl_sync_task(oldname, dsl_dir_rename_check, dsl_dir_rename_sync, &ddra, - 3, ZFS_SPACE_CHECK_RESERVED)); + 3, ZFS_SPACE_CHECK_RESERVED); + + crfree(cr); + return (err); } 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, proc_t *proc) + cred_t *cr) { dsl_dir_t *ancestor; int64_t adelta; @@ -2242,11 +2238,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, proc); + ancestor, cr); if (err != 0) return (err); err = dsl_fs_ss_limit_check(tdd, ss_cnt, ZFS_PROP_SNAPSHOT_LIMIT, - ancestor, cr, proc); + ancestor, cr); if (err != 0) return (err); diff --git a/module/zfs/zcp.c b/module/zfs/zcp.c index 4cc3be6dd..c0f395d3c 100644 --- a/module/zfs/zcp.c +++ b/module/zfs/zcp.c @@ -1141,12 +1141,14 @@ zcp_eval(const char *poolname, const char *program, boolean_t sync, } VERIFY3U(3, ==, lua_gettop(state)); + cred_t *cr = CRED(); + crhold(cr); + runinfo.zri_state = state; runinfo.zri_allocargs = &allocargs; runinfo.zri_outnvl = outnvl; runinfo.zri_result = 0; - runinfo.zri_cred = CRED(); - runinfo.zri_proc = curproc; + runinfo.zri_cred = cr; runinfo.zri_timed_out = B_FALSE; runinfo.zri_canceled = B_FALSE; runinfo.zri_sync = sync; @@ -1165,6 +1167,8 @@ zcp_eval(const char *poolname, const char *program, boolean_t sync, } lua_close(state); + crfree(cr); + /* * Create device minor nodes for any new zvols. */ diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c index b9a42ffba..28f734abf 100644 --- a/module/zfs/zcp_synctask.c +++ b/module/zfs/zcp_synctask.c @@ -193,7 +193,6 @@ 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 @@ -277,7 +276,6 @@ 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);