LCOV - code coverage report
Current view: top level - fs/nfs - nfs3acl.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 186 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 9 0.0 %
Branches: 0 113 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/fs.h>
       3                 :            : #include <linux/gfp.h>
       4                 :            : #include <linux/nfs.h>
       5                 :            : #include <linux/nfs3.h>
       6                 :            : #include <linux/nfs_fs.h>
       7                 :            : #include <linux/posix_acl_xattr.h>
       8                 :            : #include <linux/nfsacl.h>
       9                 :            : 
      10                 :            : #include "internal.h"
      11                 :            : #include "nfs3_fs.h"
      12                 :            : 
      13                 :            : #define NFSDBG_FACILITY NFSDBG_PROC
      14                 :            : 
      15                 :            : /*
      16                 :            :  * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for
      17                 :            :  * caching get_acl results in a race-free way.  See fs/posix_acl.c:get_acl()
      18                 :            :  * for explanations.
      19                 :            :  */
      20                 :          0 : static void nfs3_prepare_get_acl(struct posix_acl **p)
      21                 :            : {
      22                 :          0 :         struct posix_acl *sentinel = uncached_acl_sentinel(current);
      23                 :            : 
      24                 :          0 :         if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) {
      25                 :            :                 /* Not the first reader or sentinel already in place. */
      26                 :          0 :         }
      27                 :          0 : }
      28                 :            : 
      29                 :          0 : static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
      30                 :            : {
      31         [ #  # ]:          0 :         struct posix_acl *sentinel = uncached_acl_sentinel(current);
      32                 :            : 
      33                 :            :         /* Only cache the ACL if our sentinel is still in place. */
      34         [ #  # ]:          0 :         posix_acl_dup(acl);
      35         [ #  # ]:          0 :         if (cmpxchg(p, sentinel, acl) != sentinel)
      36                 :          0 :                 posix_acl_release(acl);
      37                 :          0 : }
      38                 :            : 
      39                 :          0 : static void nfs3_abort_get_acl(struct posix_acl **p)
      40                 :            : {
      41                 :          0 :         struct posix_acl *sentinel = uncached_acl_sentinel(current);
      42                 :            : 
      43                 :            :         /* Remove our sentinel upon failure. */
      44                 :          0 :         cmpxchg(p, sentinel, ACL_NOT_CACHED);
      45                 :          0 : }
      46                 :            : 
      47                 :          0 : struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
      48                 :            : {
      49         [ #  # ]:          0 :         struct nfs_server *server = NFS_SERVER(inode);
      50                 :          0 :         struct page *pages[NFSACL_MAXPAGES] = { };
      51         [ #  # ]:          0 :         struct nfs3_getaclargs args = {
      52                 :            :                 .fh = NFS_FH(inode),
      53                 :            :                 /* The xdr layer may allocate pages here. */
      54                 :            :                 .pages = pages,
      55                 :            :         };
      56                 :          0 :         struct nfs3_getaclres res = {
      57                 :            :                 NULL,
      58                 :            :         };
      59                 :          0 :         struct rpc_message msg = {
      60                 :            :                 .rpc_argp       = &args,
      61                 :            :                 .rpc_resp       = &res,
      62                 :            :         };
      63                 :          0 :         int status, count;
      64                 :            : 
      65         [ #  # ]:          0 :         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
      66                 :            :                 return ERR_PTR(-EOPNOTSUPP);
      67                 :            : 
      68                 :          0 :         status = nfs_revalidate_inode(server, inode);
      69         [ #  # ]:          0 :         if (status < 0)
      70                 :          0 :                 return ERR_PTR(status);
      71                 :            : 
      72                 :            :         /*
      73                 :            :          * Only get the access acl when explicitly requested: We don't
      74                 :            :          * need it for access decisions, and only some applications use
      75                 :            :          * it. Applications which request the access acl first are not
      76                 :            :          * penalized from this optimization.
      77                 :            :          */
      78         [ #  # ]:          0 :         if (type == ACL_TYPE_ACCESS)
      79                 :          0 :                 args.mask |= NFS_ACLCNT|NFS_ACL;
      80         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode))
      81                 :          0 :                 args.mask |= NFS_DFACLCNT|NFS_DFACL;
      82         [ #  # ]:          0 :         if (args.mask == 0)
      83                 :            :                 return NULL;
      84                 :            : 
      85                 :          0 :         dprintk("NFS call getacl\n");
      86                 :          0 :         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
      87                 :          0 :         res.fattr = nfs_alloc_fattr();
      88         [ #  # ]:          0 :         if (res.fattr == NULL)
      89                 :            :                 return ERR_PTR(-ENOMEM);
      90                 :            : 
      91         [ #  # ]:          0 :         if (args.mask & NFS_ACL)
      92                 :          0 :                 nfs3_prepare_get_acl(&inode->i_acl);
      93         [ #  # ]:          0 :         if (args.mask & NFS_DFACL)
      94                 :          0 :                 nfs3_prepare_get_acl(&inode->i_default_acl);
      95                 :            : 
      96                 :          0 :         status = rpc_call_sync(server->client_acl, &msg, 0);
      97                 :          0 :         dprintk("NFS reply getacl: %d\n", status);
      98                 :            : 
      99                 :            :         /* pages may have been allocated at the xdr layer. */
     100   [ #  #  #  # ]:          0 :         for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
     101                 :          0 :                 __free_page(args.pages[count]);
     102                 :            : 
     103   [ #  #  #  # ]:          0 :         switch (status) {
     104                 :          0 :                 case 0:
     105                 :          0 :                         status = nfs_refresh_inode(inode, res.fattr);
     106                 :          0 :                         break;
     107                 :          0 :                 case -EPFNOSUPPORT:
     108                 :            :                 case -EPROTONOSUPPORT:
     109                 :          0 :                         dprintk("NFS_V3_ACL extension not supported; disabling\n");
     110                 :          0 :                         server->caps &= ~NFS_CAP_ACLS;
     111                 :            :                         /* fall through */
     112                 :            :                 case -ENOTSUPP:
     113                 :            :                         status = -EOPNOTSUPP;
     114                 :          0 :                 default:
     115                 :          0 :                         goto getout;
     116                 :            :         }
     117         [ #  # ]:          0 :         if ((args.mask & res.mask) != args.mask) {
     118                 :          0 :                 status = -EIO;
     119                 :          0 :                 goto getout;
     120                 :            :         }
     121                 :            : 
     122         [ #  # ]:          0 :         if (res.acl_access != NULL) {
     123         [ #  # ]:          0 :                 if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) ||
     124         [ #  # ]:          0 :                     res.acl_access->a_count == 0) {
     125                 :          0 :                         posix_acl_release(res.acl_access);
     126                 :          0 :                         res.acl_access = NULL;
     127                 :            :                 }
     128                 :            :         }
     129                 :            : 
     130         [ #  # ]:          0 :         if (res.mask & NFS_ACL)
     131                 :          0 :                 nfs3_complete_get_acl(&inode->i_acl, res.acl_access);
     132                 :            :         else
     133                 :          0 :                 forget_cached_acl(inode, ACL_TYPE_ACCESS);
     134                 :            : 
     135         [ #  # ]:          0 :         if (res.mask & NFS_DFACL)
     136                 :          0 :                 nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default);
     137                 :            :         else
     138                 :          0 :                 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
     139                 :            : 
     140                 :          0 :         nfs_free_fattr(res.fattr);
     141         [ #  # ]:          0 :         if (type == ACL_TYPE_ACCESS) {
     142                 :          0 :                 posix_acl_release(res.acl_default);
     143                 :          0 :                 return res.acl_access;
     144                 :            :         } else {
     145                 :          0 :                 posix_acl_release(res.acl_access);
     146                 :          0 :                 return res.acl_default;
     147                 :            :         }
     148                 :            : 
     149                 :          0 : getout:
     150                 :          0 :         nfs3_abort_get_acl(&inode->i_acl);
     151                 :          0 :         nfs3_abort_get_acl(&inode->i_default_acl);
     152                 :          0 :         posix_acl_release(res.acl_access);
     153                 :          0 :         posix_acl_release(res.acl_default);
     154                 :          0 :         nfs_free_fattr(res.fattr);
     155                 :          0 :         return ERR_PTR(status);
     156                 :            : }
     157                 :            : 
     158                 :          0 : static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
     159                 :            :                 struct posix_acl *dfacl)
     160                 :            : {
     161         [ #  # ]:          0 :         struct nfs_server *server = NFS_SERVER(inode);
     162                 :          0 :         struct nfs_fattr *fattr;
     163                 :          0 :         struct page *pages[NFSACL_MAXPAGES];
     164                 :          0 :         struct nfs3_setaclargs args = {
     165                 :            :                 .inode = inode,
     166                 :            :                 .mask = NFS_ACL,
     167                 :            :                 .acl_access = acl,
     168                 :            :                 .pages = pages,
     169                 :            :         };
     170                 :          0 :         struct rpc_message msg = {
     171                 :            :                 .rpc_argp       = &args,
     172                 :            :                 .rpc_resp       = &fattr,
     173                 :            :         };
     174                 :          0 :         int status = 0;
     175                 :            : 
     176   [ #  #  #  #  :          0 :         if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL))
                   #  # ]
     177                 :          0 :                 goto out;
     178                 :            : 
     179                 :          0 :         status = -EOPNOTSUPP;
     180         [ #  # ]:          0 :         if (!nfs_server_capable(inode, NFS_CAP_ACLS))
     181                 :          0 :                 goto out;
     182                 :            : 
     183                 :            :         /* We are doing this here because XDR marshalling does not
     184                 :            :          * return any results, it BUGs. */
     185                 :          0 :         status = -ENOSPC;
     186   [ #  #  #  # ]:          0 :         if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
     187                 :          0 :                 goto out;
     188   [ #  #  #  # ]:          0 :         if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
     189                 :          0 :                 goto out;
     190         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode)) {
     191                 :          0 :                 args.mask |= NFS_DFACL;
     192                 :          0 :                 args.acl_default = dfacl;
     193         [ #  # ]:          0 :                 args.len = nfsacl_size(acl, dfacl);
     194                 :            :         } else
     195         [ #  # ]:          0 :                 args.len = nfsacl_size(acl, NULL);
     196                 :            : 
     197         [ #  # ]:          0 :         if (args.len > NFS_ACL_INLINE_BUFSIZE) {
     198                 :          0 :                 unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
     199                 :            : 
     200                 :          0 :                 status = -ENOMEM;
     201                 :          0 :                 do {
     202                 :          0 :                         args.pages[args.npages] = alloc_page(GFP_KERNEL);
     203         [ #  # ]:          0 :                         if (args.pages[args.npages] == NULL)
     204                 :          0 :                                 goto out_freepages;
     205                 :          0 :                         args.npages++;
     206         [ #  # ]:          0 :                 } while (args.npages < npages);
     207                 :            :         }
     208                 :            : 
     209                 :          0 :         dprintk("NFS call setacl\n");
     210                 :          0 :         status = -ENOMEM;
     211                 :          0 :         fattr = nfs_alloc_fattr();
     212         [ #  # ]:          0 :         if (fattr == NULL)
     213                 :          0 :                 goto out_freepages;
     214                 :            : 
     215                 :          0 :         msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
     216                 :          0 :         msg.rpc_resp = fattr;
     217                 :          0 :         status = rpc_call_sync(server->client_acl, &msg, 0);
     218                 :          0 :         nfs_access_zap_cache(inode);
     219                 :          0 :         nfs_zap_acl_cache(inode);
     220                 :          0 :         dprintk("NFS reply setacl: %d\n", status);
     221                 :            : 
     222   [ #  #  #  # ]:          0 :         switch (status) {
     223                 :          0 :                 case 0:
     224                 :          0 :                         status = nfs_refresh_inode(inode, fattr);
     225                 :          0 :                         break;
     226                 :          0 :                 case -EPFNOSUPPORT:
     227                 :            :                 case -EPROTONOSUPPORT:
     228                 :          0 :                         dprintk("NFS_V3_ACL SETACL RPC not supported"
     229                 :            :                                         "(will not retry)\n");
     230                 :          0 :                         server->caps &= ~NFS_CAP_ACLS;
     231                 :            :                         /* fall through */
     232                 :            :                 case -ENOTSUPP:
     233                 :            :                         status = -EOPNOTSUPP;
     234                 :            :         }
     235                 :          0 :         nfs_free_fattr(fattr);
     236                 :          0 : out_freepages:
     237         [ #  # ]:          0 :         while (args.npages != 0) {
     238                 :          0 :                 args.npages--;
     239                 :          0 :                 __free_page(args.pages[args.npages]);
     240                 :            :         }
     241                 :          0 : out:
     242                 :          0 :         return status;
     243                 :            : }
     244                 :            : 
     245                 :          0 : int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
     246                 :            :                 struct posix_acl *dfacl)
     247                 :            : {
     248                 :          0 :         int ret;
     249                 :          0 :         ret = __nfs3_proc_setacls(inode, acl, dfacl);
     250         [ #  # ]:          0 :         return (ret == -EOPNOTSUPP) ? 0 : ret;
     251                 :            : 
     252                 :            : }
     253                 :            : 
     254                 :          0 : int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
     255                 :            : {
     256                 :          0 :         struct posix_acl *alloc = NULL, *dfacl = NULL;
     257                 :          0 :         int status;
     258                 :            : 
     259         [ #  # ]:          0 :         if (S_ISDIR(inode->i_mode)) {
     260      [ #  #  # ]:          0 :                 switch(type) {
     261                 :          0 :                 case ACL_TYPE_ACCESS:
     262                 :          0 :                         alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
     263         [ #  # ]:          0 :                         if (IS_ERR(alloc))
     264                 :          0 :                                 goto fail;
     265                 :            :                         break;
     266                 :            : 
     267                 :          0 :                 case ACL_TYPE_DEFAULT:
     268                 :          0 :                         dfacl = acl;
     269                 :          0 :                         alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
     270         [ #  # ]:          0 :                         if (IS_ERR(alloc))
     271                 :          0 :                                 goto fail;
     272                 :            :                         break;
     273                 :            :                 }
     274                 :          0 :         }
     275                 :            : 
     276         [ #  # ]:          0 :         if (acl == NULL) {
     277                 :          0 :                 alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
     278         [ #  # ]:          0 :                 if (IS_ERR(alloc))
     279                 :          0 :                         goto fail;
     280                 :            :         }
     281                 :          0 :         status = __nfs3_proc_setacls(inode, acl, dfacl);
     282                 :          0 :         posix_acl_release(alloc);
     283                 :          0 :         return status;
     284                 :            : 
     285                 :          0 : fail:
     286                 :          0 :         return PTR_ERR(alloc);
     287                 :            : }
     288                 :            : 
     289                 :            : const struct xattr_handler *nfs3_xattr_handlers[] = {
     290                 :            :         &posix_acl_access_xattr_handler,
     291                 :            :         &posix_acl_default_xattr_handler,
     292                 :            :         NULL,
     293                 :            : };
     294                 :            : 
     295                 :            : static int
     296                 :          0 : nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
     297                 :            :                 size_t size, ssize_t *result)
     298                 :            : {
     299                 :          0 :         struct posix_acl *acl;
     300                 :          0 :         char *p = data + *result;
     301                 :            : 
     302                 :          0 :         acl = get_acl(inode, type);
     303   [ #  #  #  # ]:          0 :         if (IS_ERR_OR_NULL(acl))
     304                 :            :                 return 0;
     305                 :            : 
     306                 :          0 :         posix_acl_release(acl);
     307                 :            : 
     308                 :          0 :         *result += strlen(name);
     309                 :          0 :         *result += 1;
     310         [ #  # ]:          0 :         if (!size)
     311                 :            :                 return 0;
     312         [ #  # ]:          0 :         if (*result > size)
     313                 :            :                 return -ERANGE;
     314                 :            : 
     315                 :          0 :         strcpy(p, name);
     316                 :          0 :         return 0;
     317                 :            : }
     318                 :            : 
     319                 :            : ssize_t
     320                 :          0 : nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
     321                 :            : {
     322                 :          0 :         struct inode *inode = d_inode(dentry);
     323                 :          0 :         ssize_t result = 0;
     324                 :          0 :         int error;
     325                 :            : 
     326                 :          0 :         error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
     327                 :            :                         XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
     328         [ #  # ]:          0 :         if (error)
     329                 :          0 :                 return error;
     330                 :            : 
     331                 :          0 :         error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
     332                 :            :                         XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
     333         [ #  # ]:          0 :         if (error)
     334                 :          0 :                 return error;
     335                 :          0 :         return result;
     336                 :            : }

Generated by: LCOV version 1.14