040-backport_tmpfs_xattr.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. --- a/fs/Kconfig
  2. +++ b/fs/Kconfig
  3. @@ -121,9 +121,25 @@ config TMPFS
  4. See <file:Documentation/filesystems/tmpfs.txt> for details.
  5. +config TMPFS_XATTR
  6. + bool "Tmpfs extended attributes"
  7. + depends on TMPFS
  8. + default n
  9. + help
  10. + Extended attributes are name:value pairs associated with inodes by
  11. + the kernel or by users (see the attr(5) manual page, or visit
  12. + <http://acl.bestbits.at/> for details).
  13. +
  14. + Currently this enables support for the trusted.* and
  15. + security.* namespaces.
  16. +
  17. + If unsure, say N.
  18. +
  19. + You need this for POSIX ACL support on tmpfs.
  20. +
  21. config TMPFS_POSIX_ACL
  22. bool "Tmpfs POSIX Access Control Lists"
  23. - depends on TMPFS
  24. + depends on TMPFS_XATTR
  25. select GENERIC_ACL
  26. help
  27. POSIX Access Control Lists (ACLs) support permissions for users and
  28. --- a/include/linux/shmem_fs.h
  29. +++ b/include/linux/shmem_fs.h
  30. @@ -9,6 +9,8 @@
  31. #define SHMEM_NR_DIRECT 16
  32. +#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
  33. +
  34. struct shmem_inode_info {
  35. spinlock_t lock;
  36. unsigned long flags;
  37. @@ -17,8 +19,12 @@ struct shmem_inode_info {
  38. unsigned long next_index; /* highest alloced index + 1 */
  39. struct shared_policy policy; /* NUMA memory alloc policy */
  40. struct page *i_indirect; /* top indirect blocks page */
  41. - swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
  42. + union {
  43. + swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
  44. + char inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
  45. + };
  46. struct list_head swaplist; /* chain of maybes on swap */
  47. + struct list_head xattr_list; /* list of shmem_xattr */
  48. struct inode vfs_inode;
  49. };
  50. --- a/mm/shmem.c
  51. +++ b/mm/shmem.c
  52. @@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
  53. /* Pretend that each entry is of this size in directory's i_size */
  54. #define BOGO_DIRENT_SIZE 20
  55. +struct shmem_xattr {
  56. + struct list_head list; /* anchored by shmem_inode_info->xattr_list */
  57. + char *name; /* xattr name */
  58. + size_t size;
  59. + char value[0];
  60. +};
  61. +
  62. /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
  63. enum sgp_type {
  64. SGP_READ, /* don't exceed i_size, don't allocate page */
  65. @@ -822,6 +829,7 @@ static int shmem_notify_change(struct de
  66. static void shmem_evict_inode(struct inode *inode)
  67. {
  68. struct shmem_inode_info *info = SHMEM_I(inode);
  69. + struct shmem_xattr *xattr, *nxattr;
  70. if (inode->i_mapping->a_ops == &shmem_aops) {
  71. truncate_inode_pages(inode->i_mapping, 0);
  72. @@ -834,6 +842,11 @@ static void shmem_evict_inode(struct ino
  73. mutex_unlock(&shmem_swaplist_mutex);
  74. }
  75. }
  76. +
  77. + list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
  78. + kfree(xattr->name);
  79. + kfree(xattr);
  80. + }
  81. BUG_ON(inode->i_blocks);
  82. shmem_free_inode(inode->i_sb);
  83. end_writeback(inode);
  84. @@ -1615,6 +1628,7 @@ static struct inode *shmem_get_inode(str
  85. spin_lock_init(&info->lock);
  86. info->flags = flags & VM_NORESERVE;
  87. INIT_LIST_HEAD(&info->swaplist);
  88. + INIT_LIST_HEAD(&info->xattr_list);
  89. cache_no_acl(inode);
  90. switch (mode & S_IFMT) {
  91. @@ -2014,9 +2028,9 @@ static int shmem_symlink(struct inode *d
  92. info = SHMEM_I(inode);
  93. inode->i_size = len-1;
  94. - if (len <= (char *)inode - (char *)info) {
  95. + if (len <= SHMEM_SYMLINK_INLINE_LEN) {
  96. /* do it inline */
  97. - memcpy(info, symname, len);
  98. + memcpy(info->inline_symlink, symname, len);
  99. inode->i_op = &shmem_symlink_inline_operations;
  100. } else {
  101. error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
  102. @@ -2042,7 +2056,7 @@ static int shmem_symlink(struct inode *d
  103. static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
  104. {
  105. - nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
  106. + nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
  107. return NULL;
  108. }
  109. @@ -2066,63 +2080,253 @@ static void shmem_put_link(struct dentry
  110. }
  111. }
  112. -static const struct inode_operations shmem_symlink_inline_operations = {
  113. - .readlink = generic_readlink,
  114. - .follow_link = shmem_follow_link_inline,
  115. -};
  116. -
  117. -static const struct inode_operations shmem_symlink_inode_operations = {
  118. - .readlink = generic_readlink,
  119. - .follow_link = shmem_follow_link,
  120. - .put_link = shmem_put_link,
  121. -};
  122. -
  123. -#ifdef CONFIG_TMPFS_POSIX_ACL
  124. +#ifdef CONFIG_TMPFS_XATTR
  125. /*
  126. - * Superblocks without xattr inode operations will get security.* xattr
  127. - * support from the VFS "for free". As soon as we have any other xattrs
  128. + * Superblocks without xattr inode operations may get some security.* xattr
  129. + * support from the LSM "for free". As soon as we have any other xattrs
  130. * like ACLs, we also need to implement the security.* handlers at
  131. * filesystem level, though.
  132. */
  133. -static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
  134. - size_t list_len, const char *name,
  135. - size_t name_len, int handler_flags)
  136. +static int shmem_xattr_get(struct dentry *dentry, const char *name,
  137. + void *buffer, size_t size)
  138. {
  139. - return security_inode_listsecurity(dentry->d_inode, list, list_len);
  140. -}
  141. + struct shmem_inode_info *info;
  142. + struct shmem_xattr *xattr;
  143. + int ret = -ENODATA;
  144. -static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
  145. - void *buffer, size_t size, int handler_flags)
  146. -{
  147. - if (strcmp(name, "") == 0)
  148. - return -EINVAL;
  149. - return xattr_getsecurity(dentry->d_inode, name, buffer, size);
  150. + info = SHMEM_I(dentry->d_inode);
  151. +
  152. + spin_lock(&info->lock);
  153. + list_for_each_entry(xattr, &info->xattr_list, list) {
  154. + if (strcmp(name, xattr->name))
  155. + continue;
  156. +
  157. + ret = xattr->size;
  158. + if (buffer) {
  159. + if (size < xattr->size)
  160. + ret = -ERANGE;
  161. + else
  162. + memcpy(buffer, xattr->value, xattr->size);
  163. + }
  164. + break;
  165. + }
  166. + spin_unlock(&info->lock);
  167. + return ret;
  168. }
  169. -static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
  170. - const void *value, size_t size, int flags, int handler_flags)
  171. +static int shmem_xattr_set(struct dentry *dentry, const char *name,
  172. + const void *value, size_t size, int flags)
  173. {
  174. - if (strcmp(name, "") == 0)
  175. - return -EINVAL;
  176. - return security_inode_setsecurity(dentry->d_inode, name, value,
  177. - size, flags);
  178. + struct inode *inode = dentry->d_inode;
  179. + struct shmem_inode_info *info = SHMEM_I(inode);
  180. + struct shmem_xattr *xattr;
  181. + struct shmem_xattr *new_xattr = NULL;
  182. + size_t len;
  183. + int err = 0;
  184. +
  185. + /* value == NULL means remove */
  186. + if (value) {
  187. + /* wrap around? */
  188. + len = sizeof(*new_xattr) + size;
  189. + if (len <= sizeof(*new_xattr))
  190. + return -ENOMEM;
  191. +
  192. + new_xattr = kmalloc(len, GFP_KERNEL);
  193. + if (!new_xattr)
  194. + return -ENOMEM;
  195. +
  196. + new_xattr->name = kstrdup(name, GFP_KERNEL);
  197. + if (!new_xattr->name) {
  198. + kfree(new_xattr);
  199. + return -ENOMEM;
  200. + }
  201. +
  202. + new_xattr->size = size;
  203. + memcpy(new_xattr->value, value, size);
  204. + }
  205. +
  206. + spin_lock(&info->lock);
  207. + list_for_each_entry(xattr, &info->xattr_list, list) {
  208. + if (!strcmp(name, xattr->name)) {
  209. + if (flags & XATTR_CREATE) {
  210. + xattr = new_xattr;
  211. + err = -EEXIST;
  212. + } else if (new_xattr) {
  213. + list_replace(&xattr->list, &new_xattr->list);
  214. + } else {
  215. + list_del(&xattr->list);
  216. + }
  217. + goto out;
  218. + }
  219. + }
  220. + if (flags & XATTR_REPLACE) {
  221. + xattr = new_xattr;
  222. + err = -ENODATA;
  223. + } else {
  224. + list_add(&new_xattr->list, &info->xattr_list);
  225. + xattr = NULL;
  226. + }
  227. +out:
  228. + spin_unlock(&info->lock);
  229. + if (xattr)
  230. + kfree(xattr->name);
  231. + kfree(xattr);
  232. + return err;
  233. }
  234. -static const struct xattr_handler shmem_xattr_security_handler = {
  235. - .prefix = XATTR_SECURITY_PREFIX,
  236. - .list = shmem_xattr_security_list,
  237. - .get = shmem_xattr_security_get,
  238. - .set = shmem_xattr_security_set,
  239. -};
  240. static const struct xattr_handler *shmem_xattr_handlers[] = {
  241. +#ifdef CONFIG_TMPFS_POSIX_ACL
  242. &generic_acl_access_handler,
  243. &generic_acl_default_handler,
  244. - &shmem_xattr_security_handler,
  245. +#endif
  246. NULL
  247. };
  248. +
  249. +static int shmem_xattr_validate(const char *name)
  250. +{
  251. + struct { const char *prefix; size_t len; } arr[] = {
  252. + { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
  253. + { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
  254. + };
  255. + int i;
  256. +
  257. + for (i = 0; i < ARRAY_SIZE(arr); i++) {
  258. + size_t preflen = arr[i].len;
  259. + if (strncmp(name, arr[i].prefix, preflen) == 0) {
  260. + if (!name[preflen])
  261. + return -EINVAL;
  262. + return 0;
  263. + }
  264. + }
  265. + return -EOPNOTSUPP;
  266. +}
  267. +
  268. +static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
  269. + void *buffer, size_t size)
  270. +{
  271. + int err;
  272. +
  273. + /*
  274. + * If this is a request for a synthetic attribute in the system.*
  275. + * namespace use the generic infrastructure to resolve a handler
  276. + * for it via sb->s_xattr.
  277. + */
  278. + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  279. + return generic_getxattr(dentry, name, buffer, size);
  280. +
  281. + err = shmem_xattr_validate(name);
  282. + if (err)
  283. + return err;
  284. +
  285. + return shmem_xattr_get(dentry, name, buffer, size);
  286. +}
  287. +
  288. +static int shmem_setxattr(struct dentry *dentry, const char *name,
  289. + const void *value, size_t size, int flags)
  290. +{
  291. + int err;
  292. +
  293. + /*
  294. + * If this is a request for a synthetic attribute in the system.*
  295. + * namespace use the generic infrastructure to resolve a handler
  296. + * for it via sb->s_xattr.
  297. + */
  298. + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  299. + return generic_setxattr(dentry, name, value, size, flags);
  300. +
  301. + err = shmem_xattr_validate(name);
  302. + if (err)
  303. + return err;
  304. +
  305. + if (size == 0)
  306. + value = ""; /* empty EA, do not remove */
  307. +
  308. + return shmem_xattr_set(dentry, name, value, size, flags);
  309. +
  310. +}
  311. +
  312. +static int shmem_removexattr(struct dentry *dentry, const char *name)
  313. +{
  314. + int err;
  315. +
  316. + /*
  317. + * If this is a request for a synthetic attribute in the system.*
  318. + * namespace use the generic infrastructure to resolve a handler
  319. + * for it via sb->s_xattr.
  320. + */
  321. + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  322. + return generic_removexattr(dentry, name);
  323. +
  324. + err = shmem_xattr_validate(name);
  325. + if (err)
  326. + return err;
  327. +
  328. + return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
  329. +}
  330. +
  331. +static bool xattr_is_trusted(const char *name)
  332. +{
  333. + return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
  334. +}
  335. +
  336. +static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
  337. +{
  338. + bool trusted = capable(CAP_SYS_ADMIN);
  339. + struct shmem_xattr *xattr;
  340. + struct shmem_inode_info *info;
  341. + size_t used = 0;
  342. +
  343. + info = SHMEM_I(dentry->d_inode);
  344. +
  345. + spin_lock(&info->lock);
  346. + list_for_each_entry(xattr, &info->xattr_list, list) {
  347. + size_t len;
  348. +
  349. + /* skip "trusted." attributes for unprivileged callers */
  350. + if (!trusted && xattr_is_trusted(xattr->name))
  351. + continue;
  352. +
  353. + len = strlen(xattr->name) + 1;
  354. + used += len;
  355. + if (buffer) {
  356. + if (size < used) {
  357. + used = -ERANGE;
  358. + break;
  359. + }
  360. + memcpy(buffer, xattr->name, len);
  361. + buffer += len;
  362. + }
  363. + }
  364. + spin_unlock(&info->lock);
  365. +
  366. + return used;
  367. +}
  368. +#endif /* CONFIG_TMPFS_XATTR */
  369. +
  370. +static const struct inode_operations shmem_symlink_inline_operations = {
  371. + .readlink = generic_readlink,
  372. + .follow_link = shmem_follow_link_inline,
  373. +#ifdef CONFIG_TMPFS_XATTR
  374. + .setxattr = shmem_setxattr,
  375. + .getxattr = shmem_getxattr,
  376. + .listxattr = shmem_listxattr,
  377. + .removexattr = shmem_removexattr,
  378. +#endif
  379. +};
  380. +
  381. +static const struct inode_operations shmem_symlink_inode_operations = {
  382. + .readlink = generic_readlink,
  383. + .follow_link = shmem_follow_link,
  384. + .put_link = shmem_put_link,
  385. +#ifdef CONFIG_TMPFS_XATTR
  386. + .setxattr = shmem_setxattr,
  387. + .getxattr = shmem_getxattr,
  388. + .listxattr = shmem_listxattr,
  389. + .removexattr = shmem_removexattr,
  390. #endif
  391. +};
  392. static struct dentry *shmem_get_parent(struct dentry *child)
  393. {
  394. @@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block
  395. sb->s_magic = TMPFS_MAGIC;
  396. sb->s_op = &shmem_ops;
  397. sb->s_time_gran = 1;
  398. -#ifdef CONFIG_TMPFS_POSIX_ACL
  399. +#ifdef CONFIG_TMPFS_XATTR
  400. sb->s_xattr = shmem_xattr_handlers;
  401. +#endif
  402. +#ifdef CONFIG_TMPFS_POSIX_ACL
  403. sb->s_flags |= MS_POSIXACL;
  404. #endif
  405. @@ -2501,11 +2707,13 @@ static const struct file_operations shme
  406. static const struct inode_operations shmem_inode_operations = {
  407. .setattr = shmem_notify_change,
  408. .truncate_range = shmem_truncate_range,
  409. +#ifdef CONFIG_TMPFS_XATTR
  410. + .setxattr = shmem_setxattr,
  411. + .getxattr = shmem_getxattr,
  412. + .listxattr = shmem_listxattr,
  413. + .removexattr = shmem_removexattr,
  414. +#endif
  415. #ifdef CONFIG_TMPFS_POSIX_ACL
  416. - .setxattr = generic_setxattr,
  417. - .getxattr = generic_getxattr,
  418. - .listxattr = generic_listxattr,
  419. - .removexattr = generic_removexattr,
  420. .check_acl = generic_check_acl,
  421. #endif
  422. @@ -2523,23 +2731,27 @@ static const struct inode_operations shm
  423. .mknod = shmem_mknod,
  424. .rename = shmem_rename,
  425. #endif
  426. +#ifdef CONFIG_TMPFS_XATTR
  427. + .setxattr = shmem_setxattr,
  428. + .getxattr = shmem_getxattr,
  429. + .listxattr = shmem_listxattr,
  430. + .removexattr = shmem_removexattr,
  431. +#endif
  432. #ifdef CONFIG_TMPFS_POSIX_ACL
  433. .setattr = shmem_notify_change,
  434. - .setxattr = generic_setxattr,
  435. - .getxattr = generic_getxattr,
  436. - .listxattr = generic_listxattr,
  437. - .removexattr = generic_removexattr,
  438. .check_acl = generic_check_acl,
  439. #endif
  440. };
  441. static const struct inode_operations shmem_special_inode_operations = {
  442. +#ifdef CONFIG_TMPFS_XATTR
  443. + .setxattr = shmem_setxattr,
  444. + .getxattr = shmem_getxattr,
  445. + .listxattr = shmem_listxattr,
  446. + .removexattr = shmem_removexattr,
  447. +#endif
  448. #ifdef CONFIG_TMPFS_POSIX_ACL
  449. .setattr = shmem_notify_change,
  450. - .setxattr = generic_setxattr,
  451. - .getxattr = generic_getxattr,
  452. - .listxattr = generic_listxattr,
  453. - .removexattr = generic_removexattr,
  454. .check_acl = generic_check_acl,
  455. #endif
  456. };