summaryrefslogtreecommitdiff
path: root/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch')
-rw-r--r--target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch477
1 files changed, 0 insertions, 477 deletions
diff --git a/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch b/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch
deleted file mode 100644
index c7ae196..0000000
--- a/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch
+++ /dev/null
@@ -1,477 +0,0 @@
---- a/fs/Kconfig
-+++ b/fs/Kconfig
-@@ -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
---- a/include/linux/shmem_fs.h
-+++ b/include/linux/shmem_fs.h
-@@ -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;
- };
-
---- a/mm/shmem.c
-+++ b/mm/shmem.c
-@@ -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);
-@@ -1615,6 +1628,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) {
-@@ -2014,9 +2028,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);
-@@ -2042,7 +2056,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;
- }
-
-@@ -2066,63 +2080,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)
- {
-@@ -2402,8 +2606,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
-
-@@ -2501,11 +2707,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
-
-@@ -2523,23 +2731,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
- };