From ab637174f4c6608932eba447e7ceacebdcdb7ba5 Mon Sep 17 00:00:00 2001 From: Gionatan Danti Date: Sun, 26 Jan 2025 21:16:33 +0100 Subject: [PATCH] require rollback permission when force receive Force receive (zfs receive -F) can rollback or destroy snapshots and file systems that do not exist on the sending side (see zfs-receive man page). This means an user having the receive permission can effectively delete data on receiving side, even if such user does not have explicit rollback or destroy permissions. This patch add the rollback permission requirement for force receive. To avoid changing current default behavior, a new tunable zfs_recv_force_needs_perm is introduced. When set to 0 (default) the new permission check is disabled. When set to 1 rollback permission requirement is enabled. Fixes https://github.com/openzfs/zfs/issues/16943 Signed-off-by: Gionatan Danti --- man/man4/zfs.4 | 3 +++ man/man8/zfs-allow.8 | 2 +- module/zfs/zfs_ioctl.c | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index dd0b3d848fe9..81390c3c703d 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -2188,6 +2188,9 @@ If there is an error during healing, the healing receive is not terminated instead it moves on to the next record. .El . +.It Sy zfs_recv_force_needs_perm Ns = Ns Sy 0 Pq int +When not zero, force receive (zfs recv -F) requires rollback permission. +. .It Sy zfs_override_estimate_recordsize Ns = Ns Sy 0 Ns | Ns 1 Pq uint Setting this variable overrides the default logic for estimating block sizes when doing a diff --git a/man/man8/zfs-allow.8 b/man/man8/zfs-allow.8 index d26984317c2e..49e02680371c 100644 --- a/man/man8/zfs-allow.8 +++ b/man/man8/zfs-allow.8 @@ -207,7 +207,7 @@ load-key subcommand Allows loading and unloading of encryption key (see \fBzfs l change-key subcommand Allows changing an encryption key via \fBzfs change-key\fR. mount subcommand Allows mounting/umounting ZFS datasets promote subcommand Must also have the \fBmount\fR and \fBpromote\fR ability in the origin file system -receive subcommand Must also have the \fBmount\fR and \fBcreate\fR ability +receive subcommand Must also have the \fBmount\fR and \fBcreate\fR ability; must also have the \fBrollback\fR ability if \fBzfs receive -F\fR (force receive) is used and \fBzfs_recv_force_needs_perm\fR is set to 1. release subcommand Allows releasing a user hold which might destroy the snapshot rename subcommand Must also have the \fBmount\fR and \fBcreate\fR ability in the new parent rollback subcommand Must also have the \fBmount\fR ability diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index b1b0ae54460b..5af853d5e95a 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -238,6 +238,11 @@ uint64_t zfs_max_nvlist_src_size = 0; */ static uint64_t zfs_history_output_max = 1024 * 1024; +/* + * zfs_recv_force_needs_perm: if true, force receive (-F) requires rollback permission + */ +static int zfs_recv_force_needs_perm = 0; + uint_t zfs_allow_log_key; /* DATA_TYPE_ANY is used when zkey_type can vary. */ @@ -908,6 +913,12 @@ zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) ZFS_DELEG_PERM_MOUNT, cr)) != 0) return (error); + /* Forced receive can rollback or destroy snapshots */ + if (zfs_recv_force_needs_perm && zc->zc_guid && + (error = zfs_secpolicy_write_perms(zc->zc_name, + ZFS_DELEG_PERM_ROLLBACK, cr)) != 0) + return (error); + return (zfs_secpolicy_write_perms(zc->zc_name, ZFS_DELEG_PERM_CREATE, cr)); } @@ -8177,3 +8188,6 @@ ZFS_MODULE_PARAM(zfs, zfs_, max_nvlist_src_size, U64, ZMOD_RW, ZFS_MODULE_PARAM(zfs, zfs_, history_output_max, U64, ZMOD_RW, "Maximum size in bytes of ZFS ioctl output that will be logged"); + +ZFS_MODULE_PARAM(zfs, zfs_, recv_force_needs_perm, INT, ZMOD_RW, + "Force receive (-F) requires rollback permission");