linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] vfs: make immutable files actually immutable
@ 2019-03-28 17:50 Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 1/3] mm/fs: don't allow writes to immutable files Darrick J. Wong
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Darrick J. Wong @ 2019-03-28 17:50 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

Hi all,

The chattr(1) manpage has this to say about the immutable bit that
system administrators can set on files:

"A file with the 'i' attribute cannot be modified: it cannot be deleted
or renamed, no link can be created to this file, most of the file's
metadata can not be modified, and the file can not be opened in write
mode."

Given the clause about how the file 'cannot be modified', it is
surprising that programs holding writable file descriptors can continue
to write to and truncate files after the immutable flag has been set,
but they cannot call other things such as utimes, fallocate, unlink,
link, setxattr, or reflink.

Since the immutable flag is only settable by administrators, resolve
this inconsistent behavior in favor of the documented behavior -- once
the flag is set, the file cannot be modified, period.

This has been lightly tested with fstests.  Enjoy!
Comments and questions are, as always, welcome.

--D

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] mm/fs: don't allow writes to immutable files
  2019-03-28 17:50 [PATCH 0/3] vfs: make immutable files actually immutable Darrick J. Wong
@ 2019-03-28 17:50 ` Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 2/3] xfs: reset page mappings after setting immutable Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 3/3] xfs: don't allow most setxattr to immutable files Darrick J. Wong
  2 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2019-03-28 17:50 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

From: Darrick J. Wong <darrick.wong@oracle.com>

The chattr manpage has this to say about immutable files:

"A file with the 'i' attribute cannot be modified: it cannot be deleted
or renamed, no link can be created to this file, most of the file's
metadata can not be modified, and the file can not be opened in write
mode."

Once the flag is set, it is enforced for quite a few file operations,
such as fallocate, fpunch, fzero, rm, touch, open, etc.  However, we
don't check for immutability when doing a write(), a PROT_WRITE mmap(),
a truncate(), or a write to a previously established mmap.

If a program has an open write fd to a file that the administrator
subsequently marks immutable, the program still can change the file
contents.  Weird!

The ability to write to an immutable file does not follow the manpage
promise that immutable files cannot be modified.  Worse yet it's
inconsistent with the behavior of other syscalls which don't allow
modifications of immutable files.

Therefore, add the necessary checks to make the write, mmap, and
truncate behavior consistent with what the manpage says and consistent
with other syscalls on filesystems which support IMMUTABLE.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/attr.c    |   13 ++++++-------
 mm/filemap.c |    3 +++
 mm/memory.c  |    3 +++
 mm/mmap.c    |    3 +++
 4 files changed, 15 insertions(+), 7 deletions(-)


diff --git a/fs/attr.c b/fs/attr.c
index d22e8187477f..1fcfdcc5b367 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -233,19 +233,18 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
 
 	WARN_ON_ONCE(!inode_is_locked(inode));
 
-	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
-		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-			return -EPERM;
-	}
+	if (IS_IMMUTABLE(inode))
+		return -EPERM;
+
+	if ((ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) &&
+	    IS_APPEND(inode))
+		return -EPERM;
 
 	/*
 	 * If utimes(2) and friends are called with times == NULL (or both
 	 * times are UTIME_NOW), then we need to check for write permission
 	 */
 	if (ia_valid & ATTR_TOUCH) {
-		if (IS_IMMUTABLE(inode))
-			return -EPERM;
-
 		if (!inode_owner_or_capable(inode)) {
 			error = inode_permission(inode, MAY_WRITE);
 			if (error)
diff --git a/mm/filemap.c b/mm/filemap.c
index d78f577baef2..9fed698f4c63 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3033,6 +3033,9 @@ inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
 	loff_t count;
 	int ret;
 
+	if (IS_IMMUTABLE(inode))
+		return -EPERM;
+
 	if (!iov_iter_count(from))
 		return 0;
 
diff --git a/mm/memory.c b/mm/memory.c
index 47fe250307c7..c493db22413a 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2148,6 +2148,9 @@ static vm_fault_t do_page_mkwrite(struct vm_fault *vmf)
 
 	vmf->flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
 
+	if (vmf->vma->vm_file && IS_IMMUTABLE(file_inode(vmf->vma->vm_file)))
+		return VM_FAULT_SIGBUS;
+
 	ret = vmf->vma->vm_ops->page_mkwrite(vmf);
 	/* Restore original flags so that caller is not surprised */
 	vmf->flags = old_flags;
diff --git a/mm/mmap.c b/mm/mmap.c
index 41eb48d9b527..e49dcbeda461 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1394,6 +1394,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
 	if (!len)
 		return -EINVAL;
 
+	if (file && IS_IMMUTABLE(file_inode(file)))
+		return -EPERM;
+
 	/*
 	 * Does the application expect PROT_READ to imply PROT_EXEC?
 	 *


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] xfs: reset page mappings after setting immutable
  2019-03-28 17:50 [PATCH 0/3] vfs: make immutable files actually immutable Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 1/3] mm/fs: don't allow writes to immutable files Darrick J. Wong
@ 2019-03-28 17:50 ` Darrick J. Wong
  2019-03-28 21:21   ` Dave Chinner
  2019-03-28 17:50 ` [PATCH 3/3] xfs: don't allow most setxattr to immutable files Darrick J. Wong
  2 siblings, 1 reply; 9+ messages in thread
From: Darrick J. Wong @ 2019-03-28 17:50 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

From: Darrick J. Wong <darrick.wong@oracle.com>

The chattr manpage has this to say about immutable files:

"A file with the 'i' attribute cannot be modified: it cannot be deleted
or renamed, no link can be created to this file, most of the file's
metadata can not be modified, and the file can not be opened in write
mode."

This means that we need to flush the page cache when setting the
immutable flag so that programs cannot continue to write to writable
mappings.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_ioctl.c |   63 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 20 deletions(-)


diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 6ecdbb3af7de..2bd1c5ab5008 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -998,6 +998,37 @@ xfs_diflags_to_linux(
 #endif
 }
 
+static int
+xfs_ioctl_setattr_flush(
+	struct xfs_inode	*ip,
+	int			*join_flags)
+{
+	struct inode		*inode = VFS_I(ip);
+	int			error;
+
+	if (S_ISDIR(inode->i_mode))
+		return 0;
+	if ((*join_flags) & (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL))
+		return 0;
+
+	/* lock, flush and invalidate mapping in preparation for flag change */
+	xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
+	error = filemap_write_and_wait(inode->i_mapping);
+	if (error)
+		goto out_unlock;
+	error = invalidate_inode_pages2(inode->i_mapping);
+	if (error)
+		goto out_unlock;
+
+	*join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL;
+	return 0;
+
+out_unlock:
+	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
+	return error;
+
+}
+
 static int
 xfs_ioctl_setattr_xflags(
 	struct xfs_trans	*tp,
@@ -1067,7 +1098,6 @@ xfs_ioctl_setattr_dax_invalidate(
 {
 	struct inode		*inode = VFS_I(ip);
 	struct super_block	*sb = inode->i_sb;
-	int			error;
 
 	*join_flags = 0;
 
@@ -1092,25 +1122,7 @@ xfs_ioctl_setattr_dax_invalidate(
 	if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode))
 		return 0;
 
-	if (S_ISDIR(inode->i_mode))
-		return 0;
-
-	/* lock, flush and invalidate mapping in preparation for flag change */
-	xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
-	error = filemap_write_and_wait(inode->i_mapping);
-	if (error)
-		goto out_unlock;
-	error = invalidate_inode_pages2(inode->i_mapping);
-	if (error)
-		goto out_unlock;
-
-	*join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL;
-	return 0;
-
-out_unlock:
-	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
-	return error;
-
+	return xfs_ioctl_setattr_flush(ip, join_flags);
 }
 
 /*
@@ -1356,6 +1368,17 @@ xfs_ioctl_setattr(
 	if (code)
 		goto error_free_dquots;
 
+	/*
+	 * If we are trying to set immutable then flush everything to disk to
+	 * force all writable memory mappings back through the pagefault
+	 * handler.
+	 */
+	if (!IS_IMMUTABLE(VFS_I(ip)) && (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)) {
+		code = xfs_ioctl_setattr_flush(ip, &join_flags);
+		if (code)
+			goto error_free_dquots;
+	}
+
 	tp = xfs_ioctl_setattr_get_trans(ip, join_flags);
 	if (IS_ERR(tp)) {
 		code = PTR_ERR(tp);


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] xfs: don't allow most setxattr to immutable files
  2019-03-28 17:50 [PATCH 0/3] vfs: make immutable files actually immutable Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 1/3] mm/fs: don't allow writes to immutable files Darrick J. Wong
  2019-03-28 17:50 ` [PATCH 2/3] xfs: reset page mappings after setting immutable Darrick J. Wong
@ 2019-03-28 17:50 ` Darrick J. Wong
  2019-03-28 21:24   ` Amir Goldstein
  2019-03-28 21:29   ` Dave Chinner
  2 siblings, 2 replies; 9+ messages in thread
From: Darrick J. Wong @ 2019-03-28 17:50 UTC (permalink / raw)
  To: darrick.wong; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

From: Darrick J. Wong <darrick.wong@oracle.com>

The chattr manpage has this to say about immutable files:

"A file with the 'i' attribute cannot be modified: it cannot be deleted
or renamed, no link can be created to this file, most of the file's
metadata can not be modified, and the file can not be opened in write
mode."

However, we don't actually check the immutable flag in the setattr code,
which means that we can update project ids and extent size hints on
supposedly immutable files.  Therefore, reject a setattr call on an
immutable file except for the case where we're trying to unset
IMMUTABLE.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_ioctl.c |    8 ++++++++
 1 file changed, 8 insertions(+)


diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 2bd1c5ab5008..9cf0bc0ae2bd 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1067,6 +1067,14 @@ xfs_ioctl_setattr_xflags(
 	    !capable(CAP_LINUX_IMMUTABLE))
 		return -EPERM;
 
+	/*
+	 * If immutable is set and we are not clearing it, we're not allowed
+	 * to change anything else in the inode.
+	 */
+	if ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) &&
+	    (fa->fsx_xflags & FS_XFLAG_IMMUTABLE))
+		return -EPERM;
+
 	/* diflags2 only valid for v3 inodes. */
 	di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
 	if (di_flags2 && ip->i_d.di_version < 3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] xfs: reset page mappings after setting immutable
  2019-03-28 17:50 ` [PATCH 2/3] xfs: reset page mappings after setting immutable Darrick J. Wong
@ 2019-03-28 21:21   ` Dave Chinner
  2019-04-05  0:29     ` Darrick J. Wong
  0 siblings, 1 reply; 9+ messages in thread
From: Dave Chinner @ 2019-03-28 21:21 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

On Thu, Mar 28, 2019 at 10:50:47AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> The chattr manpage has this to say about immutable files:
> 
> "A file with the 'i' attribute cannot be modified: it cannot be deleted
> or renamed, no link can be created to this file, most of the file's
> metadata can not be modified, and the file can not be opened in write
> mode."
> 
> This means that we need to flush the page cache when setting the

nit: flush and invalidate the page cache.

> immutable flag so that programs cannot continue to write to writable
> mappings.

Do we even need to invalidate the page cache for this? i.e. we've
cleaned the pages so that any new write to them will fault,
that will see the immutable flag via ->page_mkwrite and then the
app should segv, right?

> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/xfs_ioctl.c |   63 +++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 43 insertions(+), 20 deletions(-)
> 
> 
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 6ecdbb3af7de..2bd1c5ab5008 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -998,6 +998,37 @@ xfs_diflags_to_linux(
>  #endif
>  }
>  
> +static int
> +xfs_ioctl_setattr_flush(
> +	struct xfs_inode	*ip,
> +	int			*join_flags)
> +{
> +	struct inode		*inode = VFS_I(ip);
> +	int			error;
> +
> +	if (S_ISDIR(inode->i_mode))
> +		return 0;
> +	if ((*join_flags) & (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL))
> +		return 0;
> +
> +	/* lock, flush and invalidate mapping in preparation for flag change */
> +	xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
> +	error = filemap_write_and_wait(inode->i_mapping);
> +	if (error)
> +		goto out_unlock;
> +	error = invalidate_inode_pages2(inode->i_mapping);
> +	if (error)
> +		goto out_unlock;
> +
> +	*join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL;
> +	return 0;
> +
> +out_unlock:
> +	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
> +	return error;
> +
> +}

Doesn't wait for direct IO to drain. Wouldn't it be better to do
this?

	lock()
	xfs_flush_unmap_range(ip, 0, XFS_SIZE(ip));
	unlock()

Otherwise looks ok.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] xfs: don't allow most setxattr to immutable files
  2019-03-28 17:50 ` [PATCH 3/3] xfs: don't allow most setxattr to immutable files Darrick J. Wong
@ 2019-03-28 21:24   ` Amir Goldstein
  2019-03-28 21:29   ` Dave Chinner
  1 sibling, 0 replies; 9+ messages in thread
From: Amir Goldstein @ 2019-03-28 21:24 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, linux-fsdevel, Ext4, Linux Btrfs, Linux MM

On Thu, Mar 28, 2019 at 7:51 PM Darrick J. Wong <darrick.wong@oracle.com> wrote:
>
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> The chattr manpage has this to say about immutable files:
>
> "A file with the 'i' attribute cannot be modified: it cannot be deleted
> or renamed, no link can be created to this file, most of the file's
> metadata can not be modified, and the file can not be opened in write
> mode."
>
> However, we don't actually check the immutable flag in the setattr code,
> which means that we can update project ids and extent size hints on
> supposedly immutable files.  Therefore, reject a setattr call on an
> immutable file except for the case where we're trying to unset
> IMMUTABLE.
>

I think if preventing modification of projid and extent size hints is what you
are after you should place the check in xfs_ioctl_setattr() and not in
xfs_ioctl_setattr_xflags().

Yes, it sounds tempting to block changes of xfs_ioc_setxflags(),
but it leads you to a trap of 2nd time chattr +i fails on -EPERM,
because chattr(1) doesn't optimize out the SETFLAGS ioctl
in the case of unmodified flags.
I think if you try to fix that, code will get ugly, so I suggest that
you let SETFLAGS slide.

Thanks,
Amir.

> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/xfs_ioctl.c |    8 ++++++++
>  1 file changed, 8 insertions(+)
>
>
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 2bd1c5ab5008..9cf0bc0ae2bd 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -1067,6 +1067,14 @@ xfs_ioctl_setattr_xflags(
>             !capable(CAP_LINUX_IMMUTABLE))
>                 return -EPERM;
>
> +       /*
> +        * If immutable is set and we are not clearing it, we're not allowed
> +        * to change anything else in the inode.
> +        */
> +       if ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) &&
> +           (fa->fsx_xflags & FS_XFLAG_IMMUTABLE))
> +               return -EPERM;
> +
>         /* diflags2 only valid for v3 inodes. */
>         di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
>         if (di_flags2 && ip->i_d.di_version < 3)
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] xfs: don't allow most setxattr to immutable files
  2019-03-28 17:50 ` [PATCH 3/3] xfs: don't allow most setxattr to immutable files Darrick J. Wong
  2019-03-28 21:24   ` Amir Goldstein
@ 2019-03-28 21:29   ` Dave Chinner
  2019-03-29  4:02     ` Darrick J. Wong
  1 sibling, 1 reply; 9+ messages in thread
From: Dave Chinner @ 2019-03-28 21:29 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

On Thu, Mar 28, 2019 at 10:50:54AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> The chattr manpage has this to say about immutable files:
> 
> "A file with the 'i' attribute cannot be modified: it cannot be deleted
> or renamed, no link can be created to this file, most of the file's
> metadata can not be modified, and the file can not be opened in write
> mode."
> 
> However, we don't actually check the immutable flag in the setattr code,
> which means that we can update project ids and extent size hints on
> supposedly immutable files.  Therefore, reject a setattr call on an
> immutable file except for the case where we're trying to unset
> IMMUTABLE.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/xfs_ioctl.c |    8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> 
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 2bd1c5ab5008..9cf0bc0ae2bd 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -1067,6 +1067,14 @@ xfs_ioctl_setattr_xflags(
>  	    !capable(CAP_LINUX_IMMUTABLE))
>  		return -EPERM;
>  
> +	/*
> +	 * If immutable is set and we are not clearing it, we're not allowed
> +	 * to change anything else in the inode.
> +	 */
> +	if ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) &&
> +	    (fa->fsx_xflags & FS_XFLAG_IMMUTABLE))
> +		return -EPERM;
> +
>  	/* diflags2 only valid for v3 inodes. */
>  	di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
>  	if (di_flags2 && ip->i_d.di_version < 3)

Looks fine - catches both FS_IOC_SETFLAGS and FS_IOC_FSSETXATTR
for XFS.

Do the other filesystems that implement FS_IOC_FSSETXATTR have
the same bug?

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] xfs: don't allow most setxattr to immutable files
  2019-03-28 21:29   ` Dave Chinner
@ 2019-03-29  4:02     ` Darrick J. Wong
  0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2019-03-29  4:02 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

On Fri, Mar 29, 2019 at 08:29:48AM +1100, Dave Chinner wrote:
> On Thu, Mar 28, 2019 at 10:50:54AM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > The chattr manpage has this to say about immutable files:
> > 
> > "A file with the 'i' attribute cannot be modified: it cannot be deleted
> > or renamed, no link can be created to this file, most of the file's
> > metadata can not be modified, and the file can not be opened in write
> > mode."
> > 
> > However, we don't actually check the immutable flag in the setattr code,
> > which means that we can update project ids and extent size hints on
> > supposedly immutable files.  Therefore, reject a setattr call on an
> > immutable file except for the case where we're trying to unset
> > IMMUTABLE.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  fs/xfs/xfs_ioctl.c |    8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> > 
> > diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> > index 2bd1c5ab5008..9cf0bc0ae2bd 100644
> > --- a/fs/xfs/xfs_ioctl.c
> > +++ b/fs/xfs/xfs_ioctl.c
> > @@ -1067,6 +1067,14 @@ xfs_ioctl_setattr_xflags(
> >  	    !capable(CAP_LINUX_IMMUTABLE))
> >  		return -EPERM;
> >  
> > +	/*
> > +	 * If immutable is set and we are not clearing it, we're not allowed
> > +	 * to change anything else in the inode.
> > +	 */
> > +	if ((ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) &&
> > +	    (fa->fsx_xflags & FS_XFLAG_IMMUTABLE))
> > +		return -EPERM;
> > +
> >  	/* diflags2 only valid for v3 inodes. */
> >  	di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
> >  	if (di_flags2 && ip->i_d.di_version < 3)
> 
> Looks fine - catches both FS_IOC_SETFLAGS and FS_IOC_FSSETXATTR
> for XFS.
> 
> Do the other filesystems that implement FS_IOC_FSSETXATTR have
> the same bug?

Yes.  I'm not even 100% sure I've finished playing xfs whackamole yet.

--D

> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] xfs: reset page mappings after setting immutable
  2019-03-28 21:21   ` Dave Chinner
@ 2019-04-05  0:29     ` Darrick J. Wong
  0 siblings, 0 replies; 9+ messages in thread
From: Darrick J. Wong @ 2019-04-05  0:29 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs, linux-fsdevel, linux-ext4, linux-btrfs, linux-mm

On Fri, Mar 29, 2019 at 08:21:47AM +1100, Dave Chinner wrote:
> On Thu, Mar 28, 2019 at 10:50:47AM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <darrick.wong@oracle.com>
> > 
> > The chattr manpage has this to say about immutable files:
> > 
> > "A file with the 'i' attribute cannot be modified: it cannot be deleted
> > or renamed, no link can be created to this file, most of the file's
> > metadata can not be modified, and the file can not be opened in write
> > mode."
> > 
> > This means that we need to flush the page cache when setting the
> 
> nit: flush and invalidate the page cache.
> 
> > immutable flag so that programs cannot continue to write to writable
> > mappings.
> 
> Do we even need to invalidate the page cache for this? i.e. we've
> cleaned the pages so that any new write to them will fault,
> that will see the immutable flag via ->page_mkwrite and then the
> app should segv, right?

Yeah, we only need to flush the pages.  No need to invalidate.

> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> >  fs/xfs/xfs_ioctl.c |   63 +++++++++++++++++++++++++++++++++++-----------------
> >  1 file changed, 43 insertions(+), 20 deletions(-)
> > 
> > 
> > diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> > index 6ecdbb3af7de..2bd1c5ab5008 100644
> > --- a/fs/xfs/xfs_ioctl.c
> > +++ b/fs/xfs/xfs_ioctl.c
> > @@ -998,6 +998,37 @@ xfs_diflags_to_linux(
> >  #endif
> >  }
> >  
> > +static int
> > +xfs_ioctl_setattr_flush(
> > +	struct xfs_inode	*ip,
> > +	int			*join_flags)
> > +{
> > +	struct inode		*inode = VFS_I(ip);
> > +	int			error;
> > +
> > +	if (S_ISDIR(inode->i_mode))
> > +		return 0;
> > +	if ((*join_flags) & (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL))
> > +		return 0;
> > +
> > +	/* lock, flush and invalidate mapping in preparation for flag change */
> > +	xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
> > +	error = filemap_write_and_wait(inode->i_mapping);
> > +	if (error)
> > +		goto out_unlock;
> > +	error = invalidate_inode_pages2(inode->i_mapping);
> > +	if (error)
> > +		goto out_unlock;
> > +
> > +	*join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL;
> > +	return 0;
> > +
> > +out_unlock:
> > +	xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
> > +	return error;
> > +
> > +}
> 
> Doesn't wait for direct IO to drain. Wouldn't it be better to do
> this?
> 
> 	lock()
> 	xfs_flush_unmap_range(ip, 0, XFS_SIZE(ip));
> 	unlock()

But if we only need to filemap_write_and_wait, then calling flush_unmap
(which also calls truncate_pagecache_range) is too much work.

--D

> 
> Otherwise looks ok.
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-04-05  0:29 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-28 17:50 [PATCH 0/3] vfs: make immutable files actually immutable Darrick J. Wong
2019-03-28 17:50 ` [PATCH 1/3] mm/fs: don't allow writes to immutable files Darrick J. Wong
2019-03-28 17:50 ` [PATCH 2/3] xfs: reset page mappings after setting immutable Darrick J. Wong
2019-03-28 21:21   ` Dave Chinner
2019-04-05  0:29     ` Darrick J. Wong
2019-03-28 17:50 ` [PATCH 3/3] xfs: don't allow most setxattr to immutable files Darrick J. Wong
2019-03-28 21:24   ` Amir Goldstein
2019-03-28 21:29   ` Dave Chinner
2019-03-29  4:02     ` Darrick J. Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).