1 /* 2 * fs/f2fs/acl.c 3 * 4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * 7 * Portions of this code from linux/fs/ext2/acl.c 8 * 9 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 */ 15 #include <linux/f2fs_fs.h> 16 #include "f2fs.h" 17 #include "xattr.h" 18 #include "acl.h" 19 20 #define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ 21 (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) 22 23 static inline size_t f2fs_acl_size(int count) 24 { 25 if (count <= 4) { 26 return sizeof(struct f2fs_acl_header) + 27 count * sizeof(struct f2fs_acl_entry_short); 28 } else { 29 return sizeof(struct f2fs_acl_header) + 30 4 * sizeof(struct f2fs_acl_entry_short) + 31 (count - 4) * sizeof(struct f2fs_acl_entry); 32 } 33 } 34 35 static inline int f2fs_acl_count(size_t size) 36 { 37 ssize_t s; 38 size -= sizeof(struct f2fs_acl_header); 39 s = size - 4 * sizeof(struct f2fs_acl_entry_short); 40 if (s < 0) { 41 if (size % sizeof(struct f2fs_acl_entry_short)) 42 return -1; 43 return size / sizeof(struct f2fs_acl_entry_short); 44 } else { 45 if (s % sizeof(struct f2fs_acl_entry)) 46 return -1; 47 return s / sizeof(struct f2fs_acl_entry) + 4; 48 } 49 } 50 51 static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) 52 { 53 int i, count; 54 struct posix_acl *acl; 55 struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; 56 struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); 57 const char *end = value + size; 58 59 if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) 60 return ERR_PTR(-EINVAL); 61 62 count = f2fs_acl_count(size); 63 if (count < 0) 64 return ERR_PTR(-EINVAL); 65 if (count == 0) 66 return NULL; 67 68 acl = posix_acl_alloc(count, GFP_KERNEL); 69 if (!acl) 70 return ERR_PTR(-ENOMEM); 71 72 for (i = 0; i < count; i++) { 73 74 if ((char *)entry > end) 75 goto fail; 76 77 acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); 78 acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); 79 80 switch (acl->a_entries[i].e_tag) { 81 case ACL_USER_OBJ: 82 case ACL_GROUP_OBJ: 83 case ACL_MASK: 84 case ACL_OTHER: 85 entry = (struct f2fs_acl_entry *)((char *)entry + 86 sizeof(struct f2fs_acl_entry_short)); 87 break; 88 89 case ACL_USER: 90 acl->a_entries[i].e_uid = 91 make_kuid(&init_user_ns, 92 le32_to_cpu(entry->e_id)); 93 entry = (struct f2fs_acl_entry *)((char *)entry + 94 sizeof(struct f2fs_acl_entry)); 95 break; 96 case ACL_GROUP: 97 acl->a_entries[i].e_gid = 98 make_kgid(&init_user_ns, 99 le32_to_cpu(entry->e_id)); 100 entry = (struct f2fs_acl_entry *)((char *)entry + 101 sizeof(struct f2fs_acl_entry)); 102 break; 103 default: 104 goto fail; 105 } 106 } 107 if ((char *)entry != end) 108 goto fail; 109 return acl; 110 fail: 111 posix_acl_release(acl); 112 return ERR_PTR(-EINVAL); 113 } 114 115 static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) 116 { 117 struct f2fs_acl_header *f2fs_acl; 118 struct f2fs_acl_entry *entry; 119 int i; 120 121 f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * 122 sizeof(struct f2fs_acl_entry), GFP_KERNEL); 123 if (!f2fs_acl) 124 return ERR_PTR(-ENOMEM); 125 126 f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION); 127 entry = (struct f2fs_acl_entry *)(f2fs_acl + 1); 128 129 for (i = 0; i < acl->a_count; i++) { 130 131 entry->e_tag = cpu_to_le16(acl->a_entries[i].e_tag); 132 entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm); 133 134 switch (acl->a_entries[i].e_tag) { 135 case ACL_USER: 136 entry->e_id = cpu_to_le32( 137 from_kuid(&init_user_ns, 138 acl->a_entries[i].e_uid)); 139 entry = (struct f2fs_acl_entry *)((char *)entry + 140 sizeof(struct f2fs_acl_entry)); 141 break; 142 case ACL_GROUP: 143 entry->e_id = cpu_to_le32( 144 from_kgid(&init_user_ns, 145 acl->a_entries[i].e_gid)); 146 entry = (struct f2fs_acl_entry *)((char *)entry + 147 sizeof(struct f2fs_acl_entry)); 148 break; 149 case ACL_USER_OBJ: 150 case ACL_GROUP_OBJ: 151 case ACL_MASK: 152 case ACL_OTHER: 153 entry = (struct f2fs_acl_entry *)((char *)entry + 154 sizeof(struct f2fs_acl_entry_short)); 155 break; 156 default: 157 goto fail; 158 } 159 } 160 *size = f2fs_acl_size(acl->a_count); 161 return (void *)f2fs_acl; 162 163 fail: 164 kfree(f2fs_acl); 165 return ERR_PTR(-EINVAL); 166 } 167 168 struct posix_acl *f2fs_get_acl(struct inode *inode, int type) 169 { 170 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 171 int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 172 void *value = NULL; 173 struct posix_acl *acl; 174 int retval; 175 176 if (!test_opt(sbi, POSIX_ACL)) 177 return NULL; 178 179 acl = get_cached_acl(inode, type); 180 if (acl != ACL_NOT_CACHED) 181 return acl; 182 183 if (type == ACL_TYPE_ACCESS) 184 name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 185 186 retval = f2fs_getxattr(inode, name_index, "", NULL, 0); 187 if (retval > 0) { 188 value = kmalloc(retval, GFP_KERNEL); 189 if (!value) 190 return ERR_PTR(-ENOMEM); 191 retval = f2fs_getxattr(inode, name_index, "", value, retval); 192 } 193 194 if (retval > 0) 195 acl = f2fs_acl_from_disk(value, retval); 196 else if (retval == -ENODATA) 197 acl = NULL; 198 else 199 acl = ERR_PTR(retval); 200 kfree(value); 201 202 if (!IS_ERR(acl)) 203 set_cached_acl(inode, type, acl); 204 205 return acl; 206 } 207 208 static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 209 { 210 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 211 struct f2fs_inode_info *fi = F2FS_I(inode); 212 int name_index; 213 void *value = NULL; 214 size_t size = 0; 215 int error; 216 217 if (!test_opt(sbi, POSIX_ACL)) 218 return 0; 219 if (S_ISLNK(inode->i_mode)) 220 return -EOPNOTSUPP; 221 222 switch (type) { 223 case ACL_TYPE_ACCESS: 224 name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 225 if (acl) { 226 error = posix_acl_equiv_mode(acl, &inode->i_mode); 227 if (error < 0) 228 return error; 229 set_acl_inode(fi, inode->i_mode); 230 if (error == 0) 231 acl = NULL; 232 } 233 break; 234 235 case ACL_TYPE_DEFAULT: 236 name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 237 if (!S_ISDIR(inode->i_mode)) 238 return acl ? -EACCES : 0; 239 break; 240 241 default: 242 return -EINVAL; 243 } 244 245 if (acl) { 246 value = f2fs_acl_to_disk(acl, &size); 247 if (IS_ERR(value)) { 248 cond_clear_inode_flag(fi, FI_ACL_MODE); 249 return (int)PTR_ERR(value); 250 } 251 } 252 253 error = f2fs_setxattr(inode, name_index, "", value, size, NULL); 254 255 kfree(value); 256 if (!error) 257 set_cached_acl(inode, type, acl); 258 259 cond_clear_inode_flag(fi, FI_ACL_MODE); 260 return error; 261 } 262 263 int f2fs_init_acl(struct inode *inode, struct inode *dir) 264 { 265 struct posix_acl *acl = NULL; 266 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); 267 int error = 0; 268 269 if (!S_ISLNK(inode->i_mode)) { 270 if (test_opt(sbi, POSIX_ACL)) { 271 acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); 272 if (IS_ERR(acl)) 273 return PTR_ERR(acl); 274 } 275 if (!acl) 276 inode->i_mode &= ~current_umask(); 277 } 278 279 if (test_opt(sbi, POSIX_ACL) && acl) { 280 281 if (S_ISDIR(inode->i_mode)) { 282 error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 283 if (error) 284 goto cleanup; 285 } 286 error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); 287 if (error < 0) 288 return error; 289 if (error > 0) 290 error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); 291 } 292 cleanup: 293 posix_acl_release(acl); 294 return error; 295 } 296 297 int f2fs_acl_chmod(struct inode *inode) 298 { 299 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 300 struct posix_acl *acl; 301 int error; 302 umode_t mode = get_inode_mode(inode); 303 304 if (!test_opt(sbi, POSIX_ACL)) 305 return 0; 306 if (S_ISLNK(mode)) 307 return -EOPNOTSUPP; 308 309 acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); 310 if (IS_ERR(acl) || !acl) 311 return PTR_ERR(acl); 312 313 error = posix_acl_chmod(&acl, GFP_KERNEL, mode); 314 if (error) 315 return error; 316 error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); 317 posix_acl_release(acl); 318 return error; 319 } 320 321 static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, 322 size_t list_size, const char *name, size_t name_len, int type) 323 { 324 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 325 const char *xname = POSIX_ACL_XATTR_DEFAULT; 326 size_t size; 327 328 if (!test_opt(sbi, POSIX_ACL)) 329 return 0; 330 331 if (type == ACL_TYPE_ACCESS) 332 xname = POSIX_ACL_XATTR_ACCESS; 333 334 size = strlen(xname) + 1; 335 if (list && size <= list_size) 336 memcpy(list, xname, size); 337 return size; 338 } 339 340 static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, 341 void *buffer, size_t size, int type) 342 { 343 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 344 struct posix_acl *acl; 345 int error; 346 347 if (strcmp(name, "") != 0) 348 return -EINVAL; 349 if (!test_opt(sbi, POSIX_ACL)) 350 return -EOPNOTSUPP; 351 352 acl = f2fs_get_acl(dentry->d_inode, type); 353 if (IS_ERR(acl)) 354 return PTR_ERR(acl); 355 if (!acl) 356 return -ENODATA; 357 error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 358 posix_acl_release(acl); 359 360 return error; 361 } 362 363 static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, 364 const void *value, size_t size, int flags, int type) 365 { 366 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 367 struct inode *inode = dentry->d_inode; 368 struct posix_acl *acl = NULL; 369 int error; 370 371 if (strcmp(name, "") != 0) 372 return -EINVAL; 373 if (!test_opt(sbi, POSIX_ACL)) 374 return -EOPNOTSUPP; 375 if (!inode_owner_or_capable(inode)) 376 return -EPERM; 377 378 if (value) { 379 acl = posix_acl_from_xattr(&init_user_ns, value, size); 380 if (IS_ERR(acl)) 381 return PTR_ERR(acl); 382 if (acl) { 383 error = posix_acl_valid(acl); 384 if (error) 385 goto release_and_out; 386 } 387 } else { 388 acl = NULL; 389 } 390 391 error = f2fs_set_acl(inode, type, acl); 392 393 release_and_out: 394 posix_acl_release(acl); 395 return error; 396 } 397 398 const struct xattr_handler f2fs_xattr_acl_default_handler = { 399 .prefix = POSIX_ACL_XATTR_DEFAULT, 400 .flags = ACL_TYPE_DEFAULT, 401 .list = f2fs_xattr_list_acl, 402 .get = f2fs_xattr_get_acl, 403 .set = f2fs_xattr_set_acl, 404 }; 405 406 const struct xattr_handler f2fs_xattr_acl_access_handler = { 407 .prefix = POSIX_ACL_XATTR_ACCESS, 408 .flags = ACL_TYPE_ACCESS, 409 .list = f2fs_xattr_list_acl, 410 .get = f2fs_xattr_get_acl, 411 .set = f2fs_xattr_set_acl, 412 }; 413