mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2026-01-09 10:42:12 +01:00
1220 lines
39 KiB
Diff
1220 lines
39 KiB
Diff
Patch-Source:
|
|
https://github.com/openzfs/zfs/pull/17229,
|
|
https://github.com/openzfs/zfs/commit/c8fa39b46c133cd094aebb46064da0592b9a553b,
|
|
https://github.com/openzfs/zfs/commit/906ced88df211bdeef9287f72a87661b0192e440
|
|
---
|
|
From 04443007440c71e0d97f905e43fee474d7a04566 Mon Sep 17 00:00:00 2001
|
|
From: Rob Norris <robn@despairlabs.com>
|
|
Date: Fri, 4 Apr 2025 16:59:15 +1100
|
|
Subject: [PATCH 1/2] Linux 6.15: mkdir now returns struct dentry *
|
|
|
|
The intent is that the filesystem may have a reference to an "old"
|
|
version of the new directory, eg if it was keeping it alive because a
|
|
remote NFS client still had it open.
|
|
|
|
We don't need anything like that, so this really just changes things so
|
|
we return error codes encoded in pointers.
|
|
|
|
Sponsored-by: https://despairlabs.com/sponsor/
|
|
Signed-off-by: Rob Norris <robn@despairlabs.com>
|
|
---
|
|
config/kernel-mkdir.m4 | 57 +++++++++++++++++++++++---------
|
|
module/os/linux/zfs/zpl_ctldir.c | 12 ++++++-
|
|
module/os/linux/zfs/zpl_inode.c | 21 +++++++++---
|
|
3 files changed, 70 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4
|
|
index 8e084443c7b4..c1aebc387abe 100644
|
|
--- a/config/kernel-mkdir.m4
|
|
+++ b/config/kernel-mkdir.m4
|
|
@@ -2,6 +2,22 @@ dnl #
|
|
dnl # Supported mkdir() interfaces checked newest to oldest.
|
|
dnl #
|
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [
|
|
+ dnl #
|
|
+ dnl # 6.15 API change
|
|
+ dnl # mkdir() returns struct dentry *
|
|
+ dnl #
|
|
+ ZFS_LINUX_TEST_SRC([mkdir_return_dentry], [
|
|
+ #include <linux/fs.h>
|
|
+
|
|
+ static struct dentry *mkdir(struct mnt_idmap *idmap,
|
|
+ struct inode *inode, struct dentry *dentry,
|
|
+ umode_t umode) { return dentry; }
|
|
+ static const struct inode_operations
|
|
+ iops __attribute__ ((unused)) = {
|
|
+ .mkdir = mkdir,
|
|
+ };
|
|
+ ],[])
|
|
+
|
|
dnl #
|
|
dnl # 6.3 API change
|
|
dnl # mkdir() takes struct mnt_idmap * as the first arg
|
|
@@ -59,29 +75,40 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [
|
|
|
|
AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [
|
|
dnl #
|
|
- dnl # 6.3 API change
|
|
- dnl # mkdir() takes struct mnt_idmap * as the first arg
|
|
+ dnl # 6.15 API change
|
|
+ dnl # mkdir() returns struct dentry *
|
|
dnl #
|
|
- AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*])
|
|
- ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [
|
|
+ AC_MSG_CHECKING([whether iops->mkdir() returns struct dentry*])
|
|
+ ZFS_LINUX_TEST_RESULT([mkdir_return_dentry], [
|
|
AC_MSG_RESULT(yes)
|
|
- AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1,
|
|
- [iops->mkdir() takes struct mnt_idmap*])
|
|
+ AC_DEFINE(HAVE_IOPS_MKDIR_DENTRY, 1,
|
|
+ [iops->mkdir() returns struct dentry*])
|
|
],[
|
|
- AC_MSG_RESULT(no)
|
|
-
|
|
dnl #
|
|
- dnl # 5.12 API change
|
|
- dnl # The struct user_namespace arg was added as the first argument to
|
|
- dnl # mkdir() of the iops structure.
|
|
+ dnl # 6.3 API change
|
|
+ dnl # mkdir() takes struct mnt_idmap * as the first arg
|
|
dnl #
|
|
- AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*])
|
|
- ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [
|
|
+ AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*])
|
|
+ ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [
|
|
AC_MSG_RESULT(yes)
|
|
- AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
|
|
- [iops->mkdir() takes struct user_namespace*])
|
|
+ AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1,
|
|
+ [iops->mkdir() takes struct mnt_idmap*])
|
|
],[
|
|
AC_MSG_RESULT(no)
|
|
+
|
|
+ dnl #
|
|
+ dnl # 5.12 API change
|
|
+ dnl # The struct user_namespace arg was added as the first argument to
|
|
+ dnl # mkdir() of the iops structure.
|
|
+ dnl #
|
|
+ AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*])
|
|
+ ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [
|
|
+ AC_MSG_RESULT(yes)
|
|
+ AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
|
|
+ [iops->mkdir() takes struct user_namespace*])
|
|
+ ],[
|
|
+ AC_MSG_RESULT(no)
|
|
+ ])
|
|
])
|
|
])
|
|
])
|
|
diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c
|
|
index 0b04ec6866f4..48dae79a2373 100644
|
|
--- a/module/os/linux/zfs/zpl_ctldir.c
|
|
+++ b/module/os/linux/zfs/zpl_ctldir.c
|
|
@@ -341,14 +341,20 @@ zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry)
|
|
return (error);
|
|
}
|
|
|
|
+#if defined(HAVE_IOPS_MKDIR_USERNS)
|
|
static int
|
|
-#ifdef HAVE_IOPS_MKDIR_USERNS
|
|
zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip,
|
|
struct dentry *dentry, umode_t mode)
|
|
#elif defined(HAVE_IOPS_MKDIR_IDMAP)
|
|
+static int
|
|
+zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
|
|
+ struct dentry *dentry, umode_t mode)
|
|
+#elif defined(HAVE_IOPS_MKDIR_DENTRY)
|
|
+static struct dentry *
|
|
zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
|
|
struct dentry *dentry, umode_t mode)
|
|
#else
|
|
+static int
|
|
zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
|
|
#endif
|
|
{
|
|
@@ -376,7 +382,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
|
|
ASSERT3S(error, <=, 0);
|
|
crfree(cr);
|
|
|
|
+#if defined(HAVE_IOPS_MKDIR_DENTRY)
|
|
+ return (ERR_PTR(error));
|
|
+#else
|
|
return (error);
|
|
+#endif
|
|
}
|
|
|
|
/*
|
|
diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c
|
|
index 85df9b9acf28..f9f6406f8b47 100644
|
|
--- a/module/os/linux/zfs/zpl_inode.c
|
|
+++ b/module/os/linux/zfs/zpl_inode.c
|
|
@@ -374,14 +374,20 @@ zpl_unlink(struct inode *dir, struct dentry *dentry)
|
|
return (error);
|
|
}
|
|
|
|
+#if defined(HAVE_IOPS_MKDIR_USERNS)
|
|
static int
|
|
-#ifdef HAVE_IOPS_MKDIR_USERNS
|
|
zpl_mkdir(struct user_namespace *user_ns, struct inode *dir,
|
|
struct dentry *dentry, umode_t mode)
|
|
#elif defined(HAVE_IOPS_MKDIR_IDMAP)
|
|
+static int
|
|
+zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir,
|
|
+ struct dentry *dentry, umode_t mode)
|
|
+#elif defined(HAVE_IOPS_MKDIR_DENTRY)
|
|
+static struct dentry *
|
|
zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir,
|
|
struct dentry *dentry, umode_t mode)
|
|
#else
|
|
+static int
|
|
zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
#endif
|
|
{
|
|
@@ -390,12 +396,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
znode_t *zp;
|
|
int error;
|
|
fstrans_cookie_t cookie;
|
|
-#if !(defined(HAVE_IOPS_MKDIR_USERNS) || defined(HAVE_IOPS_MKDIR_IDMAP))
|
|
+#if !(defined(HAVE_IOPS_MKDIR_USERNS) || \
|
|
+ defined(HAVE_IOPS_MKDIR_IDMAP) || defined(HAVE_IOPS_MKDIR_DENTRY))
|
|
zidmap_t *user_ns = kcred->user_ns;
|
|
#endif
|
|
|
|
if (is_nametoolong(dentry)) {
|
|
- return (-ENAMETOOLONG);
|
|
+ error = -ENAMETOOLONG;
|
|
+ goto err;
|
|
}
|
|
|
|
crhold(cr);
|
|
@@ -422,9 +430,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
spl_fstrans_unmark(cookie);
|
|
kmem_free(vap, sizeof (vattr_t));
|
|
crfree(cr);
|
|
- ASSERT3S(error, <=, 0);
|
|
|
|
+err:
|
|
+ ASSERT3S(error, <=, 0);
|
|
+#if defined(HAVE_IOPS_MKDIR_DENTRY)
|
|
+ return (error != 0 ? ERR_PTR(error) : NULL);
|
|
+#else
|
|
return (error);
|
|
+#endif
|
|
}
|
|
|
|
static int
|
|
---
|
|
From 1604c3d882faa49252b41384c461a745f041f9ce Mon Sep 17 00:00:00 2001
|
|
From: Rob Norris <robn@despairlabs.com>
|
|
Date: Tue, 8 Apr 2025 20:47:43 +1000
|
|
Subject: [PATCH 2/2] Linux 6.2/6.15: del_timer_sync() renamed to
|
|
timer_delete_sync()
|
|
|
|
Renamed in 6.2, and the compat wrapper removed in 6.15. No signature or
|
|
functional change apart from that, so a very minimal update for us.
|
|
|
|
Sponsored-by: https://despairlabs.com/sponsor/
|
|
Signed-off-by: Rob Norris <robn@despairlabs.com>
|
|
---
|
|
config/kernel-timer.m4 | 32 ++++++++++++++++++++++++++++++++
|
|
config/kernel.m4 | 2 ++
|
|
module/os/linux/spl/spl-taskq.c | 7 ++++++-
|
|
3 files changed, 40 insertions(+), 1 deletion(-)
|
|
create mode 100644 config/kernel-timer.m4
|
|
|
|
diff --git a/config/kernel-timer.m4 b/config/kernel-timer.m4
|
|
new file mode 100644
|
|
index 000000000000..c89ea204e83d
|
|
--- /dev/null
|
|
+++ b/config/kernel-timer.m4
|
|
@@ -0,0 +1,32 @@
|
|
+dnl #
|
|
+dnl # 6.2: timer_delete_sync introduced, del_timer_sync deprecated and made
|
|
+dnl # into a simple wrapper
|
|
+dnl # 6.15: del_timer_sync removed
|
|
+dnl #
|
|
+AC_DEFUN([ZFS_AC_KERNEL_SRC_TIMER_DELETE_SYNC], [
|
|
+ ZFS_LINUX_TEST_SRC([timer_delete_sync], [
|
|
+ #include <linux/timer.h>
|
|
+ ],[
|
|
+ struct timer_list *timer __attribute__((unused)) = NULL;
|
|
+ timer_delete_sync(timer);
|
|
+ ])
|
|
+])
|
|
+
|
|
+AC_DEFUN([ZFS_AC_KERNEL_TIMER_DELETE_SYNC], [
|
|
+ AC_MSG_CHECKING([whether timer_delete_sync() is available])
|
|
+ ZFS_LINUX_TEST_RESULT([timer_delete_sync], [
|
|
+ AC_MSG_RESULT(yes)
|
|
+ AC_DEFINE(HAVE_TIMER_DELETE_SYNC, 1,
|
|
+ [timer_delete_sync is available])
|
|
+ ],[
|
|
+ AC_MSG_RESULT(no)
|
|
+ ])
|
|
+])
|
|
+
|
|
+AC_DEFUN([ZFS_AC_KERNEL_SRC_TIMER], [
|
|
+ ZFS_AC_KERNEL_SRC_TIMER_DELETE_SYNC
|
|
+])
|
|
+
|
|
+AC_DEFUN([ZFS_AC_KERNEL_TIMER], [
|
|
+ ZFS_AC_KERNEL_TIMER_DELETE_SYNC
|
|
+])
|
|
diff --git a/config/kernel.m4 b/config/kernel.m4
|
|
index 29bf588688f8..b933475e9e70 100644
|
|
--- a/config/kernel.m4
|
|
+++ b/config/kernel.m4
|
|
@@ -130,6 +130,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|
ZFS_AC_KERNEL_SRC_MM_PAGE_MAPPING
|
|
ZFS_AC_KERNEL_SRC_FILE
|
|
ZFS_AC_KERNEL_SRC_PIN_USER_PAGES
|
|
+ ZFS_AC_KERNEL_SRC_TIMER
|
|
case "$host_cpu" in
|
|
powerpc*)
|
|
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
|
@@ -244,6 +245,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|
ZFS_AC_KERNEL_1ARG_ASSIGN_STR
|
|
ZFS_AC_KERNEL_FILE
|
|
ZFS_AC_KERNEL_PIN_USER_PAGES
|
|
+ ZFS_AC_KERNEL_TIMER
|
|
case "$host_cpu" in
|
|
powerpc*)
|
|
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
|
diff --git a/module/os/linux/spl/spl-taskq.c b/module/os/linux/spl/spl-taskq.c
|
|
index d5b42fdfaf20..700ec1c7fc04 100644
|
|
--- a/module/os/linux/spl/spl-taskq.c
|
|
+++ b/module/os/linux/spl/spl-taskq.c
|
|
@@ -38,6 +38,11 @@
|
|
#include <sys/kstat.h>
|
|
#include <linux/cpuhotplug.h>
|
|
|
|
+/* Linux 6.2 renamed timer_delete_sync(); point it at its old name for those. */
|
|
+#ifndef HAVE_TIMER_DELETE_SYNC
|
|
+#define timer_delete_sync(t) del_timer_sync(t)
|
|
+#endif
|
|
+
|
|
typedef struct taskq_kstats {
|
|
/* static values, for completeness */
|
|
kstat_named_t tqks_threads_max;
|
|
@@ -633,7 +638,7 @@ taskq_cancel_id(taskq_t *tq, taskqid_t id)
|
|
*/
|
|
if (timer_pending(&t->tqent_timer)) {
|
|
spin_unlock_irqrestore(&tq->tq_lock, flags);
|
|
- del_timer_sync(&t->tqent_timer);
|
|
+ timer_delete_sync(&t->tqent_timer);
|
|
spin_lock_irqsave_nested(&tq->tq_lock, flags,
|
|
tq->tq_lock_class);
|
|
}
|
|
---
|
|
From c8fa39b46c133cd094aebb46064da0592b9a553b Mon Sep 17 00:00:00 2001
|
|
From: Rob Norris <robn@despairlabs.com>
|
|
Date: Wed, 30 Apr 2025 09:27:48 +1000
|
|
Subject: [PATCH] cred: properly pass and test creds on other threads (#17273)
|
|
|
|
### Background
|
|
|
|
Various admin operations will be invoked by some userspace task, but the
|
|
work will be done on a separate kernel thread at a later time. Snapshots
|
|
are an example, which are triggered through zfs_ioc_snapshot() ->
|
|
dsl_dataset_snapshot(), but the actual work is from a task dispatched to
|
|
dp_sync_taskq.
|
|
|
|
Many such tasks end up in dsl_enforce_ds_ss_limits(), where various
|
|
limits and permissions are enforced. Among other things, it is necessary
|
|
to ensure that the invoking task (that is, the user) has permission to
|
|
do things. We can't simply check if the running task has permission; it
|
|
is a privileged kernel thread, which can do anything.
|
|
|
|
However, in the general case it's not safe to simply query the task for
|
|
its permissions at the check time, as the task may not exist any more,
|
|
or its permissions may have changed since it was first invoked. So
|
|
instead, we capture the permissions by saving CRED() in the user task,
|
|
and then using it for the check through the secpolicy_* functions.
|
|
|
|
### Current implementation
|
|
|
|
The current code calls CRED() to get the credential, which gets a
|
|
pointer to the cred_t inside the current task and passes it to the
|
|
worker task. However, it doesn't take a reference to the cred_t, and so
|
|
expects that it won't change, and that the task continues to exist. In
|
|
practice that is always the case, because we don't let the calling task
|
|
return from the kernel until the work is done.
|
|
|
|
For Linux, we also take a reference to the current task, because the
|
|
Linux credential APIs for the most part do not check an arbitrary
|
|
credential, but rather, query what a task can do. See
|
|
secpolicy_zfs_proc(). Again, we don't take a reference on the task, just
|
|
a pointer to it.
|
|
|
|
### Changes
|
|
|
|
We change to calling crhold() on the task credential, and crfree() when
|
|
we're done with it. This ensures it stays alive and unchanged for the
|
|
duration of the call.
|
|
|
|
On the Linux side, we change the main policy checking function
|
|
priv_policy_ns() to use override_creds()/revert_creds() if necessary to
|
|
make the provided credential active in the current task, allowing the
|
|
standard task-permission APIs to do the needed check. Since the task
|
|
pointer is no longer required, this lets us entirely remove
|
|
secpolicy_zfs_proc() and the need to carry a task pointer around as
|
|
well.
|
|
|
|
Sponsored-by: https://despairlabs.com/sponsor/
|
|
|
|
Signed-off-by: Rob Norris <robn@despairlabs.com>
|
|
Reviewed-by: Pavel Snajdr <snajpa@snajpa.net>
|
|
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
|
|
Reviewed-by: Kyle Evans <kevans@FreeBSD.org>
|
|
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
|
|
---
|
|
include/os/freebsd/spl/sys/policy.h | 1 -
|
|
include/os/linux/zfs/sys/policy.h | 1 -
|
|
include/sys/dmu_recv.h | 1 -
|
|
include/sys/dsl_dataset.h | 4 +--
|
|
include/sys/dsl_dir.h | 4 +--
|
|
include/sys/zcp.h | 1 -
|
|
include/sys/zfs_context.h | 4 ++-
|
|
lib/libzpool/kernel.c | 7 -----
|
|
module/os/freebsd/spl/spl_policy.c | 7 -----
|
|
module/os/linux/zfs/policy.c | 44 +++++++++++---------------
|
|
module/zfs/dmu_objset.c | 25 ++++++++++-----
|
|
module/zfs/dmu_recv.c | 48 +++++++++++++++++++----------
|
|
module/zfs/dsl_dataset.c | 29 +++++++++++------
|
|
module/zfs/dsl_dir.c | 42 ++++++++++++-------------
|
|
module/zfs/zcp.c | 8 +++--
|
|
module/zfs/zcp_synctask.c | 2 --
|
|
16 files changed, 116 insertions(+), 112 deletions(-)
|
|
|
|
diff --git a/include/os/freebsd/spl/sys/policy.h b/include/os/freebsd/spl/sys/policy.h
|
|
index 639ade831c28..48bc4f3d5b0f 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 77d0cdef5d2f..8fa6ab01d1ad 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 cd292d9244b0..ffb2b602d73f 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 624f3ddde9f0..681294593001 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 6135835fca48..d2e9e2282975 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 96279deaee75..5fcfb6219870 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 549f54c09383..b3d48e257538 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 653380149a9e..e397fc851cc1 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 aad3ef2fad5d..7fc93648c71e 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 c50ffcfe6992..4396a5d9e076 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 <robn@despairlabs.com>
|
|
*
|
|
* 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 <linux/security.h>
|
|
#include <linux/vfs_compat.h>
|
|
|
|
-/*
|
|
- * 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 f22a236a6317..6ab4304fae89 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 <robn@despairlabs.com>
|
|
*/
|
|
|
|
/* Portions Copyright 2010 Robert Milkowski */
|
|
@@ -68,6 +69,7 @@
|
|
#include <sys/vdev_impl.h>
|
|
#include <sys/arc.h>
|
|
#include <cityhash.h>
|
|
+#include <sys/cred.h>
|
|
|
|
/*
|
|
* 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 a636ae73bbd7..6d27dabc2e56 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 <robn@despairlabs.com>
|
|
*/
|
|
|
|
#include <sys/arc.h>
|
|
@@ -68,6 +69,7 @@
|
|
#include <sys/zfs_vfsops.h>
|
|
#endif
|
|
#include <sys/zfs_file.h>
|
|
+#include <sys/cred.h>
|
|
|
|
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 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, offset_t *voffp)
|
|
*/
|
|
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 6f467fc0d3c2..e4113c604a41 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 <robn@despairlabs.com>
|
|
*
|
|
* [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 a2348600866b..8c59fbf60c83 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 <ezomori.nozomu@gmail.com>. All rights reserved.
|
|
* Copyright (c) 2023 Hewlett Packard Enterprise Development LP.
|
|
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
|
|
*/
|
|
|
|
#include <sys/dmu.h>
|
|
@@ -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 4cc3be6ddffc..c0f395d3c90f 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 b9a42ffba85c..28f734abfea7 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);
|
|
|
|
---
|
|
From 906ced88df211bdeef9287f72a87661b0192e440 Mon Sep 17 00:00:00 2001
|
|
From: Tony Hutter <hutter2@llnl.gov>
|
|
Date: Wed, 28 May 2025 16:28:02 -0700
|
|
Subject: [PATCH] Linux 6.15 compat: META
|
|
|
|
Update the META file to reflect compatibility with the 6.15
|
|
kernel.
|
|
|
|
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
Signed-off-by: Tony Hutter <hutter2@llnl.gov>
|
|
Closes #17393
|
|
---
|
|
META | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/META b/META
|
|
index 6249d5ec2458..47f0795bfa11 100644
|
|
--- a/META
|
|
+++ b/META
|
|
@@ -6,5 +6,5 @@ Release: 1
|
|
Release-Tags: relext
|
|
License: CDDL
|
|
Author: OpenZFS
|
|
-Linux-Maximum: 6.14
|
|
+Linux-Maximum: 6.15
|
|
Linux-Minimum: 4.18
|