Discussion:
[RFC PATCH 2/2] fs: Grant CAP_TRUSTED rw access to trusted xattrs
Nicolas Belouin
2017-10-21 13:45:58 UTC
Permalink
The trusted xattrs read/write access is the perfect use case for
CAP_TRUSTED.

Signed-off-by: Nicolas Belouin <***@belouin.fr>
---
fs/ext2/xattr_trusted.c | 2 +-
fs/ext4/xattr_trusted.c | 2 +-
fs/f2fs/xattr.c | 6 +++---
fs/hfsplus/xattr.c | 2 +-
fs/jffs2/xattr_trusted.c | 2 +-
fs/jfs/xattr.c | 3 ++-
fs/ocfs2/xattr.c | 2 +-
fs/overlayfs/inode.c | 3 ++-
fs/reiserfs/xattr_trusted.c | 11 ++++++++---
fs/squashfs/xattr.c | 2 +-
fs/ubifs/xattr.c | 3 ++-
fs/xattr.c | 4 ++--
12 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index 65049b71af13..8006c24f8ee0 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -11,7 +11,7 @@
static bool
ext2_xattr_trusted_list(struct dentry *dentry)
{
- return capable(CAP_SYS_ADMIN);
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

static int
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
index c7765c735714..9849d1e0ebb9 100644
--- a/fs/ext4/xattr_trusted.c
+++ b/fs/ext4/xattr_trusted.c
@@ -15,7 +15,7 @@
static bool
ext4_xattr_trusted_list(struct dentry *dentry)
{
- return capable(CAP_SYS_ADMIN);
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

static int
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 7c65540148f8..ef572464deca 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -37,7 +37,7 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
return -EOPNOTSUPP;
break;
case F2FS_XATTR_INDEX_TRUSTED:
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_TRUSTED))
return -EPERM;
break;
case F2FS_XATTR_INDEX_SECURITY:
@@ -62,7 +62,7 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
return -EOPNOTSUPP;
break;
case F2FS_XATTR_INDEX_TRUSTED:
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_TRUSTED))
return -EPERM;
break;
case F2FS_XATTR_INDEX_SECURITY:
@@ -83,7 +83,7 @@ static bool f2fs_xattr_user_list(struct dentry *dentry)

static bool f2fs_xattr_trusted_list(struct dentry *dentry)
{
- return capable(CAP_SYS_ADMIN);
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index ae03a19196ef..0ec6d02ee7e9 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -606,7 +606,7 @@ static inline int can_list(const char *xattr_name)

return !strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN) ||
- capable(CAP_SYS_ADMIN);
+ capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c
index 5d6030826c52..3c7ae98e4525 100644
--- a/fs/jffs2/xattr_trusted.c
+++ b/fs/jffs2/xattr_trusted.c
@@ -35,7 +35,7 @@ static int jffs2_trusted_setxattr(const struct xattr_handler *handler,

static bool jffs2_trusted_listxattr(struct dentry *dentry)
{
- return capable(CAP_SYS_ADMIN);
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

const struct xattr_handler jffs2_trusted_xattr_handler = {
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 1c46573a96ed..e4f44f5133a1 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -859,7 +859,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
static inline int can_list(struct jfs_ea *ea)
{
return (!strncmp(ea->name, XATTR_TRUSTED_PREFIX,
- XATTR_TRUSTED_PREFIX_LEN) || capable(CAP_SYS_ADMIN));
+ XATTR_TRUSTED_PREFIX_LEN) ||
+ capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED));
}

ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 5fdf269ba82e..2b3994d192c6 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -906,7 +906,7 @@ static int ocfs2_xattr_list_entry(struct super_block *sb,
break;

case OCFS2_XATTR_INDEX_TRUSTED:
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_TRUSTED))
return 0;
break;
}
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index a619addecafc..c627003d3a74 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -264,7 +264,8 @@ static bool ovl_can_list(const char *s)
return true;

/* Never list trusted.overlay, list other trusted for superuser only */
- return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN);
+ return !ovl_is_private_xattr(s) &&
+ (capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED));
}

ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c
index f15a5f9e84ce..6f3fa0db8272 100644
--- a/fs/reiserfs/xattr_trusted.c
+++ b/fs/reiserfs/xattr_trusted.c
@@ -7,11 +7,16 @@
#include "xattr.h"
#include <linux/uaccess.h>

+inline bool trusted_capable(void)
+{
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
+}
+
static int
trusted_get(const struct xattr_handler *handler, struct dentry *unused,
struct inode *inode, const char *name, void *buffer, size_t size)
{
- if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
+ if (!trusted_capable() || IS_PRIVATE(inode))
return -EPERM;

return reiserfs_xattr_get(inode, xattr_full_name(handler, name),
@@ -23,7 +28,7 @@ trusted_set(const struct xattr_handler *handler, struct dentry *unused,
struct inode *inode, const char *name, const void *buffer,
size_t size, int flags)
{
- if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
+ if (!trusted_capable() || IS_PRIVATE(inode))
return -EPERM;

return reiserfs_xattr_set(inode,
@@ -33,7 +38,7 @@ trusted_set(const struct xattr_handler *handler, struct dentry *unused,

static bool trusted_list(struct dentry *dentry)
{
- return capable(CAP_SYS_ADMIN) && !IS_PRIVATE(d_inode(dentry));
+ return trusted_capable() && !IS_PRIVATE(d_inode(dentry));
}

const struct xattr_handler reiserfs_xattr_trusted_handler = {
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c
index 1548b3784548..e0a285ab1f7e 100644
--- a/fs/squashfs/xattr.c
+++ b/fs/squashfs/xattr.c
@@ -237,7 +237,7 @@ static const struct xattr_handler squashfs_xattr_user_handler = {
*/
static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
{
- return capable(CAP_SYS_ADMIN);
+ return capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
}

static const struct xattr_handler squashfs_xattr_trusted_handler = {
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index c13eae819cbc..f3aa8be72a66 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -406,7 +406,8 @@ static bool xattr_visible(const char *name)

/* Show trusted namespace only for "power" users */
if (strncmp(name, XATTR_TRUSTED_PREFIX,
- XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
+ XATTR_TRUSTED_PREFIX_LEN) == 0 &&
+ !capable(CAP_SYS_ADMIN) && !capable(CAP_TRUSTED))
return false;

return true;
diff --git a/fs/xattr.c b/fs/xattr.c
index 61cd28ba25f3..d9e9a0083dbb 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -113,7 +113,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
* The trusted.* namespace can only be accessed by privileged users.
*/
if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_TRUSTED))
return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
return 0;
}
@@ -945,7 +945,7 @@ static int xattr_list_one(char **buffer, ssize_t *remaining_size,
ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
char *buffer, size_t size)
{
- bool trusted = capable(CAP_SYS_ADMIN);
+ bool trusted = capable(CAP_SYS_ADMIN) || capable(CAP_TRUSTED);
struct simple_xattr *xattr;
ssize_t remaining_size = size;
int err = 0;
--
2.14.2
Serge E. Hallyn
2017-10-21 16:03:02 UTC
Permalink
with CAP_SYS_ADMIN being bloated, the usefulness of using it to
flag a process to be entrusted for e.g reading and writing trusted
xattr is near zero.
CAP_TRUSTED aims to provide userland with a way to mark a process as
entrusted to do specific (not specially admin-centered) actions. It
would for example allow a process to red/write the trusted xattrs.
You say "for example". Are you intending to add more uses? If so, what
are they? If not, how about renaming it CAP_TRUSTED_XATTR?

What all does allowing writes to trusted xattrs give you? There are
the overlayfs whiteouts, what else?
n***@belouin.fr
2017-10-21 19:09:32 UTC
Permalink
Post by Serge E. Hallyn
with CAP_SYS_ADMIN being bloated, the usefulness of using it to
flag a process to be entrusted for e.g reading and writing trusted
xattr is near zero.
CAP_TRUSTED aims to provide userland with a way to mark a process as
entrusted to do specific (not specially admin-centered) actions. It
would for example allow a process to red/write the trusted xattrs.
You say "for example". Are you intending to add more uses? If so, what
are they? If not, how about renaming it CAP_TRUSTED_XATTR?
I don't see any other use for now, but I don't want it to be too narrow and non usable in a similar context in the future. So I believe the underlying purpose of marking a process as "trusted" (even if for now it only means rw permission on trusted xattr) is more meaningful.
Post by Serge E. Hallyn
What all does allowing writes to trusted xattrs give you? There are
the overlayfs whiteouts, what else?
Nicolas

Casey Schaufler
2017-10-21 17:25:21 UTC
Permalink
with CAP_SYS_ADMIN being bloated, the usefulness of using it to
flag a process to be entrusted for e.g reading and writing trusted
xattr is near zero.
CAP_TRUSTED aims to provide userland with a way to mark a process as
entrusted to do specific (not specially admin-centered) actions. It
would for example allow a process to red/write the trusted xattrs.
Please explain how this is different from CAP_MAC_ADMIN in
any existing use case. If it is significantly different, how
would the two interact?
---
include/uapi/linux/capability.h | 6 +++++-
security/selinux/include/classmap.h | 5 +++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
index ce230aa6d928..27e457b93c84 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -369,7 +369,11 @@ struct vfs_ns_cap_data {
#define CAP_SYS_MOUNT 38
-#define CAP_LAST_CAP CAP_SYS_MOUNT
+/* Allow read/write trusted xattr */
+
+#define CAP_TRUSTED 39
+
+#define CAP_LAST_CAP CAP_TRUSTED
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index a873dce97fd5..f5dc8e109f5a 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -24,9 +24,10 @@
"audit_control", "setfcap"
#define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \
- "wake_alarm", "block_suspend", "audit_read", "sys_mount"
+ "wake_alarm", "block_suspend", "audit_read", "sys_mount", \
+ "trusted"
-#if CAP_LAST_CAP > CAP_SYS_MOUNT
+#if CAP_LAST_CAP > CAP_TRUSTED
#error New capability defined, please update COMMON_CAP2_PERMS.
#endif
n***@belouin.fr
2017-10-21 19:04:48 UTC
Permalink
Post by Casey Schaufler
with CAP_SYS_ADMIN being bloated, the usefulness of using it to
flag a process to be entrusted for e.g reading and writing trusted
xattr is near zero.
CAP_TRUSTED aims to provide userland with a way to mark a process as
entrusted to do specific (not specially admin-centered) actions. It
would for example allow a process to red/write the trusted xattrs.
Please explain how this is different from CAP_MAC_ADMIN in
any existing use case. If it is significantly different, how
would the two interact?
From my point of view, CAP_MAC_ADMIN allows one to read/write security xattrs, those are meant to describe security policies. As far as I know of, trusted xattrs are intended for a privileged process to read or write arbitrary data. I don't have any real world example in mind that use trusted xattrs, but I'll try to find one.
Post by Casey Schaufler
---
include/uapi/linux/capability.h | 6 +++++-
security/selinux/include/classmap.h | 5 +++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/uapi/linux/capability.h
b/include/uapi/linux/capability.h
index ce230aa6d928..27e457b93c84 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -369,7 +369,11 @@ struct vfs_ns_cap_data {
#define CAP_SYS_MOUNT 38
-#define CAP_LAST_CAP CAP_SYS_MOUNT
+/* Allow read/write trusted xattr */
+
+#define CAP_TRUSTED 39
+
+#define CAP_LAST_CAP CAP_TRUSTED
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
diff --git a/security/selinux/include/classmap.h
b/security/selinux/include/classmap.h
index a873dce97fd5..f5dc8e109f5a 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -24,9 +24,10 @@
"audit_control", "setfcap"
#define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \
- "wake_alarm", "block_suspend", "audit_read", "sys_mount"
+ "wake_alarm", "block_suspend", "audit_read", "sys_mount", \
+ "trusted"
-#if CAP_LAST_CAP > CAP_SYS_MOUNT
+#if CAP_LAST_CAP > CAP_TRUSTED
#error New capability defined, please update COMMON_CAP2_PERMS.
#endif
Nicolas
Loading...