From f549d6c18c0e8e6cf1bf0e7a47acc1daf7e2cec1 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Sat, 3 Sep 2005 15:55:18 -0700 Subject: [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 Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/xattr.c | 80 ++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 31 deletions(-) (limited to 'fs/xattr.c') 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, } } + down(&d->d_inode->i_sem); + error = security_inode_setxattr(d, kname, kvalue, size, flags); + if (error) + goto out; error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { - down(&d->d_inode->i_sem); - error = security_inode_setxattr(d, kname, kvalue, size, flags); - if (error) - goto out; - error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); + error = d->d_inode->i_op->setxattr(d, kname, kvalue, + size, flags); if (!error) { fsnotify_xattr(d); - security_inode_post_setxattr(d, kname, kvalue, size, flags); + security_inode_post_setxattr(d, kname, kvalue, + size, flags); } -out: - up(&d->d_inode->i_sem); + } else if (!strncmp(kname, XATTR_SECURITY_PREFIX, + sizeof XATTR_SECURITY_PREFIX - 1)) { + const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; + error = security_inode_setsecurity(d->d_inode, suffix, kvalue, + size, flags); + if (!error) + fsnotify_xattr(d); } +out: + up(&d->d_inode->i_sem); if (kvalue) kfree(kvalue); return error; @@ -139,20 +148,25 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size) return -ENOMEM; } + error = security_inode_getxattr(d, kname); + if (error) + goto out; error = -EOPNOTSUPP; - if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { - error = security_inode_getxattr(d, kname); - if (error) - goto out; + if (d->d_inode->i_op && d->d_inode->i_op->getxattr) error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); - if (error > 0) { - if (size && copy_to_user(value, kvalue, error)) - error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { - /* The file system tried to returned a value bigger - than XATTR_SIZE_MAX bytes. Not possible. */ - error = -E2BIG; - } + else if (!strncmp(kname, XATTR_SECURITY_PREFIX, + sizeof XATTR_SECURITY_PREFIX - 1)) { + const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; + error = security_inode_getsecurity(d->d_inode, suffix, kvalue, + size); + } + if (error > 0) { + if (size && copy_to_user(value, kvalue, error)) + error = -EFAULT; + } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { + /* The file system tried to returned a value bigger + than XATTR_SIZE_MAX bytes. Not possible. */ + error = -E2BIG; } out: if (kvalue) @@ -221,20 +235,24 @@ listxattr(struct dentry *d, char __user *list, size_t size) return -ENOMEM; } + error = security_inode_listxattr(d); + if (error) + goto out; error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { - error = security_inode_listxattr(d); - if (error) - goto out; error = d->d_inode->i_op->listxattr(d, klist, size); - if (error > 0) { - if (size && copy_to_user(list, klist, error)) - error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { - /* The file system tried to returned a list bigger - than XATTR_LIST_MAX bytes. Not possible. */ - error = -E2BIG; - } + } else { + error = security_inode_listsecurity(d->d_inode, klist, size); + if (size && error >= size) + error = -ERANGE; + } + if (error > 0) { + if (size && copy_to_user(list, klist, error)) + error = -EFAULT; + } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { + /* The file system tried to returned a list bigger + than XATTR_LIST_MAX bytes. Not possible. */ + error = -E2BIG; } out: if (klist) -- cgit v1.2.3-58-ga151