[RFC 1/1] xattr: provide integrity. namespace to read real values

From: Dmitry Kasatkin
Date: Wed Feb 13 2013 - 04:08:06 EST


User space tools use getxattr() system call to read values of extended
attributes. getxattr() system call uses vfs_getattr(), which for "security."
namespace might get a value of the xattr indirectly from LSM via calling
xattr_getsecurity(). For that reason value set by setxattr and read by getxattr
might differ.

Here is an example of SMACK label, which shows that set and read values are
different:

setfattr -n security.SMACK64 -v "hello world" foo
getfattr -n security.SMACK64 foo
# file: foo
security.SMACK64="hello"

EVM uses vfs_getxattr_alloc(), which directly reads xattr values from the file
system. When performing the file system labeling with digital signatures, it is
necessary to read real xattr values in order to generate the correct signatures.

This patch adds the virtual "integrity." name space, which allows to bypass
calling LSM and read real extended attribute values.

getfattr -e text -n integrity.SMACK64 foo
# file: foo
integrity.SMACK64="hello world"

Suggested-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@xxxxxxxxx>
---
fs/xattr.c | 22 +++++++++++++++++++---
include/uapi/linux/xattr.h | 4 ++++
2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/fs/xattr.c b/fs/xattr.c
index 3377dff..76c2620 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -232,12 +232,28 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
int error;
+ char *usename = (char *)name, name_buf[XATTR_NAME_MAX];
+
+ /* because this function calls LSM for "security." namespace,
+ * it may be impossible to get real value stored in xattr.
+ * An LSM may mangle the attribute value to its own ends.
+ * Smack is known to do this.
+ * virtual namespace "integrity." is used to fetch real
+ * security attributes without talking to LSM
+ */
+ if (!strncmp(name, XATTR_INTEGRITY_PREFIX,
+ XATTR_INTEGRITY_PREFIX_LEN)) {
+ /* replace "integrity. with security. */
+ snprintf(name_buf, sizeof(name_buf), "security.%s",
+ name + XATTR_INTEGRITY_PREFIX_LEN);
+ usename = name_buf;
+ }

- error = xattr_permission(inode, name, MAY_READ);
+ error = xattr_permission(inode, usename, MAY_READ);
if (error)
return error;

- error = security_inode_getxattr(dentry, name);
+ error = security_inode_getxattr(dentry, usename);
if (error)
return error;

@@ -255,7 +271,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
}
nolsm:
if (inode->i_op->getxattr)
- error = inode->i_op->getxattr(dentry, name, value, size);
+ error = inode->i_op->getxattr(dentry, usename, value, size);
else
error = -EOPNOTSUPP;

diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
index 26607bd..133998b 100644
--- a/include/uapi/linux/xattr.h
+++ b/include/uapi/linux/xattr.h
@@ -20,6 +20,10 @@
#define XATTR_SECURITY_PREFIX "security."
#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)

+/* integrity - security mirror namespace for integrity purpose */
+#define XATTR_INTEGRITY_PREFIX "integrity."
+#define XATTR_INTEGRITY_PREFIX_LEN (sizeof (XATTR_INTEGRITY_PREFIX) - 1)
+
#define XATTR_SYSTEM_PREFIX "system."
#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1)

--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/