[PATCH] move xattr permission checks into the VFS
authorakpm@osdl.org <akpm@osdl.org>
Tue, 10 Jan 2006 04:51:56 +0000 (20:51 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 10 Jan 2006 16:01:29 +0000 (08:01 -0800)
\r)

From: Christoph Hellwig <hch@lst.de>

The xattr code has rather complex permission checks because the rules are very
different for different attribute namespaces.  This patch moves as much as we
can into the generic code.  Currently all the major disk based filesystems
duplicate these checks, while many minor filesystems or network filesystems
lack some or all of them.

To do this we need defines for the extended attribute names in common code, I
moved them up from JFS which had the nicest defintions.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Dave Kleikamp <shaggy@austin.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/jfs/xattr.c
fs/xattr.c
include/linux/xattr.h

index 23aa5066b5a438014d84a2d0491c79e49b25e4dd..9dde36a1eb5d44c015213907acff232f98cf3368 100644 (file)
@@ -83,21 +83,6 @@ struct ea_buffer {
 #define EA_NEW         0x0004
 #define EA_MALLOC      0x0008
 
-/* Namespaces */
-#define XATTR_SYSTEM_PREFIX "system."
-#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1)
-
-#define XATTR_USER_PREFIX "user."
-#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
-
-#define XATTR_OS2_PREFIX "os2."
-#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
-
-/* XATTR_SECURITY_PREFIX is defined in include/linux/xattr.h */
-#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
-
-#define XATTR_TRUSTED_PREFIX "trusted."
-#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
 
 /*
  * These three routines are used to recognize on-disk extended attributes
index fee804e69a9a40206fd55ca81dc3c31ace876eca..80eca7d3d69f68272a70b4a79bdc7c8f6d273ebf 100644 (file)
 #include <asm/uaccess.h>
 
 
+/*
+ * Check permissions for extended attribute access.  This is a bit complicated
+ * because different namespaces have very different rules.
+ */
+static int
+xattr_permission(struct inode *inode, const char *name, int mask)
+{
+       /*
+        * We can never set or remove an extended attribute on a read-only
+        * filesystem  or on an immutable / append-only inode.
+        */
+       if (mask & MAY_WRITE) {
+               if (IS_RDONLY(inode))
+                       return -EROFS;
+               if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+                       return -EPERM;
+       }
+
+       /*
+        * No restriction for security.* and system.* from the VFS.  Decision
+        * on these is left to the underlying filesystem / security module.
+        */
+       if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
+           !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return 0;
+
+       /*
+        * The trusted.* namespace can only accessed by a privilegued user.
+        */
+       if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
+               return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM);
+
+       if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
+               if (!S_ISREG(inode->i_mode) &&
+                   (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+                       return -EPERM;
+       }
+
+       return permission(inode, mask, NULL);
+}
+
 int
 vfs_setxattr(struct dentry *dentry, char *name, void *value,
                size_t size, int flags)
@@ -27,6 +68,10 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value,
        struct inode *inode = dentry->d_inode;
        int error;
 
+       error = xattr_permission(inode, name, MAY_WRITE);
+       if (error)
+               return error;
+
        mutex_lock(&inode->i_mutex);
        error = security_inode_setxattr(dentry, name, value, size, flags);
        if (error)
@@ -40,8 +85,8 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value,
                                                     size, flags);
                }
        } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                               sizeof XATTR_SECURITY_PREFIX - 1)) {
-               const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
+                               XATTR_SECURITY_PREFIX_LEN)) {
+               const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
                error = security_inode_setsecurity(inode, suffix, value,
                                                   size, flags);
                if (!error)
@@ -59,6 +104,10 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
        struct inode *inode = dentry->d_inode;
        int error;
 
+       error = xattr_permission(inode, name, MAY_READ);
+       if (error)
+               return error;
+
        error = security_inode_getxattr(dentry, name);
        if (error)
                return error;
@@ -69,8 +118,8 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
                error = -EOPNOTSUPP;
 
        if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                               sizeof XATTR_SECURITY_PREFIX - 1)) {
-               const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
+                               XATTR_SECURITY_PREFIX_LEN)) {
+               const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
                int ret = security_inode_getsecurity(inode, suffix, value,
                                                     size, error);
                /*
@@ -94,6 +143,10 @@ vfs_removexattr(struct dentry *dentry, char *name)
        if (!inode->i_op->removexattr)
                return -EOPNOTSUPP;
 
+       error = xattr_permission(inode, name, MAY_WRITE);
+       if (error)
+               return error;
+
        error = security_inode_removexattr(dentry, name);
        if (error)
                return error;
index 366f0ab4219fc124683a1d2561d9da9d65a85378..cda8a96e2fa039f6e43c92b973f34eac9d5d8e6d 100644 (file)
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
 #define XATTR_REPLACE  0x2     /* set value, fail if attr does not exist */
 
+/* Namespaces */
+#define XATTR_OS2_PREFIX "os2."
+#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
+
 #define XATTR_SECURITY_PREFIX  "security."
+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
+
+#define XATTR_SYSTEM_PREFIX "system."
+#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1)
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
+
+#define XATTR_USER_PREFIX "user."
+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+
 
 struct xattr_handler {
        char *prefix;