diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2005-09-03 18:55:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:05:52 -0400 |
commit | f549d6c18c0e8e6cf1bf0e7a47acc1daf7e2cec1 (patch) | |
tree | 40d827736575f2a8c489761599e9a1e5e45005be /fs | |
parent | b5bf6c55edf94e9c7fc01724d5b271f78eaf1d3f (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 43 | ||||
-rw-r--r-- | fs/devpts/Makefile | 1 | ||||
-rw-r--r-- | fs/devpts/inode.c | 21 | ||||
-rw-r--r-- | fs/devpts/xattr_security.c | 47 | ||||
-rw-r--r-- | fs/xattr.c | 80 |
5 files changed, 49 insertions, 143 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 | ||
786 | config 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 | |||
796 | config 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 | |||
808 | config TMPFS | 786 | config 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 | ||
820 | config 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 | |||
830 | config 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 | |||
841 | config HUGETLBFS | 798 | config 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 @@ | |||
5 | obj-$(CONFIG_UNIX98_PTYS) += devpts.o | 5 | obj-$(CONFIG_UNIX98_PTYS) += devpts.o |
6 | 6 | ||
7 | devpts-$(CONFIG_UNIX98_PTYS) := inode.o | 7 | devpts-$(CONFIG_UNIX98_PTYS) := inode.o |
8 | devpts-$(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 | ||
25 | extern struct xattr_handler devpts_xattr_security_handler; | ||
26 | |||
27 | static struct xattr_handler *devpts_xattr_handlers[] = { | ||
28 | #ifdef CONFIG_DEVPTS_FS_SECURITY | ||
29 | &devpts_xattr_security_handler, | ||
30 | #endif | ||
31 | NULL | ||
32 | }; | ||
33 | |||
34 | static 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 | |||
43 | static struct vfsmount *devpts_mnt; | 24 | static struct vfsmount *devpts_mnt; |
44 | static struct dentry *devpts_root; | 25 | static 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 | |||
17 | static size_t | ||
18 | devpts_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 | |||
24 | static int | ||
25 | devpts_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 | |||
33 | static int | ||
34 | devpts_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 | |||
42 | struct 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 | } |
65 | out: | 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 | } |
75 | out: | ||
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 | } |
157 | out: | 171 | out: |
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 | } |
239 | out: | 257 | out: |
240 | if (klist) | 258 | if (klist) |