Re: [PATCH v2] NFSv4.2: Update mode bits after ALLOCATE and DEALLOCATE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2022-09-01 at 14:05 -0400, Anna Schumaker wrote:
> From: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx>
> 
> The fallocate call invalidates suid and sgid bits as part of normal
> operation. We need to mark the mode bits as invalid when using
> fallocate
> with an suid so these will be updated the next time the user looks at
> them.
> 
> This fixes xfstests generic/683 and generic/684.
> 
> Reported-by: Yue Cui <cuiyue-fnst@xxxxxxxxxxx>
> Fixes: 913eca1aea87 ("NFS: Fallocate should use the
> nfs4_fattr_bitmap")
> Signed-off-by: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx>
> ---
>  fs/nfs/internal.h  | 25 +++++++++++++++++++++++++
>  fs/nfs/nfs42proc.c | 13 ++++++++++++-
>  fs/nfs/write.c     | 25 -------------------------
>  3 files changed, 37 insertions(+), 26 deletions(-)
> 
> diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
> index 27c720d71b4e..898dd95bc7a7 100644
> --- a/fs/nfs/internal.h
> +++ b/fs/nfs/internal.h
> @@ -606,6 +606,31 @@ static inline gfp_t nfs_io_gfp_mask(void)
>         return GFP_KERNEL;
>  }
>  
> +/*
> + * Special version of should_remove_suid() that ignores
> capabilities.
> + */
> +static inline int nfs_should_remove_suid(const struct inode *inode)
> +{
> +       umode_t mode = inode->i_mode;
> +       int kill = 0;
> +
> +       /* suid always must be killed */
> +       if (unlikely(mode & S_ISUID))
> +               kill = ATTR_KILL_SUID;
> +
> +       /*
> +        * sgid without any exec bits is just a mandatory locking
> mark; leave
> +        * it alone.  If some exec bits are set, it's a real sgid;
> kill it.
> +        */
> +       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> +               kill |= ATTR_KILL_SGID;
> +
> +       if (unlikely(kill && S_ISREG(mode)))
> +               return kill;
> +
> +       return 0;
> +}
> +
>  /* unlink.c */
>  extern struct rpc_task *
>  nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
> diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
> index 068c45b3bc1a..23023ddf75d1 100644
> --- a/fs/nfs/nfs42proc.c
> +++ b/fs/nfs/nfs42proc.c
> @@ -56,6 +56,7 @@ static int _nfs42_proc_fallocate(struct rpc_message
> *msg, struct file *filep,
>         struct nfs42_falloc_res res = {
>                 .falloc_server  = server,
>         };
> +       unsigned int invalid = 0;
>         int status;
>  
>         msg->rpc_argp = &args;
> @@ -78,10 +79,20 @@ static int _nfs42_proc_fallocate(struct
> rpc_message *msg, struct file *filep,
>  
>         status = nfs4_call_sync(server->client, server, msg,
>                                 &args.seq_args, &res.seq_res, 0);
> +
> +       if (!res.falloc_fattr->valid)
> +               invalid |= NFS_INO_INVALID_ATTR;
> +       if (nfs_should_remove_suid(inode))
> +               invalid |= NFS_INO_INVALID_MODE;
> +       if (invalid) {
> +               spin_lock(&inode->i_lock);
> +               nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
> +               spin_unlock(&inode->i_lock);
> +       }

This all really wants to go into the 'if (status == 0)' below.
> +
>         if (status == 0)
>                 status = nfs_post_op_update_inode_force_wcc(inode,
>                                                            
> res.falloc_fattr);
> -
>         if (msg->rpc_proc ==
> &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE])
>                 trace_nfs4_fallocate(inode, &args, status);
>         else
> diff --git a/fs/nfs/write.c b/fs/nfs/write.c
> index 1843fa235d9b..f41d24b54fd1 100644
> --- a/fs/nfs/write.c
> +++ b/fs/nfs/write.c
> @@ -1496,31 +1496,6 @@ void nfs_commit_prepare(struct rpc_task *task,
> void *calldata)
>         NFS_PROTO(data->inode)->commit_rpc_prepare(task, data);
>  }
>  
> -/*
> - * Special version of should_remove_suid() that ignores
> capabilities.
> - */
> -static int nfs_should_remove_suid(const struct inode *inode)
> -{
> -       umode_t mode = inode->i_mode;
> -       int kill = 0;
> -
> -       /* suid always must be killed */
> -       if (unlikely(mode & S_ISUID))
> -               kill = ATTR_KILL_SUID;
> -
> -       /*
> -        * sgid without any exec bits is just a mandatory locking
> mark; leave
> -        * it alone.  If some exec bits are set, it's a real sgid;
> kill it.
> -        */
> -       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> -               kill |= ATTR_KILL_SGID;
> -
> -       if (unlikely(kill && S_ISREG(mode)))
> -               return kill;
> -
> -       return 0;
> -}
> -
>  static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
>                 struct nfs_fattr *fattr)
>  {

Otherwise, looks OK.

-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@xxxxxxxxxxxxxxx






[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux