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, 209 struct posix_acl *acl, struct page *ipage) 210 { 211 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 212 struct f2fs_inode_info *fi = F2FS_I(inode); 213 int name_index; 214 void *value = NULL; 215 size_t size = 0; 216 int error; 217 218 if (!test_opt(sbi, POSIX_ACL)) 219 return 0; 220 if (S_ISLNK(inode->i_mode)) 221 return -EOPNOTSUPP; 222 223 switch (type) { 224 case ACL_TYPE_ACCESS: 225 name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 226 if (acl) { 227 error = posix_acl_equiv_mode(acl, &inode->i_mode); 228 if (error < 0) 229 return error; 230 set_acl_inode(fi, inode->i_mode); 231 if (error == 0) 232 acl = NULL; 233 } 234 break; 235 236 case ACL_TYPE_DEFAULT: 237 name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 238 if (!S_ISDIR(inode->i_mode)) 239 return acl ? -EACCES : 0; 240 break; 241 242 default: 243 return -EINVAL; 244 } 245 246 if (acl) { 247 value = f2fs_acl_to_disk(acl, &size); 248 if (IS_ERR(value)) { 249 cond_clear_inode_flag(fi, FI_ACL_MODE); 250 return (int)PTR_ERR(value); 251 } 252 } 253 254 error = f2fs_setxattr(inode, name_index, "", value, size, ipage); 255 256 kfree(value); 257 if (!error) 258 set_cached_acl(inode, type, acl); 259 260 cond_clear_inode_flag(fi, FI_ACL_MODE); 261 return error; 262 } 263 264 int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage) 265 { 266 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); 267 struct posix_acl *acl = NULL; 268 int error = 0; 269 270 if (!S_ISLNK(inode->i_mode)) { 271 if (test_opt(sbi, POSIX_ACL)) { 272 acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); 273 if (IS_ERR(acl)) 274 return PTR_ERR(acl); 275 } 276 if (!acl) 277 inode->i_mode &= ~current_umask(); 278 } 279 280 if (!test_opt(sbi, POSIX_ACL) || !acl) 281 goto cleanup; 282 283 if (S_ISDIR(inode->i_mode)) { 284 error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage); 285 if (error) 286 goto cleanup; 287 } 288 error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); 289 if (error < 0) 290 return error; 291 if (error > 0) 292 error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage); 293 cleanup: 294 posix_acl_release(acl); 295 return error; 296 } 297 298 int f2fs_acl_chmod(struct inode *inode) 299 { 300 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 301 struct posix_acl *acl; 302 int error; 303 umode_t mode = get_inode_mode(inode); 304 305 if (!test_opt(sbi, POSIX_ACL)) 306 return 0; 307 if (S_ISLNK(mode)) 308 return -EOPNOTSUPP; 309 310 acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); 311 if (IS_ERR(acl) || !acl) 312 return PTR_ERR(acl); 313 314 error = posix_acl_chmod(&acl, GFP_KERNEL, mode); 315 if (error) 316 return error; 317 318 error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL); 319 posix_acl_release(acl); 320 return error; 321 } 322 323 static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, 324 size_t list_size, const char *name, size_t name_len, int type) 325 { 326 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 327 const char *xname = POSIX_ACL_XATTR_DEFAULT; 328 size_t size; 329 330 if (!test_opt(sbi, POSIX_ACL)) 331 return 0; 332 333 if (type == ACL_TYPE_ACCESS) 334 xname = POSIX_ACL_XATTR_ACCESS; 335 336 size = strlen(xname) + 1; 337 if (list && size <= list_size) 338 memcpy(list, xname, size); 339 return size; 340 } 341 342 static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, 343 void *buffer, size_t size, int type) 344 { 345 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 346 struct posix_acl *acl; 347 int error; 348 349 if (strcmp(name, "") != 0) 350 return -EINVAL; 351 if (!test_opt(sbi, POSIX_ACL)) 352 return -EOPNOTSUPP; 353 354 acl = f2fs_get_acl(dentry->d_inode, type); 355 if (IS_ERR(acl)) 356 return PTR_ERR(acl); 357 if (!acl) 358 return -ENODATA; 359 error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 360 posix_acl_release(acl); 361 362 return error; 363 } 364 365 static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, 366 const void *value, size_t size, int flags, int type) 367 { 368 struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 369 struct inode *inode = dentry->d_inode; 370 struct posix_acl *acl = NULL; 371 int error; 372 373 if (strcmp(name, "") != 0) 374 return -EINVAL; 375 if (!test_opt(sbi, POSIX_ACL)) 376 return -EOPNOTSUPP; 377 if (!inode_owner_or_capable(inode)) 378 return -EPERM; 379 380 if (value) { 381 acl = posix_acl_from_xattr(&init_user_ns, value, size); 382 if (IS_ERR(acl)) 383 return PTR_ERR(acl); 384 if (acl) { 385 error = posix_acl_valid(acl); 386 if (error) 387 goto release_and_out; 388 } 389 } else { 390 acl = NULL; 391 } 392 393 error = f2fs_set_acl(inode, type, acl, NULL); 394 395 release_and_out: 396 posix_acl_release(acl); 397 return error; 398 } 399 400 const struct xattr_handler f2fs_xattr_acl_default_handler = { 401 .prefix = POSIX_ACL_XATTR_DEFAULT, 402 .flags = ACL_TYPE_DEFAULT, 403 .list = f2fs_xattr_list_acl, 404 .get = f2fs_xattr_get_acl, 405 .set = f2fs_xattr_set_acl, 406 }; 407 408 const struct xattr_handler f2fs_xattr_acl_access_handler = { 409 .prefix = POSIX_ACL_XATTR_ACCESS, 410 .flags = ACL_TYPE_ACCESS, 411 .list = f2fs_xattr_list_acl, 412 .get = f2fs_xattr_get_acl, 413 .set = f2fs_xattr_set_acl, 414 }; 415