Root/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch

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

Archive Download this file



interactive