aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/Kconfig18
-rw-r--r--include/linux/shmem_fs.h8
-rw-r--r--mm/shmem.c320
3 files changed, 290 insertions, 56 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index f3aa9b08b228..979992dcb386 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -121,9 +121,25 @@ config TMPFS
121 121
122 See <file:Documentation/filesystems/tmpfs.txt> for details. 122 See <file:Documentation/filesystems/tmpfs.txt> for details.
123 123
124config TMPFS_XATTR
125 bool "Tmpfs extended attributes"
126 depends on TMPFS
127 default n
128 help
129 Extended attributes are name:value pairs associated with inodes by
130 the kernel or by users (see the attr(5) manual page, or visit
131 <http://acl.bestbits.at/> for details).
132
133 Currently this enables support for the trusted.* and
134 security.* namespaces.
135
136 If unsure, say N.
137
138 You need this for POSIX ACL support on tmpfs.
139
124config TMPFS_POSIX_ACL 140config TMPFS_POSIX_ACL
125 bool "Tmpfs POSIX Access Control Lists" 141 bool "Tmpfs POSIX Access Control Lists"
126 depends on TMPFS 142 depends on TMPFS_XATTR
127 select GENERIC_ACL 143 select GENERIC_ACL
128 help 144 help
129 POSIX Access Control Lists (ACLs) support permissions for users and 145 POSIX Access Control Lists (ACLs) support permissions for users and
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 399be5ad2f99..2b7fec840517 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -9,6 +9,8 @@
9 9
10#define SHMEM_NR_DIRECT 16 10#define SHMEM_NR_DIRECT 16
11 11
12#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
13
12struct shmem_inode_info { 14struct shmem_inode_info {
13 spinlock_t lock; 15 spinlock_t lock;
14 unsigned long flags; 16 unsigned long flags;
@@ -17,8 +19,12 @@ struct shmem_inode_info {
17 unsigned long next_index; /* highest alloced index + 1 */ 19 unsigned long next_index; /* highest alloced index + 1 */
18 struct shared_policy policy; /* NUMA memory alloc policy */ 20 struct shared_policy policy; /* NUMA memory alloc policy */
19 struct page *i_indirect; /* top indirect blocks page */ 21 struct page *i_indirect; /* top indirect blocks page */
20 swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */ 22 union {
23 swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
24 char inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
25 };
21 struct list_head swaplist; /* chain of maybes on swap */ 26 struct list_head swaplist; /* chain of maybes on swap */
27 struct list_head xattr_list; /* list of shmem_xattr */
22 struct inode vfs_inode; 28 struct inode vfs_inode;
23}; 29};
24 30
diff --git a/mm/shmem.c b/mm/shmem.c
index ba4ad28b7db6..69edb45a9f28 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
99/* Pretend that each entry is of this size in directory's i_size */ 99/* Pretend that each entry is of this size in directory's i_size */
100#define BOGO_DIRENT_SIZE 20 100#define BOGO_DIRENT_SIZE 20
101 101
102struct shmem_xattr {
103 struct list_head list; /* anchored by shmem_inode_info->xattr_list */
104 char *name; /* xattr name */
105 size_t size;
106 char value[0];
107};
108
102/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */ 109/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
103enum sgp_type { 110enum sgp_type {
104 SGP_READ, /* don't exceed i_size, don't allocate page */ 111 SGP_READ, /* don't exceed i_size, don't allocate page */
@@ -822,6 +829,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
822static void shmem_evict_inode(struct inode *inode) 829static void shmem_evict_inode(struct inode *inode)
823{ 830{
824 struct shmem_inode_info *info = SHMEM_I(inode); 831 struct shmem_inode_info *info = SHMEM_I(inode);
832 struct shmem_xattr *xattr, *nxattr;
825 833
826 if (inode->i_mapping->a_ops == &shmem_aops) { 834 if (inode->i_mapping->a_ops == &shmem_aops) {
827 truncate_inode_pages(inode->i_mapping, 0); 835 truncate_inode_pages(inode->i_mapping, 0);
@@ -834,6 +842,11 @@ static void shmem_evict_inode(struct inode *inode)
834 mutex_unlock(&shmem_swaplist_mutex); 842 mutex_unlock(&shmem_swaplist_mutex);
835 } 843 }
836 } 844 }
845
846 list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
847 kfree(xattr->name);
848 kfree(xattr);
849 }
837 BUG_ON(inode->i_blocks); 850 BUG_ON(inode->i_blocks);
838 shmem_free_inode(inode->i_sb); 851 shmem_free_inode(inode->i_sb);
839 end_writeback(inode); 852 end_writeback(inode);
@@ -1615,6 +1628,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
1615 spin_lock_init(&info->lock); 1628 spin_lock_init(&info->lock);
1616 info->flags = flags & VM_NORESERVE; 1629 info->flags = flags & VM_NORESERVE;
1617 INIT_LIST_HEAD(&info->swaplist); 1630 INIT_LIST_HEAD(&info->swaplist);
1631 INIT_LIST_HEAD(&info->xattr_list);
1618 cache_no_acl(inode); 1632 cache_no_acl(inode);
1619 1633
1620 switch (mode & S_IFMT) { 1634 switch (mode & S_IFMT) {
@@ -2014,9 +2028,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
2014 2028
2015 info = SHMEM_I(inode); 2029 info = SHMEM_I(inode);
2016 inode->i_size = len-1; 2030 inode->i_size = len-1;
2017 if (len <= (char *)inode - (char *)info) { 2031 if (len <= SHMEM_SYMLINK_INLINE_LEN) {
2018 /* do it inline */ 2032 /* do it inline */
2019 memcpy(info, symname, len); 2033 memcpy(info->inline_symlink, symname, len);
2020 inode->i_op = &shmem_symlink_inline_operations; 2034 inode->i_op = &shmem_symlink_inline_operations;
2021 } else { 2035 } else {
2022 error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); 2036 error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
@@ -2042,7 +2056,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
2042 2056
2043static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) 2057static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
2044{ 2058{
2045 nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode)); 2059 nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
2046 return NULL; 2060 return NULL;
2047} 2061}
2048 2062
@@ -2066,63 +2080,253 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
2066 } 2080 }
2067} 2081}
2068 2082
2069static const struct inode_operations shmem_symlink_inline_operations = { 2083#ifdef CONFIG_TMPFS_XATTR
2070 .readlink = generic_readlink,
2071 .follow_link = shmem_follow_link_inline,
2072};
2073
2074static const struct inode_operations shmem_symlink_inode_operations = {
2075 .readlink = generic_readlink,
2076 .follow_link = shmem_follow_link,
2077 .put_link = shmem_put_link,
2078};
2079
2080#ifdef CONFIG_TMPFS_POSIX_ACL
2081/* 2084/*
2082 * Superblocks without xattr inode operations will get security.* xattr 2085 * Superblocks without xattr inode operations may get some security.* xattr
2083 * support from the VFS "for free". As soon as we have any other xattrs 2086 * support from the LSM "for free". As soon as we have any other xattrs
2084 * like ACLs, we also need to implement the security.* handlers at 2087 * like ACLs, we also need to implement the security.* handlers at
2085 * filesystem level, though. 2088 * filesystem level, though.
2086 */ 2089 */
2087 2090
2088static size_t shmem_xattr_security_list(struct dentry *dentry, char *list, 2091static int shmem_xattr_get(struct dentry *dentry, const char *name,
2089 size_t list_len, const char *name, 2092 void *buffer, size_t size)
2090 size_t name_len, int handler_flags)
2091{ 2093{
2092 return security_inode_listsecurity(dentry->d_inode, list, list_len); 2094 struct shmem_inode_info *info;
2093} 2095 struct shmem_xattr *xattr;
2096 int ret = -ENODATA;
2094 2097
2095static int shmem_xattr_security_get(struct dentry *dentry, const char *name, 2098 info = SHMEM_I(dentry->d_inode);
2096 void *buffer, size_t size, int handler_flags) 2099
2097{ 2100 spin_lock(&info->lock);
2098 if (strcmp(name, "") == 0) 2101 list_for_each_entry(xattr, &info->xattr_list, list) {
2099 return -EINVAL; 2102 if (strcmp(name, xattr->name))
2100 return xattr_getsecurity(dentry->d_inode, name, buffer, size); 2103 continue;
2104
2105 ret = xattr->size;
2106 if (buffer) {
2107 if (size < xattr->size)
2108 ret = -ERANGE;
2109 else
2110 memcpy(buffer, xattr->value, xattr->size);
2111 }
2112 break;
2113 }
2114 spin_unlock(&info->lock);
2115 return ret;
2101} 2116}
2102 2117
2103static int shmem_xattr_security_set(struct dentry *dentry, const char *name, 2118static int shmem_xattr_set(struct dentry *dentry, const char *name,
2104 const void *value, size_t size, int flags, int handler_flags) 2119 const void *value, size_t size, int flags)
2105{ 2120{
2106 if (strcmp(name, "") == 0) 2121 struct inode *inode = dentry->d_inode;
2107 return -EINVAL; 2122 struct shmem_inode_info *info = SHMEM_I(inode);
2108 return security_inode_setsecurity(dentry->d_inode, name, value, 2123 struct shmem_xattr *xattr;
2109 size, flags); 2124 struct shmem_xattr *new_xattr = NULL;
2125 size_t len;
2126 int err = 0;
2127
2128 /* value == NULL means remove */
2129 if (value) {
2130 /* wrap around? */
2131 len = sizeof(*new_xattr) + size;
2132 if (len <= sizeof(*new_xattr))
2133 return -ENOMEM;
2134
2135 new_xattr = kmalloc(len, GFP_KERNEL);
2136 if (!new_xattr)
2137 return -ENOMEM;
2138
2139 new_xattr->name = kstrdup(name, GFP_KERNEL);
2140 if (!new_xattr->name) {
2141 kfree(new_xattr);
2142 return -ENOMEM;
2143 }
2144
2145 new_xattr->size = size;
2146 memcpy(new_xattr->value, value, size);
2147 }
2148
2149 spin_lock(&info->lock);
2150 list_for_each_entry(xattr, &info->xattr_list, list) {
2151 if (!strcmp(name, xattr->name)) {
2152 if (flags & XATTR_CREATE) {
2153 xattr = new_xattr;
2154 err = -EEXIST;
2155 } else if (new_xattr) {
2156 list_replace(&xattr->list, &new_xattr->list);
2157 } else {
2158 list_del(&xattr->list);
2159 }
2160 goto out;
2161 }
2162 }
2163 if (flags & XATTR_REPLACE) {
2164 xattr = new_xattr;
2165 err = -ENODATA;
2166 } else {
2167 list_add(&new_xattr->list, &info->xattr_list);
2168 xattr = NULL;
2169 }
2170out:
2171 spin_unlock(&info->lock);
2172 if (xattr)
2173 kfree(xattr->name);
2174 kfree(xattr);
2175 return err;
2110} 2176}
2111 2177
2112static const struct xattr_handler shmem_xattr_security_handler = {
2113 .prefix = XATTR_SECURITY_PREFIX,
2114 .list = shmem_xattr_security_list,
2115 .get = shmem_xattr_security_get,
2116 .set = shmem_xattr_security_set,
2117};
2118 2178
2119static const struct xattr_handler *shmem_xattr_handlers[] = { 2179static const struct xattr_handler *shmem_xattr_handlers[] = {
2180#ifdef CONFIG_TMPFS_POSIX_ACL
2120 &generic_acl_access_handler, 2181 &generic_acl_access_handler,
2121 &generic_acl_default_handler, 2182 &generic_acl_default_handler,
2122 &shmem_xattr_security_handler, 2183#endif
2123 NULL 2184 NULL
2124}; 2185};
2186
2187static int shmem_xattr_validate(const char *name)
2188{
2189 struct { const char *prefix; size_t len; } arr[] = {
2190 { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
2191 { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
2192 };
2193 int i;
2194
2195 for (i = 0; i < ARRAY_SIZE(arr); i++) {
2196 size_t preflen = arr[i].len;
2197 if (strncmp(name, arr[i].prefix, preflen) == 0) {
2198 if (!name[preflen])
2199 return -EINVAL;
2200 return 0;
2201 }
2202 }
2203 return -EOPNOTSUPP;
2204}
2205
2206static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
2207 void *buffer, size_t size)
2208{
2209 int err;
2210
2211 /*
2212 * If this is a request for a synthetic attribute in the system.*
2213 * namespace use the generic infrastructure to resolve a handler
2214 * for it via sb->s_xattr.
2215 */
2216 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
2217 return generic_getxattr(dentry, name, buffer, size);
2218
2219 err = shmem_xattr_validate(name);
2220 if (err)
2221 return err;
2222
2223 return shmem_xattr_get(dentry, name, buffer, size);
2224}
2225
2226static int shmem_setxattr(struct dentry *dentry, const char *name,
2227 const void *value, size_t size, int flags)
2228{
2229 int err;
2230
2231 /*
2232 * If this is a request for a synthetic attribute in the system.*
2233 * namespace use the generic infrastructure to resolve a handler
2234 * for it via sb->s_xattr.
2235 */
2236 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
2237 return generic_setxattr(dentry, name, value, size, flags);
2238
2239 err = shmem_xattr_validate(name);
2240 if (err)
2241 return err;
2242
2243 if (size == 0)
2244 value = ""; /* empty EA, do not remove */
2245
2246 return shmem_xattr_set(dentry, name, value, size, flags);
2247
2248}
2249
2250static int shmem_removexattr(struct dentry *dentry, const char *name)
2251{
2252 int err;
2253
2254 /*
2255 * If this is a request for a synthetic attribute in the system.*
2256 * namespace use the generic infrastructure to resolve a handler
2257 * for it via sb->s_xattr.
2258 */
2259 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
2260 return generic_removexattr(dentry, name);
2261
2262 err = shmem_xattr_validate(name);
2263 if (err)
2264 return err;
2265
2266 return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
2267}
2268
2269static bool xattr_is_trusted(const char *name)
2270{
2271 return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
2272}
2273
2274static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
2275{
2276 bool trusted = capable(CAP_SYS_ADMIN);
2277 struct shmem_xattr *xattr;
2278 struct shmem_inode_info *info;
2279 size_t used = 0;
2280
2281 info = SHMEM_I(dentry->d_inode);
2282
2283 spin_lock(&info->lock);
2284 list_for_each_entry(xattr, &info->xattr_list, list) {
2285 size_t len;
2286
2287 /* skip "trusted." attributes for unprivileged callers */
2288 if (!trusted && xattr_is_trusted(xattr->name))
2289 continue;
2290
2291 len = strlen(xattr->name) + 1;
2292 used += len;
2293 if (buffer) {
2294 if (size < used) {
2295 used = -ERANGE;
2296 break;
2297 }
2298 memcpy(buffer, xattr->name, len);
2299 buffer += len;
2300 }
2301 }
2302 spin_unlock(&info->lock);
2303
2304 return used;
2305}
2306#endif /* CONFIG_TMPFS_XATTR */
2307
2308static const struct inode_operations shmem_symlink_inline_operations = {
2309 .readlink = generic_readlink,
2310 .follow_link = shmem_follow_link_inline,
2311#ifdef CONFIG_TMPFS_XATTR
2312 .setxattr = shmem_setxattr,
2313 .getxattr = shmem_getxattr,
2314 .listxattr = shmem_listxattr,
2315 .removexattr = shmem_removexattr,
2316#endif
2317};
2318
2319static const struct inode_operations shmem_symlink_inode_operations = {
2320 .readlink = generic_readlink,
2321 .follow_link = shmem_follow_link,
2322 .put_link = shmem_put_link,
2323#ifdef CONFIG_TMPFS_XATTR
2324 .setxattr = shmem_setxattr,
2325 .getxattr = shmem_getxattr,
2326 .listxattr = shmem_listxattr,
2327 .removexattr = shmem_removexattr,
2125#endif 2328#endif
2329};
2126 2330
2127static struct dentry *shmem_get_parent(struct dentry *child) 2331static struct dentry *shmem_get_parent(struct dentry *child)
2128{ 2332{
@@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
2402 sb->s_magic = TMPFS_MAGIC; 2606 sb->s_magic = TMPFS_MAGIC;
2403 sb->s_op = &shmem_ops; 2607 sb->s_op = &shmem_ops;
2404 sb->s_time_gran = 1; 2608 sb->s_time_gran = 1;
2405#ifdef CONFIG_TMPFS_POSIX_ACL 2609#ifdef CONFIG_TMPFS_XATTR
2406 sb->s_xattr = shmem_xattr_handlers; 2610 sb->s_xattr = shmem_xattr_handlers;
2611#endif
2612#ifdef CONFIG_TMPFS_POSIX_ACL
2407 sb->s_flags |= MS_POSIXACL; 2613 sb->s_flags |= MS_POSIXACL;
2408#endif 2614#endif
2409 2615
@@ -2501,11 +2707,13 @@ static const struct file_operations shmem_file_operations = {
2501static const struct inode_operations shmem_inode_operations = { 2707static const struct inode_operations shmem_inode_operations = {
2502 .setattr = shmem_notify_change, 2708 .setattr = shmem_notify_change,
2503 .truncate_range = shmem_truncate_range, 2709 .truncate_range = shmem_truncate_range,
2710#ifdef CONFIG_TMPFS_XATTR
2711 .setxattr = shmem_setxattr,
2712 .getxattr = shmem_getxattr,
2713 .listxattr = shmem_listxattr,
2714 .removexattr = shmem_removexattr,
2715#endif
2504#ifdef CONFIG_TMPFS_POSIX_ACL 2716#ifdef CONFIG_TMPFS_POSIX_ACL
2505 .setxattr = generic_setxattr,
2506 .getxattr = generic_getxattr,
2507 .listxattr = generic_listxattr,
2508 .removexattr = generic_removexattr,
2509 .check_acl = generic_check_acl, 2717 .check_acl = generic_check_acl,
2510#endif 2718#endif
2511 2719
@@ -2523,23 +2731,27 @@ static const struct inode_operations shmem_dir_inode_operations = {
2523 .mknod = shmem_mknod, 2731 .mknod = shmem_mknod,
2524 .rename = shmem_rename, 2732 .rename = shmem_rename,
2525#endif 2733#endif
2734#ifdef CONFIG_TMPFS_XATTR
2735 .setxattr = shmem_setxattr,
2736 .getxattr = shmem_getxattr,
2737 .listxattr = shmem_listxattr,
2738 .removexattr = shmem_removexattr,
2739#endif
2526#ifdef CONFIG_TMPFS_POSIX_ACL 2740#ifdef CONFIG_TMPFS_POSIX_ACL
2527 .setattr = shmem_notify_change, 2741 .setattr = shmem_notify_change,
2528 .setxattr = generic_setxattr,
2529 .getxattr = generic_getxattr,
2530 .listxattr = generic_listxattr,
2531 .removexattr = generic_removexattr,
2532 .check_acl = generic_check_acl, 2742 .check_acl = generic_check_acl,
2533#endif 2743#endif
2534}; 2744};
2535 2745
2536static const struct inode_operations shmem_special_inode_operations = { 2746static const struct inode_operations shmem_special_inode_operations = {
2747#ifdef CONFIG_TMPFS_XATTR
2748 .setxattr = shmem_setxattr,
2749 .getxattr = shmem_getxattr,
2750 .listxattr = shmem_listxattr,
2751 .removexattr = shmem_removexattr,
2752#endif
2537#ifdef CONFIG_TMPFS_POSIX_ACL 2753#ifdef CONFIG_TMPFS_POSIX_ACL
2538 .setattr = shmem_notify_change, 2754 .setattr = shmem_notify_change,
2539 .setxattr = generic_setxattr,
2540 .getxattr = generic_getxattr,
2541 .listxattr = generic_listxattr,
2542 .removexattr = generic_removexattr,
2543 .check_acl = generic_check_acl, 2755 .check_acl = generic_check_acl,
2544#endif 2756#endif
2545}; 2757};