aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2005-09-03 18:55:18 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:52 -0400
commitf549d6c18c0e8e6cf1bf0e7a47acc1daf7e2cec1 (patch)
tree40d827736575f2a8c489761599e9a1e5e45005be
parentb5bf6c55edf94e9c7fc01724d5b271f78eaf1d3f (diff)
[PATCH] Generic VFS fallback for security xattrs
This patch modifies the VFS setxattr, getxattr, and listxattr code to fall back to the security module for security xattrs if the filesystem does not support xattrs natively. This allows security modules to export the incore inode security label information to userspace even if the filesystem does not provide xattr storage, and eliminates the need to individually patch various pseudo filesystem types to provide such access. The patch removes the existing xattr code from devpts and tmpfs as it is then no longer needed. The patch restructures the code flow slightly to reduce duplication between the normal path and the fallback path, but this should only have one user-visible side effect - a program may get -EACCES rather than -EOPNOTSUPP if policy denied access but the filesystem didn't support the operation anyway. Note that the post_setxattr hook call is not needed in the fallback case, as the inode_setsecurity hook call handles the incore inode security state update directly. In contrast, we do call fsnotify in both cases. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/Kconfig43
-rw-r--r--fs/devpts/Makefile1
-rw-r--r--fs/devpts/inode.c21
-rw-r--r--fs/devpts/xattr_security.c47
-rw-r--r--fs/xattr.c80
-rw-r--r--mm/shmem.c85
6 files changed, 49 insertions, 228 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index e54be7058359..ed78d24ee426 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -783,28 +783,6 @@ config SYSFS
783 783
784 Designers of embedded systems may wish to say N here to conserve space. 784 Designers of embedded systems may wish to say N here to conserve space.
785 785
786config DEVPTS_FS_XATTR
787 bool "/dev/pts Extended Attributes"
788 depends on UNIX98_PTYS
789 help
790 Extended attributes are name:value pairs associated with inodes by
791 the kernel or by users (see the attr(5) manual page, or visit
792 <http://acl.bestbits.at/> for details).
793
794 If unsure, say N.
795
796config DEVPTS_FS_SECURITY
797 bool "/dev/pts Security Labels"
798 depends on DEVPTS_FS_XATTR
799 help
800 Security labels support alternative access control models
801 implemented by security modules like SELinux. This option
802 enables an extended attribute handler for file security
803 labels in the /dev/pts filesystem.
804
805 If you are not using a security module that requires using
806 extended attributes for file security labels, say N.
807
808config TMPFS 786config TMPFS
809 bool "Virtual memory file system support (former shm fs)" 787 bool "Virtual memory file system support (former shm fs)"
810 help 788 help
@@ -817,27 +795,6 @@ config TMPFS
817 795
818 See <file:Documentation/filesystems/tmpfs.txt> for details. 796 See <file:Documentation/filesystems/tmpfs.txt> for details.
819 797
820config TMPFS_XATTR
821 bool "tmpfs Extended Attributes"
822 depends on TMPFS
823 help
824 Extended attributes are name:value pairs associated with inodes by
825 the kernel or by users (see the attr(5) manual page, or visit
826 <http://acl.bestbits.at/> for details).
827
828 If unsure, say N.
829
830config TMPFS_SECURITY
831 bool "tmpfs Security Labels"
832 depends on TMPFS_XATTR
833 help
834 Security labels support alternative access control models
835 implemented by security modules like SELinux. This option
836 enables an extended attribute handler for file security
837 labels in the tmpfs filesystem.
838 If you are not using a security module that requires using
839 extended attributes for file security labels, say N.
840
841config HUGETLBFS 798config HUGETLBFS
842 bool "HugeTLB file system support" 799 bool "HugeTLB file system support"
843 depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN 800 depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN
diff --git a/fs/devpts/Makefile b/fs/devpts/Makefile
index 5800df2e50c8..236696efcbac 100644
--- a/fs/devpts/Makefile
+++ b/fs/devpts/Makefile
@@ -5,4 +5,3 @@
5obj-$(CONFIG_UNIX98_PTYS) += devpts.o 5obj-$(CONFIG_UNIX98_PTYS) += devpts.o
6 6
7devpts-$(CONFIG_UNIX98_PTYS) := inode.o 7devpts-$(CONFIG_UNIX98_PTYS) := inode.o
8devpts-$(CONFIG_DEVPTS_FS_SECURITY) += xattr_security.o
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 1571c8d6c232..f2be44d4491f 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -18,28 +18,9 @@
18#include <linux/mount.h> 18#include <linux/mount.h>
19#include <linux/tty.h> 19#include <linux/tty.h>
20#include <linux/devpts_fs.h> 20#include <linux/devpts_fs.h>
21#include <linux/xattr.h>
22 21
23#define DEVPTS_SUPER_MAGIC 0x1cd1 22#define DEVPTS_SUPER_MAGIC 0x1cd1
24 23
25extern struct xattr_handler devpts_xattr_security_handler;
26
27static struct xattr_handler *devpts_xattr_handlers[] = {
28#ifdef CONFIG_DEVPTS_FS_SECURITY
29 &devpts_xattr_security_handler,
30#endif
31 NULL
32};
33
34static struct inode_operations devpts_file_inode_operations = {
35#ifdef CONFIG_DEVPTS_FS_XATTR
36 .setxattr = generic_setxattr,
37 .getxattr = generic_getxattr,
38 .listxattr = generic_listxattr,
39 .removexattr = generic_removexattr,
40#endif
41};
42
43static struct vfsmount *devpts_mnt; 24static struct vfsmount *devpts_mnt;
44static struct dentry *devpts_root; 25static struct dentry *devpts_root;
45 26
@@ -102,7 +83,6 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
102 s->s_blocksize_bits = 10; 83 s->s_blocksize_bits = 10;
103 s->s_magic = DEVPTS_SUPER_MAGIC; 84 s->s_magic = DEVPTS_SUPER_MAGIC;
104 s->s_op = &devpts_sops; 85 s->s_op = &devpts_sops;
105 s->s_xattr = devpts_xattr_handlers;
106 s->s_time_gran = 1; 86 s->s_time_gran = 1;
107 87
108 inode = new_inode(s); 88 inode = new_inode(s);
@@ -175,7 +155,6 @@ int devpts_pty_new(struct tty_struct *tty)
175 inode->i_gid = config.setgid ? config.gid : current->fsgid; 155 inode->i_gid = config.setgid ? config.gid : current->fsgid;
176 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 156 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
177 init_special_inode(inode, S_IFCHR|config.mode, device); 157 init_special_inode(inode, S_IFCHR|config.mode, device);
178 inode->i_op = &devpts_file_inode_operations;
179 inode->u.generic_ip = tty; 158 inode->u.generic_ip = tty;
180 159
181 dentry = get_node(number); 160 dentry = get_node(number);
diff --git a/fs/devpts/xattr_security.c b/fs/devpts/xattr_security.c
deleted file mode 100644
index 864cb5c79baa..000000000000
--- a/fs/devpts/xattr_security.c
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 * Security xattr support for devpts.
3 *
4 * Author: Stephen Smalley <sds@epoch.ncsc.mil>
5 * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12#include <linux/string.h>
13#include <linux/fs.h>
14#include <linux/security.h>
15#include <linux/xattr.h>
16
17static size_t
18devpts_xattr_security_list(struct inode *inode, char *list, size_t list_len,
19 const char *name, size_t name_len)
20{
21 return security_inode_listsecurity(inode, list, list_len);
22}
23
24static int
25devpts_xattr_security_get(struct inode *inode, const char *name,
26 void *buffer, size_t size)
27{
28 if (strcmp(name, "") == 0)
29 return -EINVAL;
30 return security_inode_getsecurity(inode, name, buffer, size);
31}
32
33static int
34devpts_xattr_security_set(struct inode *inode, const char *name,
35 const void *value, size_t size, int flags)
36{
37 if (strcmp(name, "") == 0)
38 return -EINVAL;
39 return security_inode_setsecurity(inode, name, value, size, flags);
40}
41
42struct xattr_handler devpts_xattr_security_handler = {
43 .prefix = XATTR_SECURITY_PREFIX,
44 .list = devpts_xattr_security_list,
45 .get = devpts_xattr_security_get,
46 .set = devpts_xattr_security_set,
47};
diff --git a/fs/xattr.c b/fs/xattr.c
index 6acd5c63da91..dc8bc7624f26 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -51,20 +51,29 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
51 } 51 }
52 } 52 }
53 53
54 down(&d->d_inode->i_sem);
55 error = security_inode_setxattr(d, kname, kvalue, size, flags);
56 if (error)
57 goto out;
54 error = -EOPNOTSUPP; 58 error = -EOPNOTSUPP;
55 if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { 59 if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
56 down(&d->d_inode->i_sem); 60 error = d->d_inode->i_op->setxattr(d, kname, kvalue,
57 error = security_inode_setxattr(d, kname, kvalue, size, flags); 61 size, flags);
58 if (error)
59 goto out;
60 error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
61 if (!error) { 62 if (!error) {
62 fsnotify_xattr(d); 63 fsnotify_xattr(d);
63 security_inode_post_setxattr(d, kname, kvalue, size, flags); 64 security_inode_post_setxattr(d, kname, kvalue,
65 size, flags);
64 } 66 }
65out: 67 } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
66 up(&d->d_inode->i_sem); 68 sizeof XATTR_SECURITY_PREFIX - 1)) {
69 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
70 error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
71 size, flags);
72 if (!error)
73 fsnotify_xattr(d);
67 } 74 }
75out:
76 up(&d->d_inode->i_sem);
68 if (kvalue) 77 if (kvalue)
69 kfree(kvalue); 78 kfree(kvalue);
70 return error; 79 return error;
@@ -139,20 +148,25 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
139 return -ENOMEM; 148 return -ENOMEM;
140 } 149 }
141 150
151 error = security_inode_getxattr(d, kname);
152 if (error)
153 goto out;
142 error = -EOPNOTSUPP; 154 error = -EOPNOTSUPP;
143 if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { 155 if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
144 error = security_inode_getxattr(d, kname);
145 if (error)
146 goto out;
147 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); 156 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
148 if (error > 0) { 157 else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
149 if (size && copy_to_user(value, kvalue, error)) 158 sizeof XATTR_SECURITY_PREFIX - 1)) {
150 error = -EFAULT; 159 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
151 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { 160 error = security_inode_getsecurity(d->d_inode, suffix, kvalue,
152 /* The file system tried to returned a value bigger 161 size);
153 than XATTR_SIZE_MAX bytes. Not possible. */ 162 }
154 error = -E2BIG; 163 if (error > 0) {
155 } 164 if (size && copy_to_user(value, kvalue, error))
165 error = -EFAULT;
166 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
167 /* The file system tried to returned a value bigger
168 than XATTR_SIZE_MAX bytes. Not possible. */
169 error = -E2BIG;
156 } 170 }
157out: 171out:
158 if (kvalue) 172 if (kvalue)
@@ -221,20 +235,24 @@ listxattr(struct dentry *d, char __user *list, size_t size)
221 return -ENOMEM; 235 return -ENOMEM;
222 } 236 }
223 237
238 error = security_inode_listxattr(d);
239 if (error)
240 goto out;
224 error = -EOPNOTSUPP; 241 error = -EOPNOTSUPP;
225 if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { 242 if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
226 error = security_inode_listxattr(d);
227 if (error)
228 goto out;
229 error = d->d_inode->i_op->listxattr(d, klist, size); 243 error = d->d_inode->i_op->listxattr(d, klist, size);
230 if (error > 0) { 244 } else {
231 if (size && copy_to_user(list, klist, error)) 245 error = security_inode_listsecurity(d->d_inode, klist, size);
232 error = -EFAULT; 246 if (size && error >= size)
233 } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { 247 error = -ERANGE;
234 /* The file system tried to returned a list bigger 248 }
235 than XATTR_LIST_MAX bytes. Not possible. */ 249 if (error > 0) {
236 error = -E2BIG; 250 if (size && copy_to_user(list, klist, error))
237 } 251 error = -EFAULT;
252 } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
253 /* The file system tried to returned a list bigger
254 than XATTR_LIST_MAX bytes. Not possible. */
255 error = -E2BIG;
238 } 256 }
239out: 257out:
240 if (klist) 258 if (klist)
diff --git a/mm/shmem.c b/mm/shmem.c
index 08a3bc2fba61..bdc4bbb6ddbb 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -45,7 +45,6 @@
45#include <linux/swapops.h> 45#include <linux/swapops.h>
46#include <linux/mempolicy.h> 46#include <linux/mempolicy.h>
47#include <linux/namei.h> 47#include <linux/namei.h>
48#include <linux/xattr.h>
49#include <asm/uaccess.h> 48#include <asm/uaccess.h>
50#include <asm/div64.h> 49#include <asm/div64.h>
51#include <asm/pgtable.h> 50#include <asm/pgtable.h>
@@ -179,7 +178,6 @@ static struct address_space_operations shmem_aops;
179static struct file_operations shmem_file_operations; 178static struct file_operations shmem_file_operations;
180static struct inode_operations shmem_inode_operations; 179static struct inode_operations shmem_inode_operations;
181static struct inode_operations shmem_dir_inode_operations; 180static struct inode_operations shmem_dir_inode_operations;
182static struct inode_operations shmem_special_inode_operations;
183static struct vm_operations_struct shmem_vm_ops; 181static struct vm_operations_struct shmem_vm_ops;
184 182
185static struct backing_dev_info shmem_backing_dev_info = { 183static struct backing_dev_info shmem_backing_dev_info = {
@@ -1300,7 +1298,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
1300 1298
1301 switch (mode & S_IFMT) { 1299 switch (mode & S_IFMT) {
1302 default: 1300 default:
1303 inode->i_op = &shmem_special_inode_operations;
1304 init_special_inode(inode, mode, dev); 1301 init_special_inode(inode, mode, dev);
1305 break; 1302 break;
1306 case S_IFREG: 1303 case S_IFREG:
@@ -1804,12 +1801,6 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
1804static struct inode_operations shmem_symlink_inline_operations = { 1801static struct inode_operations shmem_symlink_inline_operations = {
1805 .readlink = generic_readlink, 1802 .readlink = generic_readlink,
1806 .follow_link = shmem_follow_link_inline, 1803 .follow_link = shmem_follow_link_inline,
1807#ifdef CONFIG_TMPFS_XATTR
1808 .setxattr = generic_setxattr,
1809 .getxattr = generic_getxattr,
1810 .listxattr = generic_listxattr,
1811 .removexattr = generic_removexattr,
1812#endif
1813}; 1804};
1814 1805
1815static struct inode_operations shmem_symlink_inode_operations = { 1806static struct inode_operations shmem_symlink_inode_operations = {
@@ -1817,12 +1808,6 @@ static struct inode_operations shmem_symlink_inode_operations = {
1817 .readlink = generic_readlink, 1808 .readlink = generic_readlink,
1818 .follow_link = shmem_follow_link, 1809 .follow_link = shmem_follow_link,
1819 .put_link = shmem_put_link, 1810 .put_link = shmem_put_link,
1820#ifdef CONFIG_TMPFS_XATTR
1821 .setxattr = generic_setxattr,
1822 .getxattr = generic_getxattr,
1823 .listxattr = generic_listxattr,
1824 .removexattr = generic_removexattr,
1825#endif
1826}; 1811};
1827 1812
1828static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes) 1813static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
@@ -1942,12 +1927,6 @@ static void shmem_put_super(struct super_block *sb)
1942 sb->s_fs_info = NULL; 1927 sb->s_fs_info = NULL;
1943} 1928}
1944 1929
1945#ifdef CONFIG_TMPFS_XATTR
1946static struct xattr_handler *shmem_xattr_handlers[];
1947#else
1948#define shmem_xattr_handlers NULL
1949#endif
1950
1951static int shmem_fill_super(struct super_block *sb, 1930static int shmem_fill_super(struct super_block *sb,
1952 void *data, int silent) 1931 void *data, int silent)
1953{ 1932{
@@ -1998,7 +1977,6 @@ static int shmem_fill_super(struct super_block *sb,
1998 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 1977 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1999 sb->s_magic = TMPFS_MAGIC; 1978 sb->s_magic = TMPFS_MAGIC;
2000 sb->s_op = &shmem_ops; 1979 sb->s_op = &shmem_ops;
2001 sb->s_xattr = shmem_xattr_handlers;
2002 1980
2003 inode = shmem_get_inode(sb, S_IFDIR | mode, 0); 1981 inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
2004 if (!inode) 1982 if (!inode)
@@ -2087,12 +2065,6 @@ static struct file_operations shmem_file_operations = {
2087static struct inode_operations shmem_inode_operations = { 2065static struct inode_operations shmem_inode_operations = {
2088 .truncate = shmem_truncate, 2066 .truncate = shmem_truncate,
2089 .setattr = shmem_notify_change, 2067 .setattr = shmem_notify_change,
2090#ifdef CONFIG_TMPFS_XATTR
2091 .setxattr = generic_setxattr,
2092 .getxattr = generic_getxattr,
2093 .listxattr = generic_listxattr,
2094 .removexattr = generic_removexattr,
2095#endif
2096}; 2068};
2097 2069
2098static struct inode_operations shmem_dir_inode_operations = { 2070static struct inode_operations shmem_dir_inode_operations = {
@@ -2106,21 +2078,6 @@ static struct inode_operations shmem_dir_inode_operations = {
2106 .rmdir = shmem_rmdir, 2078 .rmdir = shmem_rmdir,
2107 .mknod = shmem_mknod, 2079 .mknod = shmem_mknod,
2108 .rename = shmem_rename, 2080 .rename = shmem_rename,
2109#ifdef CONFIG_TMPFS_XATTR
2110 .setxattr = generic_setxattr,
2111 .getxattr = generic_getxattr,
2112 .listxattr = generic_listxattr,
2113 .removexattr = generic_removexattr,
2114#endif
2115#endif
2116};
2117
2118static struct inode_operations shmem_special_inode_operations = {
2119#ifdef CONFIG_TMPFS_XATTR
2120 .setxattr = generic_setxattr,
2121 .getxattr = generic_getxattr,
2122 .listxattr = generic_listxattr,
2123 .removexattr = generic_removexattr,
2124#endif 2081#endif
2125}; 2082};
2126 2083
@@ -2146,48 +2103,6 @@ static struct vm_operations_struct shmem_vm_ops = {
2146}; 2103};
2147 2104
2148 2105
2149#ifdef CONFIG_TMPFS_SECURITY
2150
2151static size_t shmem_xattr_security_list(struct inode *inode, char *list, size_t list_len,
2152 const char *name, size_t name_len)
2153{
2154 return security_inode_listsecurity(inode, list, list_len);
2155}
2156
2157static int shmem_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size)
2158{
2159 if (strcmp(name, "") == 0)
2160 return -EINVAL;
2161 return security_inode_getsecurity(inode, name, buffer, size);
2162}
2163
2164static int shmem_xattr_security_set(struct inode *inode, const char *name, const void *value, size_t size, int flags)
2165{
2166 if (strcmp(name, "") == 0)
2167 return -EINVAL;
2168 return security_inode_setsecurity(inode, name, value, size, flags);
2169}
2170
2171static struct xattr_handler shmem_xattr_security_handler = {
2172 .prefix = XATTR_SECURITY_PREFIX,
2173 .list = shmem_xattr_security_list,
2174 .get = shmem_xattr_security_get,
2175 .set = shmem_xattr_security_set,
2176};
2177
2178#endif /* CONFIG_TMPFS_SECURITY */
2179
2180#ifdef CONFIG_TMPFS_XATTR
2181
2182static struct xattr_handler *shmem_xattr_handlers[] = {
2183#ifdef CONFIG_TMPFS_SECURITY
2184 &shmem_xattr_security_handler,
2185#endif
2186 NULL
2187};
2188
2189#endif /* CONFIG_TMPFS_XATTR */
2190
2191static struct super_block *shmem_get_sb(struct file_system_type *fs_type, 2106static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
2192 int flags, const char *dev_name, void *data) 2107 int flags, const char *dev_name, void *data)
2193{ 2108{