Unverified Commit e6d28ebc authored by Jeff Layton's avatar Jeff Layton Committed by Christian Brauner
Browse files

filelock: push the S_ISREG check down to ->setlease handlers



When nfsd starts requesting directory delegations, setlease handlers may
see requests for leases on directories. Push the !S_ISREG check down
into the non-trivial setlease handlers, so we can selectively enable
them where they're supported.

FUSE is special: It's the only filesystem that supports atomic_open and
allows kernel-internal leases. atomic_open is issued when the VFS
doesn't know the state of the dentry being opened. If the file doesn't
exist, it may be created, in which case the dir lease should be broken.

The existing kernel-internal lease implementation has no provision for
this. Ensure that we don't allow directory leases by default going
forward by explicitly disabling them there.

Reviewed-by: default avatarNeilBrown <neil@brown.name>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-4-52f3feebb2f2@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 6976ed2d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2230,6 +2230,7 @@ static const struct file_operations fuse_dir_operations = {
	.fsync		= fuse_dir_fsync,
	.unlocked_ioctl	= fuse_dir_ioctl,
	.compat_ioctl	= fuse_dir_compat_ioctl,
	.setlease	= simple_nosetlease,
};

static const struct inode_operations fuse_common_inode_operations = {
+3 −2
Original line number Diff line number Diff line
@@ -1935,6 +1935,9 @@ static int generic_delete_lease(struct file *filp, void *owner)
int generic_setlease(struct file *filp, int arg, struct file_lease **flp,
			void **priv)
{
	if (!S_ISREG(file_inode(filp)->i_mode))
		return -EINVAL;

	switch (arg) {
	case F_UNLCK:
		return generic_delete_lease(filp, *priv);
@@ -2024,8 +2027,6 @@ vfs_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)

	if ((!vfsuid_eq_kuid(vfsuid, current_fsuid())) && !capable(CAP_LEASE))
		return -EACCES;
	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
	error = security_file_lock(filp, arg);
	if (error)
		return error;
+2 −0
Original line number Diff line number Diff line
@@ -431,6 +431,8 @@ void nfs42_ssc_unregister_ops(void)
static int nfs4_setlease(struct file *file, int arg, struct file_lease **lease,
			 void **priv)
{
	if (!S_ISREG(file_inode(file)->i_mode))
		return -EINVAL;
	return nfs4_proc_setlease(file, arg, lease, priv);
}

+3 −0
Original line number Diff line number Diff line
@@ -1149,6 +1149,9 @@ cifs_setlease(struct file *file, int arg, struct file_lease **lease, void **priv
	struct inode *inode = file_inode(file);
	struct cifsFileInfo *cfile = file->private_data;

	if (!S_ISREG(inode->i_mode))
		return -EINVAL;

	/* Check if file is oplocked if this is request for new lease */
	if (arg == F_UNLCK ||
	    ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||