xattr_acl.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * linux/fs/xattr_acl.c
  3. *
  4. * Almost all from linux/fs/ext2/acl.c:
  5. * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  6. */
  7. #include <linux/export.h>
  8. #include <linux/fs.h>
  9. #include <linux/posix_acl_xattr.h>
  10. #include <linux/gfp.h>
  11. #include <linux/user_namespace.h>
  12. /*
  13. * Fix up the uids and gids in posix acl extended attributes in place.
  14. */
  15. static void posix_acl_fix_xattr_userns(
  16. struct user_namespace *to, struct user_namespace *from,
  17. void *value, size_t size)
  18. {
  19. posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
  20. posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
  21. int count;
  22. kuid_t uid;
  23. kgid_t gid;
  24. if (!value)
  25. return;
  26. if (size < sizeof(posix_acl_xattr_header))
  27. return;
  28. if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
  29. return;
  30. count = posix_acl_xattr_count(size);
  31. if (count < 0)
  32. return;
  33. if (count == 0)
  34. return;
  35. for (end = entry + count; entry != end; entry++) {
  36. switch(le16_to_cpu(entry->e_tag)) {
  37. case ACL_USER:
  38. uid = make_kuid(from, le32_to_cpu(entry->e_id));
  39. entry->e_id = cpu_to_le32(from_kuid(to, uid));
  40. break;
  41. case ACL_GROUP:
  42. gid = make_kgid(from, le32_to_cpu(entry->e_id));
  43. entry->e_id = cpu_to_le32(from_kgid(to, gid));
  44. break;
  45. default:
  46. break;
  47. }
  48. }
  49. }
  50. void posix_acl_fix_xattr_from_user(void *value, size_t size)
  51. {
  52. struct user_namespace *user_ns = current_user_ns();
  53. if (user_ns == &init_user_ns)
  54. return;
  55. posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
  56. }
  57. void posix_acl_fix_xattr_to_user(void *value, size_t size)
  58. {
  59. struct user_namespace *user_ns = current_user_ns();
  60. if (user_ns == &init_user_ns)
  61. return;
  62. posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
  63. }
  64. /*
  65. * Convert from extended attribute to in-memory representation.
  66. */
  67. struct posix_acl *
  68. posix_acl_from_xattr(struct user_namespace *user_ns,
  69. const void *value, size_t size)
  70. {
  71. posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
  72. posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
  73. int count;
  74. struct posix_acl *acl;
  75. struct posix_acl_entry *acl_e;
  76. if (!value)
  77. return NULL;
  78. if (size < sizeof(posix_acl_xattr_header))
  79. return ERR_PTR(-EINVAL);
  80. if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
  81. return ERR_PTR(-EOPNOTSUPP);
  82. count = posix_acl_xattr_count(size);
  83. if (count < 0)
  84. return ERR_PTR(-EINVAL);
  85. if (count == 0)
  86. return NULL;
  87. acl = posix_acl_alloc(count, GFP_NOFS);
  88. if (!acl)
  89. return ERR_PTR(-ENOMEM);
  90. acl_e = acl->a_entries;
  91. for (end = entry + count; entry != end; acl_e++, entry++) {
  92. acl_e->e_tag = le16_to_cpu(entry->e_tag);
  93. acl_e->e_perm = le16_to_cpu(entry->e_perm);
  94. switch(acl_e->e_tag) {
  95. case ACL_USER_OBJ:
  96. case ACL_GROUP_OBJ:
  97. case ACL_MASK:
  98. case ACL_OTHER:
  99. break;
  100. case ACL_USER:
  101. acl_e->e_uid =
  102. make_kuid(user_ns,
  103. le32_to_cpu(entry->e_id));
  104. if (!uid_valid(acl_e->e_uid))
  105. goto fail;
  106. break;
  107. case ACL_GROUP:
  108. acl_e->e_gid =
  109. make_kgid(user_ns,
  110. le32_to_cpu(entry->e_id));
  111. if (!gid_valid(acl_e->e_gid))
  112. goto fail;
  113. break;
  114. default:
  115. goto fail;
  116. }
  117. }
  118. return acl;
  119. fail:
  120. posix_acl_release(acl);
  121. return ERR_PTR(-EINVAL);
  122. }
  123. EXPORT_SYMBOL (posix_acl_from_xattr);
  124. /*
  125. * Convert from in-memory to extended attribute representation.
  126. */
  127. int
  128. posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
  129. void *buffer, size_t size)
  130. {
  131. posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
  132. posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
  133. int real_size, n;
  134. real_size = posix_acl_xattr_size(acl->a_count);
  135. if (!buffer)
  136. return real_size;
  137. if (real_size > size)
  138. return -ERANGE;
  139. ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
  140. for (n=0; n < acl->a_count; n++, ext_entry++) {
  141. const struct posix_acl_entry *acl_e = &acl->a_entries[n];
  142. ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
  143. ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
  144. switch(acl_e->e_tag) {
  145. case ACL_USER:
  146. ext_entry->e_id =
  147. cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
  148. break;
  149. case ACL_GROUP:
  150. ext_entry->e_id =
  151. cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
  152. break;
  153. default:
  154. ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
  155. break;
  156. }
  157. }
  158. return real_size;
  159. }
  160. EXPORT_SYMBOL (posix_acl_to_xattr);