diff options
Diffstat (limited to 'target/linux')
| -rw-r--r-- | target/linux/generic/config-2.6.39 | 1 | ||||
| -rw-r--r-- | target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch | 477 | ||||
| -rw-r--r-- | target/linux/generic/patches-2.6.39/950-vm_exports.patch | 4 | 
3 files changed, 480 insertions, 2 deletions
| diff --git a/target/linux/generic/config-2.6.39 b/target/linux/generic/config-2.6.39 index a322f4763..b98814ab4 100644 --- a/target/linux/generic/config-2.6.39 +++ b/target/linux/generic/config-2.6.39 @@ -2631,6 +2631,7 @@ CONFIG_TINY_RCU=y  # CONFIG_TLAN is not set  # CONFIG_TMD_HERMES is not set  CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y  # CONFIG_TMPFS_POSIX_ACL is not set  # CONFIG_TOUCHSCREEN_AD7877 is not set  # CONFIG_TOUCHSCREEN_AD7879 is not set 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 new file mode 100644 index 000000000..e5d8d43ca --- /dev/null +++ b/target/linux/generic/patches-2.6.39/040-backport_tmpfs_xattr.patch @@ -0,0 +1,477 @@ +--- 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 + }; diff --git a/target/linux/generic/patches-2.6.39/950-vm_exports.patch b/target/linux/generic/patches-2.6.39/950-vm_exports.patch index 26b2da93a..33adb23e6 100644 --- a/target/linux/generic/patches-2.6.39/950-vm_exports.patch +++ b/target/linux/generic/patches-2.6.39/950-vm_exports.patch @@ -1,6 +1,6 @@  --- a/mm/shmem.c  +++ b/mm/shmem.c -@@ -2731,6 +2731,16 @@ out: +@@ -2943,6 +2943,16 @@ out:   /* common code */ @@ -17,7 +17,7 @@   /**    * shmem_file_setup - get an unlinked file living in tmpfs    * @name: name for dentry (to be seen in /proc/<pid>/maps -@@ -2808,10 +2818,7 @@ int shmem_zero_setup(struct vm_area_stru +@@ -3020,10 +3030,7 @@ int shmem_zero_setup(struct vm_area_stru   	if (IS_ERR(file))   		return PTR_ERR(file); | 
