summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ima-allow-it-to-be-completely-disabled-and-default-off.patch145
-rw-r--r--kernel.spec14
-rw-r--r--tmpfs-implement-generic-xattr-support.patch557
3 files changed, 567 insertions, 149 deletions
diff --git a/ima-allow-it-to-be-completely-disabled-and-default-off.patch b/ima-allow-it-to-be-completely-disabled-and-default-off.patch
deleted file mode 100644
index 4f8f1f180..000000000
--- a/ima-allow-it-to-be-completely-disabled-and-default-off.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-From 785465d9cffd65b5a69dd2f465d2f7c917713220 Mon Sep 17 00:00:00 2001
-From: Kyle McMartin <kyle@mcmartin.ca>
-Date: Mon, 18 Oct 2010 13:30:39 -0400
-Subject: [PATCH] ima: provide a toggle to disable it entirely
-
-Signed-off-by: Kyle McMartin <kyle@redhat.com>
----
- security/integrity/ima/ima.h | 1 +
- security/integrity/ima/ima_iint.c | 9 +++++++++
- security/integrity/ima/ima_main.c | 24 +++++++++++++++++++++---
- 3 files changed, 31 insertions(+), 3 deletions(-)
-
-diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
-index 3fbcd1d..65c3977 100644
---- a/security/integrity/ima/ima.h
-+++ b/security/integrity/ima/ima.h
-@@ -37,6 +37,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
- /* set during initialization */
- extern int iint_initialized;
- extern int ima_initialized;
-+extern int ima_enabled;
- extern int ima_used_chip;
- extern char *ima_hash;
-
-diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
-index afba4ae..3d191ef 100644
---- a/security/integrity/ima/ima_iint.c
-+++ b/security/integrity/ima/ima_iint.c
-@@ -54,6 +54,9 @@ int ima_inode_alloc(struct inode *inode)
- struct ima_iint_cache *iint = NULL;
- int rc = 0;
-
-+ if (!ima_enabled)
-+ return 0;
-+
- iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
- if (!iint)
- return -ENOMEM;
-@@ -116,6 +119,9 @@ void ima_inode_free(struct inode *inode)
- {
- struct ima_iint_cache *iint;
-
-+ if (!ima_enabled)
-+ return;
-+
- spin_lock(&ima_iint_lock);
- iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
- spin_unlock(&ima_iint_lock);
-@@ -139,6 +145,9 @@ static void init_once(void *foo)
-
- static int __init ima_iintcache_init(void)
- {
-+ if (!ima_enabled)
-+ return 0;
-+
- iint_cache =
- kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
- SLAB_PANIC, init_once);
-diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
-index e662b89..6e91905 100644
---- a/security/integrity/ima/ima_main.c
-+++ b/security/integrity/ima/ima_main.c
-@@ -26,6 +26,7 @@
- #include "ima.h"
-
- int ima_initialized;
-+int ima_enabled;
-
- char *ima_hash = "sha1";
- static int __init hash_setup(char *str)
-@@ -36,6 +37,14 @@ static int __init hash_setup(char *str)
- }
- __setup("ima_hash=", hash_setup);
-
-+static int __init ima_enable(char *str)
-+{
-+ if (strncmp(str, "on", 2) == 0)
-+ ima_enabled = 1;
-+ return 1;
-+}
-+__setup("ima=", ima_enable);
-+
- struct ima_imbalance {
- struct hlist_node node;
- unsigned long fsmagic;
-@@ -148,7 +157,7 @@ void ima_counts_get(struct file *file)
- struct ima_iint_cache *iint;
- int rc;
-
-- if (!iint_initialized || !S_ISREG(inode->i_mode))
-+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
- return;
- iint = ima_iint_find_get(inode);
- if (!iint)
-@@ -215,7 +224,7 @@ void ima_file_free(struct file *file)
- struct inode *inode = file->f_dentry->d_inode;
- struct ima_iint_cache *iint;
-
-- if (!iint_initialized || !S_ISREG(inode->i_mode))
-+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
- return;
- iint = ima_iint_find_get(inode);
- if (!iint)
-@@ -269,7 +278,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
- {
- int rc;
-
-- if (!file)
-+ if (!ima_enabled || !file)
- return 0;
- if (prot & PROT_EXEC)
- rc = process_measurement(file, file->f_dentry->d_name.name,
-@@ -294,6 +303,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
- {
- int rc;
-
-+ if (!ima_enabled)
-+ return 0;
-+
- rc = process_measurement(bprm->file, bprm->filename,
- MAY_EXEC, BPRM_CHECK);
- return 0;
-@@ -313,6 +325,9 @@ int ima_file_check(struct file *file, int mask)
- {
- int rc;
-
-+ if (!ima_enabled)
-+ return 0;
-+
- rc = process_measurement(file, file->f_dentry->d_name.name,
- mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
- FILE_CHECK);
-@@ -324,6 +339,9 @@ static int __init init_ima(void)
- {
- int error;
-
-+ if (!ima_enabled)
-+ return 0;
-+
- error = ima_init();
- ima_initialized = 1;
- return error;
---
-1.7.3.1
-
diff --git a/kernel.spec b/kernel.spec
index fad464436..7a84f4e1c 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -619,6 +619,8 @@ Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch
Patch160: linux-2.6-32bit-mmap-exec-randomization.patch
Patch161: linux-2.6-i386-nx-emulation.patch
+Patch170: tmpfs-implement-generic-xattr-support.patch
+
Patch200: linux-2.6-debug-sizeof-structs.patch
Patch202: linux-2.6-debug-taint-vm.patch
Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch
@@ -628,8 +630,6 @@ Patch380: linux-2.6-defaults-pci_no_msi.patch
Patch381: linux-2.6-defaults-pci_use_crs.patch
Patch383: linux-2.6-defaults-aspm.patch
-Patch385: ima-allow-it-to-be-completely-disabled-and-default-off.patch
-
Patch390: linux-2.6-defaults-acpi-video.patch
Patch391: linux-2.6-acpi-video-dos.patch
Patch393: acpi-ec-add-delay-before-write.patch
@@ -1181,6 +1181,7 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch
#
# bugfixes to drivers and filesystems
#
+ApplyPatch tmpfs-implement-generic-xattr-support.patch
# ext4
@@ -1218,8 +1219,6 @@ ApplyPatch linux-2.6-defaults-pci_use_crs.patch
# enable ASPM by default on hardware we expect to work
ApplyPatch linux-2.6-defaults-aspm.patch
-#ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
-
#
# SCSI Bits.
#
@@ -1937,6 +1936,13 @@ fi
# and build.
%changelog
+* Sat May 14 2011 Kyle McMartin <kmcmartin@redhat.com> 2.6.39-0.rc7.git6.1
+- tmpfs: implement generic xattr support
+ Merge Eric Paris' patch to add xattr support to tmpfs, so that it can be
+ used to host mockroots for mass rebuilds.
+- Drop IMA disabling patch, which is no longer necessary since it's run time
+ (but unused) cost is now minimized.
+
* Sat May 14 2011 Kyle McMartin <kmcmartin@redhat.com> 2.6.39-0.rc7.git6.0
- Update to 2.6.39-rc7-git6
diff --git a/tmpfs-implement-generic-xattr-support.patch b/tmpfs-implement-generic-xattr-support.patch
new file mode 100644
index 000000000..9ca97d1c7
--- /dev/null
+++ b/tmpfs-implement-generic-xattr-support.patch
@@ -0,0 +1,557 @@
+From linux-fsdevel-owner@vger.kernel.org Fri May 13 07:16:45 2011
+From: Miklos Szeredi <miklos@szeredi.hu>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ Hugh Dickins <hughd@google.com>
+Subject: [PATCH v2] tmpfs: implement generic xattr support
+CC: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
+ Michal Suchanek <hramrach@centrum.cz>,
+ Serge Hallyn <serge.hallyn@ubuntu.com>,
+ Eric Paris <eparis@redhat.com>,
+ James Morris <jmorris@namei.org>,
+ Christoph Hellwig <hch@infradead.org>
+Date: Fri, 13 May 2011 13:16:35 +0200
+Message-ID: <871v02lujw.fsf@tucsk.pomaz.szeredi.hu>
+X-Mailing-List: linux-fsdevel@vger.kernel.org
+
+[This update addresses comments from Hugh and Andrew]
+
+
+From: Eric Paris <eparis@redhat.com>
+
+This patch implements generic xattrs for tmpfs filesystems. The feodra
+project, while trying to replace suid apps with file capabilities,
+realized that tmpfs, which is used on the build systems, does not
+support file capabilities and thus cannot be used to build packages
+which use file capabilities. Xattrs are also needed for overlayfs.
+
+The xattr interface is a bit, odd. If a filesystem does not implement any
+{get,set,list}xattr functions the VFS will call into some random LSM hooks and
+the running LSM can then implement some method for handling xattrs. SELinux
+for example provides a method to support security.selinux but no other
+security.* xattrs.
+
+As it stands today when one enables CONFIG_TMPFS_POSIX_ACL tmpfs will have
+xattr handler routines specifically to handle acls. Because of this tmpfs
+would loose the VFS/LSM helpers to support the running LSM. To make up for
+that tmpfs had stub functions that did nothing but call into the LSM hooks
+which implement the helpers.
+
+This new patch does not use the LSM fallback functions and instead
+just implements a native get/set/list xattr feature for the full
+security.* and trusted.* namespace like a normal filesystem. This
+means that tmpfs can now support both security.selinux and
+security.capability, which was not previously possible.
+
+The basic implementation is that I attach a:
+
+struct shmem_xattr {
+ struct list_head list; /* anchored by shmem_inode_info->xattr_list */
+ char *name;
+ size_t size;
+ char value[0];
+};
+
+Into the struct shmem_inode_info for each xattr that is set. This
+implementation could easily support the user.* namespace as well,
+except some care needs to be taken to prevent large amounts of
+unswappable memory being allocated for unprivileged users.
+
+[miklos: new config option, suport trusted.*, support symlinks]
+
+Signed-off-by: Eric Paris <eparis@redhat.com>
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
+---
+ fs/Kconfig | 18 ++
+ include/linux/shmem_fs.h | 8 +
+ mm/shmem.c | 320 +++++++++++++++++++++++++++++++++++++++--------
+ 3 files changed, 290 insertions(+), 56 deletions(-)
+
+Index: linux-2.6/fs/Kconfig
+===================================================================
+--- linux-2.6.orig/fs/Kconfig 2011-05-13 12:26:31.000000000 +0200
++++ linux-2.6/fs/Kconfig 2011-05-13 12:29:34.000000000 +0200
+@@ -121,9 +121,25 @@ config TMPFS
+
+ See <file:Documentation/filesystems/tmpfs.txt> for details.
+
++config TMPFS_XATTR
++ bool "Tmpfs extended attributes"
++ depends on TMPFS
++ default n
++ help
++ Extended attributes are name:value pairs associated with inodes by
++ the kernel or by users (see the attr(5) manual page, or visit
++ <http://acl.bestbits.at/> for details).
++
++ Currently this enables support for the trusted.* and
++ security.* namespaces.
++
++ If unsure, say N.
++
++ You need this for POSIX ACL support on tmpfs.
++
+ config TMPFS_POSIX_ACL
+ bool "Tmpfs POSIX Access Control Lists"
+- depends on TMPFS
++ depends on TMPFS_XATTR
+ select GENERIC_ACL
+ help
+ POSIX Access Control Lists (ACLs) support permissions for users and
+Index: linux-2.6/include/linux/shmem_fs.h
+===================================================================
+--- linux-2.6.orig/include/linux/shmem_fs.h 2011-05-13 12:26:31.000000000 +0200
++++ linux-2.6/include/linux/shmem_fs.h 2011-05-13 12:35:36.000000000 +0200
+@@ -9,6 +9,8 @@
+
+ #define SHMEM_NR_DIRECT 16
+
++#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
++
+ struct shmem_inode_info {
+ spinlock_t lock;
+ unsigned long flags;
+@@ -17,8 +19,12 @@ struct shmem_inode_info {
+ unsigned long next_index; /* highest alloced index + 1 */
+ struct shared_policy policy; /* NUMA memory alloc policy */
+ struct page *i_indirect; /* top indirect blocks page */
+- swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
++ union {
++ swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
++ char inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
++ };
+ struct list_head swaplist; /* chain of maybes on swap */
++ struct list_head xattr_list; /* list of shmem_xattr */
+ struct inode vfs_inode;
+ };
+
+Index: linux-2.6/mm/shmem.c
+===================================================================
+--- linux-2.6.orig/mm/shmem.c 2011-05-13 12:26:31.000000000 +0200
++++ linux-2.6/mm/shmem.c 2011-05-13 12:36:08.000000000 +0200
+@@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
+ /* Pretend that each entry is of this size in directory's i_size */
+ #define BOGO_DIRENT_SIZE 20
+
++struct shmem_xattr {
++ struct list_head list; /* anchored by shmem_inode_info->xattr_list */
++ char *name; /* xattr name */
++ size_t size;
++ char value[0];
++};
++
+ /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
+ enum sgp_type {
+ SGP_READ, /* don't exceed i_size, don't allocate page */
+@@ -822,6 +829,7 @@ static int shmem_notify_change(struct de
+ static void shmem_evict_inode(struct inode *inode)
+ {
+ struct shmem_inode_info *info = SHMEM_I(inode);
++ struct shmem_xattr *xattr, *nxattr;
+
+ if (inode->i_mapping->a_ops == &shmem_aops) {
+ truncate_inode_pages(inode->i_mapping, 0);
+@@ -834,6 +842,11 @@ static void shmem_evict_inode(struct ino
+ mutex_unlock(&shmem_swaplist_mutex);
+ }
+ }
++
++ list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
++ kfree(xattr->name);
++ kfree(xattr);
++ }
+ BUG_ON(inode->i_blocks);
+ shmem_free_inode(inode->i_sb);
+ end_writeback(inode);
+@@ -1616,6 +1629,7 @@ static struct inode *shmem_get_inode(str
+ spin_lock_init(&info->lock);
+ info->flags = flags & VM_NORESERVE;
+ INIT_LIST_HEAD(&info->swaplist);
++ INIT_LIST_HEAD(&info->xattr_list);
+ cache_no_acl(inode);
+
+ switch (mode & S_IFMT) {
+@@ -2015,9 +2029,9 @@ static int shmem_symlink(struct inode *d
+
+ info = SHMEM_I(inode);
+ inode->i_size = len-1;
+- if (len <= (char *)inode - (char *)info) {
++ if (len <= SHMEM_SYMLINK_INLINE_LEN) {
+ /* do it inline */
+- memcpy(info, symname, len);
++ memcpy(info->inline_symlink, symname, len);
+ inode->i_op = &shmem_symlink_inline_operations;
+ } else {
+ error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
+@@ -2043,7 +2057,7 @@ static int shmem_symlink(struct inode *d
+
+ static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
+ {
+- nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
++ nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
+ return NULL;
+ }
+
+@@ -2067,63 +2081,253 @@ static void shmem_put_link(struct dentry
+ }
+ }
+
+-static const struct inode_operations shmem_symlink_inline_operations = {
+- .readlink = generic_readlink,
+- .follow_link = shmem_follow_link_inline,
+-};
+-
+-static const struct inode_operations shmem_symlink_inode_operations = {
+- .readlink = generic_readlink,
+- .follow_link = shmem_follow_link,
+- .put_link = shmem_put_link,
+-};
+-
+-#ifdef CONFIG_TMPFS_POSIX_ACL
++#ifdef CONFIG_TMPFS_XATTR
+ /*
+- * Superblocks without xattr inode operations will get security.* xattr
+- * support from the VFS "for free". As soon as we have any other xattrs
++ * Superblocks without xattr inode operations may get some security.* xattr
++ * support from the LSM "for free". As soon as we have any other xattrs
+ * like ACLs, we also need to implement the security.* handlers at
+ * filesystem level, though.
+ */
+
+-static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
+- size_t list_len, const char *name,
+- size_t name_len, int handler_flags)
++static int shmem_xattr_get(struct dentry *dentry, const char *name,
++ void *buffer, size_t size)
+ {
+- return security_inode_listsecurity(dentry->d_inode, list, list_len);
+-}
++ struct shmem_inode_info *info;
++ struct shmem_xattr *xattr;
++ int ret = -ENODATA;
+
+-static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
+- void *buffer, size_t size, int handler_flags)
+-{
+- if (strcmp(name, "") == 0)
+- return -EINVAL;
+- return xattr_getsecurity(dentry->d_inode, name, buffer, size);
++ info = SHMEM_I(dentry->d_inode);
++
++ spin_lock(&info->lock);
++ list_for_each_entry(xattr, &info->xattr_list, list) {
++ if (strcmp(name, xattr->name))
++ continue;
++
++ ret = xattr->size;
++ if (buffer) {
++ if (size < xattr->size)
++ ret = -ERANGE;
++ else
++ memcpy(buffer, xattr->value, xattr->size);
++ }
++ break;
++ }
++ spin_unlock(&info->lock);
++ return ret;
+ }
+
+-static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
+- const void *value, size_t size, int flags, int handler_flags)
++static int shmem_xattr_set(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
+ {
+- if (strcmp(name, "") == 0)
+- return -EINVAL;
+- return security_inode_setsecurity(dentry->d_inode, name, value,
+- size, flags);
++ struct inode *inode = dentry->d_inode;
++ struct shmem_inode_info *info = SHMEM_I(inode);
++ struct shmem_xattr *xattr;
++ struct shmem_xattr *new_xattr = NULL;
++ size_t len;
++ int err = 0;
++
++ /* value == NULL means remove */
++ if (value) {
++ /* wrap around? */
++ len = sizeof(*new_xattr) + size;
++ if (len <= sizeof(*new_xattr))
++ return -ENOMEM;
++
++ new_xattr = kmalloc(len, GFP_KERNEL);
++ if (!new_xattr)
++ return -ENOMEM;
++
++ new_xattr->name = kstrdup(name, GFP_KERNEL);
++ if (!new_xattr->name) {
++ kfree(new_xattr);
++ return -ENOMEM;
++ }
++
++ new_xattr->size = size;
++ memcpy(new_xattr->value, value, size);
++ }
++
++ spin_lock(&info->lock);
++ list_for_each_entry(xattr, &info->xattr_list, list) {
++ if (!strcmp(name, xattr->name)) {
++ if (flags & XATTR_CREATE) {
++ xattr = new_xattr;
++ err = -EEXIST;
++ } else if (new_xattr) {
++ list_replace(&xattr->list, &new_xattr->list);
++ } else {
++ list_del(&xattr->list);
++ }
++ goto out;
++ }
++ }
++ if (flags & XATTR_REPLACE) {
++ xattr = new_xattr;
++ err = -ENODATA;
++ } else {
++ list_add(&new_xattr->list, &info->xattr_list);
++ xattr = NULL;
++ }
++out:
++ spin_unlock(&info->lock);
++ if (xattr)
++ kfree(xattr->name);
++ kfree(xattr);
++ return err;
+ }
+
+-static const struct xattr_handler shmem_xattr_security_handler = {
+- .prefix = XATTR_SECURITY_PREFIX,
+- .list = shmem_xattr_security_list,
+- .get = shmem_xattr_security_get,
+- .set = shmem_xattr_security_set,
+-};
+
+ static const struct xattr_handler *shmem_xattr_handlers[] = {
++#ifdef CONFIG_TMPFS_POSIX_ACL
+ &generic_acl_access_handler,
+ &generic_acl_default_handler,
+- &shmem_xattr_security_handler,
++#endif
+ NULL
+ };
++
++static int shmem_xattr_validate(const char *name)
++{
++ struct { const char *prefix; size_t len; } arr[] = {
++ { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
++ { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
++ };
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(arr); i++) {
++ size_t preflen = arr[i].len;
++ if (strncmp(name, arr[i].prefix, preflen) == 0) {
++ if (!name[preflen])
++ return -EINVAL;
++ return 0;
++ }
++ }
++ return -EOPNOTSUPP;
++}
++
++static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
++ void *buffer, size_t size)
++{
++ int err;
++
++ /*
++ * If this is a request for a synthetic attribute in the system.*
++ * namespace use the generic infrastructure to resolve a handler
++ * for it via sb->s_xattr.
++ */
++ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
++ return generic_getxattr(dentry, name, buffer, size);
++
++ err = shmem_xattr_validate(name);
++ if (err)
++ return err;
++
++ return shmem_xattr_get(dentry, name, buffer, size);
++}
++
++static int shmem_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ int err;
++
++ /*
++ * If this is a request for a synthetic attribute in the system.*
++ * namespace use the generic infrastructure to resolve a handler
++ * for it via sb->s_xattr.
++ */
++ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
++ return generic_setxattr(dentry, name, value, size, flags);
++
++ err = shmem_xattr_validate(name);
++ if (err)
++ return err;
++
++ if (size == 0)
++ value = ""; /* empty EA, do not remove */
++
++ return shmem_xattr_set(dentry, name, value, size, flags);
++
++}
++
++static int shmem_removexattr(struct dentry *dentry, const char *name)
++{
++ int err;
++
++ /*
++ * If this is a request for a synthetic attribute in the system.*
++ * namespace use the generic infrastructure to resolve a handler
++ * for it via sb->s_xattr.
++ */
++ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
++ return generic_removexattr(dentry, name);
++
++ err = shmem_xattr_validate(name);
++ if (err)
++ return err;
++
++ return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
++}
++
++static bool xattr_is_trusted(const char *name)
++{
++ return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
++}
++
++static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
++{
++ bool trusted = capable(CAP_SYS_ADMIN);
++ struct shmem_xattr *xattr;
++ struct shmem_inode_info *info;
++ size_t used = 0;
++
++ info = SHMEM_I(dentry->d_inode);
++
++ spin_lock(&info->lock);
++ list_for_each_entry(xattr, &info->xattr_list, list) {
++ size_t len;
++
++ /* skip "trusted." attributes for unprivileged callers */
++ if (!trusted && xattr_is_trusted(xattr->name))
++ continue;
++
++ len = strlen(xattr->name) + 1;
++ used += len;
++ if (buffer) {
++ if (size < used) {
++ used = -ERANGE;
++ break;
++ }
++ memcpy(buffer, xattr->name, len);
++ buffer += len;
++ }
++ }
++ spin_unlock(&info->lock);
++
++ return used;
++}
++#endif /* CONFIG_TMPFS_XATTR */
++
++static const struct inode_operations shmem_symlink_inline_operations = {
++ .readlink = generic_readlink,
++ .follow_link = shmem_follow_link_inline,
++#ifdef CONFIG_TMPFS_XATTR
++ .setxattr = shmem_setxattr,
++ .getxattr = shmem_getxattr,
++ .listxattr = shmem_listxattr,
++ .removexattr = shmem_removexattr,
++#endif
++};
++
++static const struct inode_operations shmem_symlink_inode_operations = {
++ .readlink = generic_readlink,
++ .follow_link = shmem_follow_link,
++ .put_link = shmem_put_link,
++#ifdef CONFIG_TMPFS_XATTR
++ .setxattr = shmem_setxattr,
++ .getxattr = shmem_getxattr,
++ .listxattr = shmem_listxattr,
++ .removexattr = shmem_removexattr,
+ #endif
++};
+
+ static struct dentry *shmem_get_parent(struct dentry *child)
+ {
+@@ -2403,8 +2607,10 @@ int shmem_fill_super(struct super_block
+ sb->s_magic = TMPFS_MAGIC;
+ sb->s_op = &shmem_ops;
+ sb->s_time_gran = 1;
+-#ifdef CONFIG_TMPFS_POSIX_ACL
++#ifdef CONFIG_TMPFS_XATTR
+ sb->s_xattr = shmem_xattr_handlers;
++#endif
++#ifdef CONFIG_TMPFS_POSIX_ACL
+ sb->s_flags |= MS_POSIXACL;
+ #endif
+
+@@ -2502,11 +2708,13 @@ static const struct file_operations shme
+ static const struct inode_operations shmem_inode_operations = {
+ .setattr = shmem_notify_change,
+ .truncate_range = shmem_truncate_range,
++#ifdef CONFIG_TMPFS_XATTR
++ .setxattr = shmem_setxattr,
++ .getxattr = shmem_getxattr,
++ .listxattr = shmem_listxattr,
++ .removexattr = shmem_removexattr,
++#endif
+ #ifdef CONFIG_TMPFS_POSIX_ACL
+- .setxattr = generic_setxattr,
+- .getxattr = generic_getxattr,
+- .listxattr = generic_listxattr,
+- .removexattr = generic_removexattr,
+ .check_acl = generic_check_acl,
+ #endif
+
+@@ -2524,23 +2732,27 @@ static const struct inode_operations shm
+ .mknod = shmem_mknod,
+ .rename = shmem_rename,
+ #endif
++#ifdef CONFIG_TMPFS_XATTR
++ .setxattr = shmem_setxattr,
++ .getxattr = shmem_getxattr,
++ .listxattr = shmem_listxattr,
++ .removexattr = shmem_removexattr,
++#endif
+ #ifdef CONFIG_TMPFS_POSIX_ACL
+ .setattr = shmem_notify_change,
+- .setxattr = generic_setxattr,
+- .getxattr = generic_getxattr,
+- .listxattr = generic_listxattr,
+- .removexattr = generic_removexattr,
+ .check_acl = generic_check_acl,
+ #endif
+ };
+
+ static const struct inode_operations shmem_special_inode_operations = {
++#ifdef CONFIG_TMPFS_XATTR
++ .setxattr = shmem_setxattr,
++ .getxattr = shmem_getxattr,
++ .listxattr = shmem_listxattr,
++ .removexattr = shmem_removexattr,
++#endif
+ #ifdef CONFIG_TMPFS_POSIX_ACL
+ .setattr = shmem_notify_change,
+- .setxattr = generic_setxattr,
+- .getxattr = generic_getxattr,
+- .listxattr = generic_listxattr,
+- .removexattr = generic_removexattr,
+ .check_acl = generic_check_acl,
+ #endif
+ };
+--
+To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+