root/fs/ext2/acl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ext2_acl_from_disk
  2. ext2_acl_to_disk
  3. ext2_get_acl
  4. __ext2_set_acl
  5. ext2_set_acl
  6. ext2_init_acl

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * linux/fs/ext2/acl.c
   4  *
   5  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
   6  */
   7 
   8 #include <linux/init.h>
   9 #include <linux/sched.h>
  10 #include <linux/slab.h>
  11 #include <linux/fs.h>
  12 #include "ext2.h"
  13 #include "xattr.h"
  14 #include "acl.h"
  15 
  16 /*
  17  * Convert from filesystem to in-memory representation.
  18  */
  19 static struct posix_acl *
  20 ext2_acl_from_disk(const void *value, size_t size)
  21 {
  22         const char *end = (char *)value + size;
  23         int n, count;
  24         struct posix_acl *acl;
  25 
  26         if (!value)
  27                 return NULL;
  28         if (size < sizeof(ext2_acl_header))
  29                  return ERR_PTR(-EINVAL);
  30         if (((ext2_acl_header *)value)->a_version !=
  31             cpu_to_le32(EXT2_ACL_VERSION))
  32                 return ERR_PTR(-EINVAL);
  33         value = (char *)value + sizeof(ext2_acl_header);
  34         count = ext2_acl_count(size);
  35         if (count < 0)
  36                 return ERR_PTR(-EINVAL);
  37         if (count == 0)
  38                 return NULL;
  39         acl = posix_acl_alloc(count, GFP_KERNEL);
  40         if (!acl)
  41                 return ERR_PTR(-ENOMEM);
  42         for (n=0; n < count; n++) {
  43                 ext2_acl_entry *entry =
  44                         (ext2_acl_entry *)value;
  45                 if ((char *)value + sizeof(ext2_acl_entry_short) > end)
  46                         goto fail;
  47                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
  48                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
  49                 switch(acl->a_entries[n].e_tag) {
  50                         case ACL_USER_OBJ:
  51                         case ACL_GROUP_OBJ:
  52                         case ACL_MASK:
  53                         case ACL_OTHER:
  54                                 value = (char *)value +
  55                                         sizeof(ext2_acl_entry_short);
  56                                 break;
  57 
  58                         case ACL_USER:
  59                                 value = (char *)value + sizeof(ext2_acl_entry);
  60                                 if ((char *)value > end)
  61                                         goto fail;
  62                                 acl->a_entries[n].e_uid =
  63                                         make_kuid(&init_user_ns,
  64                                                   le32_to_cpu(entry->e_id));
  65                                 break;
  66                         case ACL_GROUP:
  67                                 value = (char *)value + sizeof(ext2_acl_entry);
  68                                 if ((char *)value > end)
  69                                         goto fail;
  70                                 acl->a_entries[n].e_gid =
  71                                         make_kgid(&init_user_ns,
  72                                                   le32_to_cpu(entry->e_id));
  73                                 break;
  74 
  75                         default:
  76                                 goto fail;
  77                 }
  78         }
  79         if (value != end)
  80                 goto fail;
  81         return acl;
  82 
  83 fail:
  84         posix_acl_release(acl);
  85         return ERR_PTR(-EINVAL);
  86 }
  87 
  88 /*
  89  * Convert from in-memory to filesystem representation.
  90  */
  91 static void *
  92 ext2_acl_to_disk(const struct posix_acl *acl, size_t *size)
  93 {
  94         ext2_acl_header *ext_acl;
  95         char *e;
  96         size_t n;
  97 
  98         *size = ext2_acl_size(acl->a_count);
  99         ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count *
 100                         sizeof(ext2_acl_entry), GFP_KERNEL);
 101         if (!ext_acl)
 102                 return ERR_PTR(-ENOMEM);
 103         ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION);
 104         e = (char *)ext_acl + sizeof(ext2_acl_header);
 105         for (n=0; n < acl->a_count; n++) {
 106                 const struct posix_acl_entry *acl_e = &acl->a_entries[n];
 107                 ext2_acl_entry *entry = (ext2_acl_entry *)e;
 108                 entry->e_tag  = cpu_to_le16(acl_e->e_tag);
 109                 entry->e_perm = cpu_to_le16(acl_e->e_perm);
 110                 switch(acl_e->e_tag) {
 111                         case ACL_USER:
 112                                 entry->e_id = cpu_to_le32(
 113                                         from_kuid(&init_user_ns, acl_e->e_uid));
 114                                 e += sizeof(ext2_acl_entry);
 115                                 break;
 116                         case ACL_GROUP:
 117                                 entry->e_id = cpu_to_le32(
 118                                         from_kgid(&init_user_ns, acl_e->e_gid));
 119                                 e += sizeof(ext2_acl_entry);
 120                                 break;
 121 
 122                         case ACL_USER_OBJ:
 123                         case ACL_GROUP_OBJ:
 124                         case ACL_MASK:
 125                         case ACL_OTHER:
 126                                 e += sizeof(ext2_acl_entry_short);
 127                                 break;
 128 
 129                         default:
 130                                 goto fail;
 131                 }
 132         }
 133         return (char *)ext_acl;
 134 
 135 fail:
 136         kfree(ext_acl);
 137         return ERR_PTR(-EINVAL);
 138 }
 139 
 140 /*
 141  * inode->i_mutex: don't care
 142  */
 143 struct posix_acl *
 144 ext2_get_acl(struct inode *inode, int type)
 145 {
 146         int name_index;
 147         char *value = NULL;
 148         struct posix_acl *acl;
 149         int retval;
 150 
 151         switch (type) {
 152         case ACL_TYPE_ACCESS:
 153                 name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
 154                 break;
 155         case ACL_TYPE_DEFAULT:
 156                 name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
 157                 break;
 158         default:
 159                 BUG();
 160         }
 161         retval = ext2_xattr_get(inode, name_index, "", NULL, 0);
 162         if (retval > 0) {
 163                 value = kmalloc(retval, GFP_KERNEL);
 164                 if (!value)
 165                         return ERR_PTR(-ENOMEM);
 166                 retval = ext2_xattr_get(inode, name_index, "", value, retval);
 167         }
 168         if (retval > 0)
 169                 acl = ext2_acl_from_disk(value, retval);
 170         else if (retval == -ENODATA || retval == -ENOSYS)
 171                 acl = NULL;
 172         else
 173                 acl = ERR_PTR(retval);
 174         kfree(value);
 175 
 176         return acl;
 177 }
 178 
 179 static int
 180 __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 181 {
 182         int name_index;
 183         void *value = NULL;
 184         size_t size = 0;
 185         int error;
 186 
 187         switch(type) {
 188                 case ACL_TYPE_ACCESS:
 189                         name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
 190                         break;
 191 
 192                 case ACL_TYPE_DEFAULT:
 193                         name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT;
 194                         if (!S_ISDIR(inode->i_mode))
 195                                 return acl ? -EACCES : 0;
 196                         break;
 197 
 198                 default:
 199                         return -EINVAL;
 200         }
 201         if (acl) {
 202                 value = ext2_acl_to_disk(acl, &size);
 203                 if (IS_ERR(value))
 204                         return (int)PTR_ERR(value);
 205         }
 206 
 207         error = ext2_xattr_set(inode, name_index, "", value, size, 0);
 208 
 209         kfree(value);
 210         if (!error)
 211                 set_cached_acl(inode, type, acl);
 212         return error;
 213 }
 214 
 215 /*
 216  * inode->i_mutex: down
 217  */
 218 int
 219 ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 220 {
 221         int error;
 222         int update_mode = 0;
 223         umode_t mode = inode->i_mode;
 224 
 225         if (type == ACL_TYPE_ACCESS && acl) {
 226                 error = posix_acl_update_mode(inode, &mode, &acl);
 227                 if (error)
 228                         return error;
 229                 update_mode = 1;
 230         }
 231         error = __ext2_set_acl(inode, acl, type);
 232         if (!error && update_mode) {
 233                 inode->i_mode = mode;
 234                 inode->i_ctime = current_time(inode);
 235                 mark_inode_dirty(inode);
 236         }
 237         return error;
 238 }
 239 
 240 /*
 241  * Initialize the ACLs of a new inode. Called from ext2_new_inode.
 242  *
 243  * dir->i_mutex: down
 244  * inode->i_mutex: up (access to inode is still exclusive)
 245  */
 246 int
 247 ext2_init_acl(struct inode *inode, struct inode *dir)
 248 {
 249         struct posix_acl *default_acl, *acl;
 250         int error;
 251 
 252         error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
 253         if (error)
 254                 return error;
 255 
 256         if (default_acl) {
 257                 error = __ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
 258                 posix_acl_release(default_acl);
 259         } else {
 260                 inode->i_default_acl = NULL;
 261         }
 262         if (acl) {
 263                 if (!error)
 264                         error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
 265                 posix_acl_release(acl);
 266         } else {
 267                 inode->i_acl = NULL;
 268         }
 269         return error;
 270 }

/* [<][>][^][v][top][bottom][index][help] */