LCOV - code coverage report
Current view: top level - fs/ext4 - acl.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 57 157 36.3 %
Date: 2022-04-01 14:35:51 Functions: 4 6 66.7 %
Branches: 20 96 20.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * linux/fs/ext4/acl.c
       4                 :            :  *
       5                 :            :  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/quotaops.h>
       9                 :            : #include "ext4_jbd2.h"
      10                 :            : #include "ext4.h"
      11                 :            : #include "xattr.h"
      12                 :            : #include "acl.h"
      13                 :            : 
      14                 :            : /*
      15                 :            :  * Convert from filesystem to in-memory representation.
      16                 :            :  */
      17                 :            : static struct posix_acl *
      18                 :          0 : ext4_acl_from_disk(const void *value, size_t size)
      19                 :            : {
      20                 :          0 :         const char *end = (char *)value + size;
      21                 :          0 :         int n, count;
      22                 :          0 :         struct posix_acl *acl;
      23                 :            : 
      24         [ #  # ]:          0 :         if (!value)
      25                 :            :                 return NULL;
      26         [ #  # ]:          0 :         if (size < sizeof(ext4_acl_header))
      27                 :            :                  return ERR_PTR(-EINVAL);
      28         [ #  # ]:          0 :         if (((ext4_acl_header *)value)->a_version !=
      29                 :            :             cpu_to_le32(EXT4_ACL_VERSION))
      30                 :            :                 return ERR_PTR(-EINVAL);
      31                 :          0 :         value = (char *)value + sizeof(ext4_acl_header);
      32         [ #  # ]:          0 :         count = ext4_acl_count(size);
      33         [ #  # ]:          0 :         if (count < 0)
      34                 :            :                 return ERR_PTR(-EINVAL);
      35         [ #  # ]:          0 :         if (count == 0)
      36                 :            :                 return NULL;
      37                 :          0 :         acl = posix_acl_alloc(count, GFP_NOFS);
      38         [ #  # ]:          0 :         if (!acl)
      39                 :            :                 return ERR_PTR(-ENOMEM);
      40         [ #  # ]:          0 :         for (n = 0; n < count; n++) {
      41                 :          0 :                 ext4_acl_entry *entry =
      42                 :            :                         (ext4_acl_entry *)value;
      43         [ #  # ]:          0 :                 if ((char *)value + sizeof(ext4_acl_entry_short) > end)
      44                 :          0 :                         goto fail;
      45                 :          0 :                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
      46                 :          0 :                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
      47                 :            : 
      48   [ #  #  #  # ]:          0 :                 switch (acl->a_entries[n].e_tag) {
      49                 :            :                 case ACL_USER_OBJ:
      50                 :            :                 case ACL_GROUP_OBJ:
      51                 :            :                 case ACL_MASK:
      52                 :            :                 case ACL_OTHER:
      53                 :            :                         value = (char *)value +
      54                 :            :                                 sizeof(ext4_acl_entry_short);
      55                 :            :                         break;
      56                 :            : 
      57                 :          0 :                 case ACL_USER:
      58                 :          0 :                         value = (char *)value + sizeof(ext4_acl_entry);
      59         [ #  # ]:          0 :                         if ((char *)value > end)
      60                 :          0 :                                 goto fail;
      61                 :          0 :                         acl->a_entries[n].e_uid =
      62                 :          0 :                                 make_kuid(&init_user_ns,
      63                 :          0 :                                           le32_to_cpu(entry->e_id));
      64                 :          0 :                         break;
      65                 :          0 :                 case ACL_GROUP:
      66                 :          0 :                         value = (char *)value + sizeof(ext4_acl_entry);
      67         [ #  # ]:          0 :                         if ((char *)value > end)
      68                 :          0 :                                 goto fail;
      69                 :          0 :                         acl->a_entries[n].e_gid =
      70                 :          0 :                                 make_kgid(&init_user_ns,
      71                 :          0 :                                           le32_to_cpu(entry->e_id));
      72                 :          0 :                         break;
      73                 :            : 
      74                 :          0 :                 default:
      75                 :          0 :                         goto fail;
      76                 :            :                 }
      77                 :            :         }
      78         [ #  # ]:          0 :         if (value != end)
      79                 :          0 :                 goto fail;
      80                 :            :         return acl;
      81                 :            : 
      82                 :          0 : fail:
      83                 :          0 :         posix_acl_release(acl);
      84                 :          0 :         return ERR_PTR(-EINVAL);
      85                 :            : }
      86                 :            : 
      87                 :            : /*
      88                 :            :  * Convert from in-memory to filesystem representation.
      89                 :            :  */
      90                 :            : static void *
      91                 :          0 : ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
      92                 :            : {
      93                 :          0 :         ext4_acl_header *ext_acl;
      94                 :          0 :         char *e;
      95                 :          0 :         size_t n;
      96                 :            : 
      97         [ #  # ]:          0 :         *size = ext4_acl_size(acl->a_count);
      98         [ #  # ]:          0 :         ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
      99                 :            :                         sizeof(ext4_acl_entry), GFP_NOFS);
     100         [ #  # ]:          0 :         if (!ext_acl)
     101                 :            :                 return ERR_PTR(-ENOMEM);
     102                 :          0 :         ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
     103                 :          0 :         e = (char *)ext_acl + sizeof(ext4_acl_header);
     104         [ #  # ]:          0 :         for (n = 0; n < acl->a_count; n++) {
     105                 :          0 :                 const struct posix_acl_entry *acl_e = &acl->a_entries[n];
     106                 :          0 :                 ext4_acl_entry *entry = (ext4_acl_entry *)e;
     107                 :          0 :                 entry->e_tag  = cpu_to_le16(acl_e->e_tag);
     108                 :          0 :                 entry->e_perm = cpu_to_le16(acl_e->e_perm);
     109   [ #  #  #  # ]:          0 :                 switch (acl_e->e_tag) {
     110                 :          0 :                 case ACL_USER:
     111                 :          0 :                         entry->e_id = cpu_to_le32(
     112                 :            :                                 from_kuid(&init_user_ns, acl_e->e_uid));
     113                 :          0 :                         e += sizeof(ext4_acl_entry);
     114                 :          0 :                         break;
     115                 :          0 :                 case ACL_GROUP:
     116                 :          0 :                         entry->e_id = cpu_to_le32(
     117                 :            :                                 from_kgid(&init_user_ns, acl_e->e_gid));
     118                 :          0 :                         e += sizeof(ext4_acl_entry);
     119                 :          0 :                         break;
     120                 :            : 
     121                 :          0 :                 case ACL_USER_OBJ:
     122                 :            :                 case ACL_GROUP_OBJ:
     123                 :            :                 case ACL_MASK:
     124                 :            :                 case ACL_OTHER:
     125                 :          0 :                         e += sizeof(ext4_acl_entry_short);
     126                 :          0 :                         break;
     127                 :            : 
     128                 :          0 :                 default:
     129                 :          0 :                         goto fail;
     130                 :            :                 }
     131                 :            :         }
     132                 :            :         return (char *)ext_acl;
     133                 :            : 
     134                 :            : fail:
     135                 :          0 :         kfree(ext_acl);
     136                 :          0 :         return ERR_PTR(-EINVAL);
     137                 :            : }
     138                 :            : 
     139                 :            : /*
     140                 :            :  * Inode operation get_posix_acl().
     141                 :            :  *
     142                 :            :  * inode->i_mutex: don't care
     143                 :            :  */
     144                 :            : struct posix_acl *
     145                 :       1260 : ext4_get_acl(struct inode *inode, int type)
     146                 :            : {
     147                 :       1260 :         int name_index;
     148                 :       1260 :         char *value = NULL;
     149                 :       1260 :         struct posix_acl *acl;
     150                 :       1260 :         int retval;
     151                 :            : 
     152      [ +  -  + ]:       1260 :         switch (type) {
     153                 :            :         case ACL_TYPE_ACCESS:
     154                 :            :                 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
     155                 :            :                 break;
     156                 :        126 :         case ACL_TYPE_DEFAULT:
     157                 :        126 :                 name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
     158                 :        126 :                 break;
     159                 :          0 :         default:
     160                 :          0 :                 BUG();
     161                 :            :         }
     162                 :       1260 :         retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
     163         [ -  + ]:       1260 :         if (retval > 0) {
     164         [ #  # ]:          0 :                 value = kmalloc(retval, GFP_NOFS);
     165         [ #  # ]:          0 :                 if (!value)
     166                 :            :                         return ERR_PTR(-ENOMEM);
     167                 :          0 :                 retval = ext4_xattr_get(inode, name_index, "", value, retval);
     168                 :            :         }
     169         [ -  + ]:       1260 :         if (retval > 0)
     170                 :          0 :                 acl = ext4_acl_from_disk(value, retval);
     171         [ -  + ]:       1260 :         else if (retval == -ENODATA || retval == -ENOSYS)
     172                 :            :                 acl = NULL;
     173                 :            :         else
     174                 :          0 :                 acl = ERR_PTR(retval);
     175                 :       1260 :         kfree(value);
     176                 :            : 
     177                 :       1260 :         return acl;
     178                 :            : }
     179                 :            : 
     180                 :            : /*
     181                 :            :  * Set the access or default ACL of an inode.
     182                 :            :  *
     183                 :            :  * inode->i_mutex: down unless called from ext4_new_inode
     184                 :            :  */
     185                 :            : static int
     186                 :         42 : __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
     187                 :            :              struct posix_acl *acl, int xattr_flags)
     188                 :            : {
     189                 :         42 :         int name_index;
     190                 :         42 :         void *value = NULL;
     191                 :         42 :         size_t size = 0;
     192                 :         42 :         int error;
     193                 :            : 
     194      [ +  +  - ]:         42 :         switch (type) {
     195                 :            :         case ACL_TYPE_ACCESS:
     196                 :            :                 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
     197                 :            :                 break;
     198                 :            : 
     199                 :         21 :         case ACL_TYPE_DEFAULT:
     200                 :         21 :                 name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
     201         [ -  + ]:         21 :                 if (!S_ISDIR(inode->i_mode))
     202         [ #  # ]:          0 :                         return acl ? -EACCES : 0;
     203                 :            :                 break;
     204                 :            : 
     205                 :            :         default:
     206                 :            :                 return -EINVAL;
     207                 :            :         }
     208         [ -  + ]:         42 :         if (acl) {
     209                 :          0 :                 value = ext4_acl_to_disk(acl, &size);
     210         [ #  # ]:          0 :                 if (IS_ERR(value))
     211                 :          0 :                         return (int)PTR_ERR(value);
     212                 :            :         }
     213                 :            : 
     214                 :         42 :         error = ext4_xattr_set_handle(handle, inode, name_index, "",
     215                 :            :                                       value, size, xattr_flags);
     216                 :            : 
     217                 :         42 :         kfree(value);
     218         [ +  - ]:         42 :         if (!error) {
     219                 :         42 :                 set_cached_acl(inode, type, acl);
     220                 :            :         }
     221                 :            : 
     222                 :            :         return error;
     223                 :            : }
     224                 :            : 
     225                 :            : int
     226                 :         42 : ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
     227                 :            : {
     228                 :         42 :         handle_t *handle;
     229                 :         42 :         int error, credits, retries = 0;
     230   [ -  +  -  - ]:         42 :         size_t acl_size = acl ? ext4_acl_size(acl->a_count) : 0;
     231                 :         42 :         umode_t mode = inode->i_mode;
     232                 :         42 :         int update_mode = 0;
     233                 :            : 
     234                 :         42 :         error = dquot_initialize(inode);
     235         [ +  - ]:         42 :         if (error)
     236                 :            :                 return error;
     237                 :         42 : retry:
     238                 :         42 :         error = ext4_xattr_set_credits(inode, acl_size, false /* is_create */,
     239                 :            :                                        &credits);
     240         [ -  + ]:         42 :         if (error)
     241                 :          0 :                 return error;
     242                 :            : 
     243                 :         42 :         handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits);
     244         [ -  + ]:         42 :         if (IS_ERR(handle))
     245                 :          0 :                 return PTR_ERR(handle);
     246                 :            : 
     247         [ -  + ]:         42 :         if ((type == ACL_TYPE_ACCESS) && acl) {
     248                 :          0 :                 error = posix_acl_update_mode(inode, &mode, &acl);
     249         [ #  # ]:          0 :                 if (error)
     250                 :          0 :                         goto out_stop;
     251         [ #  # ]:          0 :                 if (mode != inode->i_mode)
     252                 :          0 :                         update_mode = 1;
     253                 :            :         }
     254                 :            : 
     255                 :         42 :         error = __ext4_set_acl(handle, inode, type, acl, 0 /* xattr_flags */);
     256         [ +  - ]:         42 :         if (!error && update_mode) {
     257                 :          0 :                 inode->i_mode = mode;
     258                 :          0 :                 inode->i_ctime = current_time(inode);
     259                 :          0 :                 ext4_mark_inode_dirty(handle, inode);
     260                 :            :         }
     261                 :         42 : out_stop:
     262                 :         42 :         ext4_journal_stop(handle);
     263   [ -  +  -  - ]:         42 :         if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
     264                 :          0 :                 goto retry;
     265                 :            :         return error;
     266                 :            : }
     267                 :            : 
     268                 :            : /*
     269                 :            :  * Initialize the ACLs of a new inode. Called from ext4_new_inode.
     270                 :            :  *
     271                 :            :  * dir->i_mutex: down
     272                 :            :  * inode->i_mutex: up (access to inode is still exclusive)
     273                 :            :  */
     274                 :            : int
     275                 :      14868 : ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
     276                 :            : {
     277                 :      14868 :         struct posix_acl *default_acl, *acl;
     278                 :      14868 :         int error;
     279                 :            : 
     280                 :      14868 :         error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
     281         [ +  - ]:      14868 :         if (error)
     282                 :            :                 return error;
     283                 :            : 
     284         [ -  + ]:      14868 :         if (default_acl) {
     285                 :          0 :                 error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT,
     286                 :            :                                        default_acl, XATTR_CREATE);
     287                 :          0 :                 posix_acl_release(default_acl);
     288                 :            :         } else {
     289                 :      14868 :                 inode->i_default_acl = NULL;
     290                 :            :         }
     291         [ -  + ]:      14868 :         if (acl) {
     292         [ #  # ]:          0 :                 if (!error)
     293                 :          0 :                         error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS,
     294                 :            :                                                acl, XATTR_CREATE);
     295                 :          0 :                 posix_acl_release(acl);
     296                 :            :         } else {
     297                 :      14868 :                 inode->i_acl = NULL;
     298                 :            :         }
     299                 :            :         return error;
     300                 :            : }

Generated by: LCOV version 1.14