1 /* 2 * JFFS2 -- Journalling Flash File System, Version 2. 3 * 4 * Copyright (C) 2006 NEC Corporation 5 * 6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> 7 * 8 * For licensing information, see the file 'LICENCE' in this directory. 9 * 10 */ 11 #include <linux/kernel.h> 12 #include <linux/slab.h> 13 #include <linux/fs.h> 14 #include <linux/time.h> 15 #include <linux/crc32.h> 16 #include <linux/jffs2.h> 17 #include <linux/xattr.h> 18 #include <linux/posix_acl_xattr.h> 19 #include <linux/mtd/mtd.h> 20 #include "nodelist.h" 21 22 static size_t jffs2_acl_size(int count) 23 { 24 if (count <= 4) { 25 return sizeof(struct jffs2_acl_header) 26 + count * sizeof(struct jffs2_acl_entry_short); 27 } else { 28 return sizeof(struct jffs2_acl_header) 29 + 4 * sizeof(struct jffs2_acl_entry_short) 30 + (count - 4) * sizeof(struct jffs2_acl_entry); 31 } 32 } 33 34 static int jffs2_acl_count(size_t size) 35 { 36 size_t s; 37 38 size -= sizeof(struct jffs2_acl_header); 39 s = size - 4 * sizeof(struct jffs2_acl_entry_short); 40 if (s < 0) { 41 if (size % sizeof(struct jffs2_acl_entry_short)) 42 return -1; 43 return size / sizeof(struct jffs2_acl_entry_short); 44 } else { 45 if (s % sizeof(struct jffs2_acl_entry)) 46 return -1; 47 return s / sizeof(struct jffs2_acl_entry) + 4; 48 } 49 } 50 51 static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size) 52 { 53 void *end = value + size; 54 struct jffs2_acl_header *header = value; 55 struct jffs2_acl_entry *entry; 56 struct posix_acl *acl; 57 uint32_t ver; 58 int i, count; 59 60 if (!value) 61 return NULL; 62 if (size < sizeof(struct jffs2_acl_header)) 63 return ERR_PTR(-EINVAL); 64 ver = je32_to_cpu(header->a_version); 65 if (ver != JFFS2_ACL_VERSION) { 66 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver); 67 return ERR_PTR(-EINVAL); 68 } 69 70 value += sizeof(struct jffs2_acl_header); 71 count = jffs2_acl_count(size); 72 if (count < 0) 73 return ERR_PTR(-EINVAL); 74 if (count == 0) 75 return NULL; 76 77 acl = posix_acl_alloc(count, GFP_KERNEL); 78 if (!acl) 79 return ERR_PTR(-ENOMEM); 80 81 for (i=0; i < count; i++) { 82 entry = value; 83 if (value + sizeof(struct jffs2_acl_entry_short) > end) 84 goto fail; 85 acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag); 86 acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm); 87 switch (acl->a_entries[i].e_tag) { 88 case ACL_USER_OBJ: 89 case ACL_GROUP_OBJ: 90 case ACL_MASK: 91 case ACL_OTHER: 92 value += sizeof(struct jffs2_acl_entry_short); 93 acl->a_entries[i].e_id = ACL_UNDEFINED_ID; 94 break; 95 96 case ACL_USER: 97 case ACL_GROUP: 98 value += sizeof(struct jffs2_acl_entry); 99 if (value > end) 100 goto fail; 101 acl->a_entries[i].e_id = je32_to_cpu(entry->e_id); 102 break; 103 104 default: 105 goto fail; 106 } 107 } 108 if (value != end) 109 goto fail; 110 return acl; 111 fail: 112 posix_acl_release(acl); 113 return ERR_PTR(-EINVAL); 114 } 115 116 static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) 117 { 118 struct jffs2_acl_header *header; 119 struct jffs2_acl_entry *entry; 120 void *e; 121 size_t i; 122 123 *size = jffs2_acl_size(acl->a_count); 124 header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL); 125 if (!header) 126 return ERR_PTR(-ENOMEM); 127 header->a_version = cpu_to_je32(JFFS2_ACL_VERSION); 128 e = header + 1; 129 for (i=0; i < acl->a_count; i++) { 130 entry = e; 131 entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag); 132 entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm); 133 switch(acl->a_entries[i].e_tag) { 134 case ACL_USER: 135 case ACL_GROUP: 136 entry->e_id = cpu_to_je32(acl->a_entries[i].e_id); 137 e += sizeof(struct jffs2_acl_entry); 138 break; 139 140 case ACL_USER_OBJ: 141 case ACL_GROUP_OBJ: 142 case ACL_MASK: 143 case ACL_OTHER: 144 e += sizeof(struct jffs2_acl_entry_short); 145 break; 146 147 default: 148 goto fail; 149 } 150 } 151 return header; 152 fail: 153 kfree(header); 154 return ERR_PTR(-EINVAL); 155 } 156 157 static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl) 158 { 159 struct posix_acl *acl = JFFS2_ACL_NOT_CACHED; 160 161 spin_lock(&inode->i_lock); 162 if (*i_acl != JFFS2_ACL_NOT_CACHED) 163 acl = posix_acl_dup(*i_acl); 164 spin_unlock(&inode->i_lock); 165 return acl; 166 } 167 168 static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) 169 { 170 spin_lock(&inode->i_lock); 171 if (*i_acl != JFFS2_ACL_NOT_CACHED) 172 posix_acl_release(*i_acl); 173 *i_acl = posix_acl_dup(acl); 174 spin_unlock(&inode->i_lock); 175 } 176 177 static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) 178 { 179 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 180 struct posix_acl *acl; 181 char *value = NULL; 182 int rc, xprefix; 183 184 switch (type) { 185 case ACL_TYPE_ACCESS: 186 acl = jffs2_iget_acl(inode, &f->i_acl_access); 187 if (acl != JFFS2_ACL_NOT_CACHED) 188 return acl; 189 xprefix = JFFS2_XPREFIX_ACL_ACCESS; 190 break; 191 case ACL_TYPE_DEFAULT: 192 acl = jffs2_iget_acl(inode, &f->i_acl_default); 193 if (acl != JFFS2_ACL_NOT_CACHED) 194 return acl; 195 xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 196 break; 197 default: 198 return ERR_PTR(-EINVAL); 199 } 200 rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); 201 if (rc > 0) { 202 value = kmalloc(rc, GFP_KERNEL); 203 if (!value) 204 return ERR_PTR(-ENOMEM); 205 rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); 206 } 207 if (rc > 0) { 208 acl = jffs2_acl_from_medium(value, rc); 209 } else if (rc == -ENODATA || rc == -ENOSYS) { 210 acl = NULL; 211 } else { 212 acl = ERR_PTR(rc); 213 } 214 if (value) 215 kfree(value); 216 if (!IS_ERR(acl)) { 217 switch (type) { 218 case ACL_TYPE_ACCESS: 219 jffs2_iset_acl(inode, &f->i_acl_access, acl); 220 break; 221 case ACL_TYPE_DEFAULT: 222 jffs2_iset_acl(inode, &f->i_acl_default, acl); 223 break; 224 } 225 } 226 return acl; 227 } 228 229 static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) 230 { 231 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 232 size_t size = 0; 233 char *value = NULL; 234 int rc, xprefix; 235 236 if (S_ISLNK(inode->i_mode)) 237 return -EOPNOTSUPP; 238 239 switch (type) { 240 case ACL_TYPE_ACCESS: 241 xprefix = JFFS2_XPREFIX_ACL_ACCESS; 242 if (acl) { 243 mode_t mode = inode->i_mode; 244 rc = posix_acl_equiv_mode(acl, &mode); 245 if (rc < 0) 246 return rc; 247 if (inode->i_mode != mode) { 248 inode->i_mode = mode; 249 jffs2_dirty_inode(inode); 250 } 251 if (rc == 0) 252 acl = NULL; 253 } 254 break; 255 case ACL_TYPE_DEFAULT: 256 xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 257 if (!S_ISDIR(inode->i_mode)) 258 return acl ? -EACCES : 0; 259 break; 260 default: 261 return -EINVAL; 262 } 263 if (acl) { 264 value = jffs2_acl_to_medium(acl, &size); 265 if (IS_ERR(value)) 266 return PTR_ERR(value); 267 } 268 269 rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); 270 if (!value && rc == -ENODATA) 271 rc = 0; 272 if (value) 273 kfree(value); 274 if (!rc) { 275 switch(type) { 276 case ACL_TYPE_ACCESS: 277 jffs2_iset_acl(inode, &f->i_acl_access, acl); 278 break; 279 case ACL_TYPE_DEFAULT: 280 jffs2_iset_acl(inode, &f->i_acl_default, acl); 281 break; 282 } 283 } 284 return rc; 285 } 286 287 static int jffs2_check_acl(struct inode *inode, int mask) 288 { 289 struct posix_acl *acl; 290 int rc; 291 292 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 293 if (IS_ERR(acl)) 294 return PTR_ERR(acl); 295 if (acl) { 296 rc = posix_acl_permission(inode, acl, mask); 297 posix_acl_release(acl); 298 return rc; 299 } 300 return -EAGAIN; 301 } 302 303 int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) 304 { 305 return generic_permission(inode, mask, jffs2_check_acl); 306 } 307 308 int jffs2_init_acl(struct inode *inode, struct inode *dir) 309 { 310 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 311 struct posix_acl *acl = NULL, *clone; 312 mode_t mode; 313 int rc = 0; 314 315 f->i_acl_access = JFFS2_ACL_NOT_CACHED; 316 f->i_acl_default = JFFS2_ACL_NOT_CACHED; 317 if (!S_ISLNK(inode->i_mode)) { 318 acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); 319 if (IS_ERR(acl)) 320 return PTR_ERR(acl); 321 if (!acl) 322 inode->i_mode &= ~current->fs->umask; 323 } 324 if (acl) { 325 if (S_ISDIR(inode->i_mode)) { 326 rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); 327 if (rc) 328 goto cleanup; 329 } 330 clone = posix_acl_clone(acl, GFP_KERNEL); 331 rc = -ENOMEM; 332 if (!clone) 333 goto cleanup; 334 mode = inode->i_mode; 335 rc = posix_acl_create_masq(clone, &mode); 336 if (rc >= 0) { 337 inode->i_mode = mode; 338 if (rc > 0) 339 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); 340 } 341 posix_acl_release(clone); 342 } 343 cleanup: 344 posix_acl_release(acl); 345 return rc; 346 } 347 348 void jffs2_clear_acl(struct inode *inode) 349 { 350 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 351 352 if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) { 353 posix_acl_release(f->i_acl_access); 354 f->i_acl_access = JFFS2_ACL_NOT_CACHED; 355 } 356 if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) { 357 posix_acl_release(f->i_acl_default); 358 f->i_acl_default = JFFS2_ACL_NOT_CACHED; 359 } 360 } 361 362 int jffs2_acl_chmod(struct inode *inode) 363 { 364 struct posix_acl *acl, *clone; 365 int rc; 366 367 if (S_ISLNK(inode->i_mode)) 368 return -EOPNOTSUPP; 369 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 370 if (IS_ERR(acl) || !acl) 371 return PTR_ERR(acl); 372 clone = posix_acl_clone(acl, GFP_KERNEL); 373 posix_acl_release(acl); 374 if (!clone) 375 return -ENOMEM; 376 rc = posix_acl_chmod_masq(clone, inode->i_mode); 377 if (!rc) 378 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); 379 posix_acl_release(clone); 380 return rc; 381 } 382 383 static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size, 384 const char *name, size_t name_len) 385 { 386 const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); 387 388 if (list && retlen <= list_size) 389 strcpy(list, POSIX_ACL_XATTR_ACCESS); 390 return retlen; 391 } 392 393 static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size, 394 const char *name, size_t name_len) 395 { 396 const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); 397 398 if (list && retlen <= list_size) 399 strcpy(list, POSIX_ACL_XATTR_DEFAULT); 400 return retlen; 401 } 402 403 static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size) 404 { 405 struct posix_acl *acl; 406 int rc; 407 408 acl = jffs2_get_acl(inode, type); 409 if (IS_ERR(acl)) 410 return PTR_ERR(acl); 411 if (!acl) 412 return -ENODATA; 413 rc = posix_acl_to_xattr(acl, buffer, size); 414 posix_acl_release(acl); 415 416 return rc; 417 } 418 419 static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) 420 { 421 if (name[0] != '\0') 422 return -EINVAL; 423 return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size); 424 } 425 426 static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) 427 { 428 if (name[0] != '\0') 429 return -EINVAL; 430 return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size); 431 } 432 433 static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size) 434 { 435 struct posix_acl *acl; 436 int rc; 437 438 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 439 return -EPERM; 440 441 if (value) { 442 acl = posix_acl_from_xattr(value, size); 443 if (IS_ERR(acl)) 444 return PTR_ERR(acl); 445 if (acl) { 446 rc = posix_acl_valid(acl); 447 if (rc) 448 goto out; 449 } 450 } else { 451 acl = NULL; 452 } 453 rc = jffs2_set_acl(inode, type, acl); 454 out: 455 posix_acl_release(acl); 456 return rc; 457 } 458 459 static int jffs2_acl_access_setxattr(struct inode *inode, const char *name, 460 const void *buffer, size_t size, int flags) 461 { 462 if (name[0] != '\0') 463 return -EINVAL; 464 return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size); 465 } 466 467 static int jffs2_acl_default_setxattr(struct inode *inode, const char *name, 468 const void *buffer, size_t size, int flags) 469 { 470 if (name[0] != '\0') 471 return -EINVAL; 472 return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size); 473 } 474 475 struct xattr_handler jffs2_acl_access_xattr_handler = { 476 .prefix = POSIX_ACL_XATTR_ACCESS, 477 .list = jffs2_acl_access_listxattr, 478 .get = jffs2_acl_access_getxattr, 479 .set = jffs2_acl_access_setxattr, 480 }; 481 482 struct xattr_handler jffs2_acl_default_xattr_handler = { 483 .prefix = POSIX_ACL_XATTR_DEFAULT, 484 .list = jffs2_acl_default_listxattr, 485 .get = jffs2_acl_default_getxattr, 486 .set = jffs2_acl_default_setxattr, 487 }; 488