From: Mimi Zohar on
Based on xattr_permission comments, the restriction to modify
'security' xattr is left up to the underlying fs or lsm. Ensure
that not just anyone can modify or remove 'security.ima'.

Changelog:
- Replace CAP_MAC_ADMIN with CAP_SYS_ADMIN
- static inline ima_inode_setxattr()/ima_inode_removexattr() stubs
- ima_protect_xattr should be static

Signed-off-by: Mimi Zohar <zohar(a)us.ibm.com>
---
include/linux/ima.h | 16 ++++++++++++++++
security/integrity/ima/ima_main.c | 26 ++++++++++++++++++++++++++
security/security.c | 6 ++++++
3 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index ce82e29..2f87cf8 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -20,6 +20,9 @@ extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
extern void ima_counts_get(struct file *file);
extern void ima_inode_post_setattr(struct dentry *dentry);
+extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len);
+extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);

#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -52,5 +55,18 @@ static inline void ima_inode_post_setattr(struct dentry *dentry)
return;
}

+static inline int ima_inode_setxattr(struct dentry *dentry,
+ const char *xattr_name,
+ const void *xattr_value,
+ size_t xattr_value_len)
+{
+ return 0;
+}
+
+static inline int ima_inode_removexattr(struct dentry *dentry,
+ const char *xattr_name)
+{
+ return 0;
+}
#endif /* CONFIG_IMA_H */
#endif /* _LINUX_IMA_H */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index d6132b9..6531765 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -372,6 +372,32 @@ void ima_inode_post_setattr(struct dentry *dentry)
return;
}

+/*
+ * ima_protect_xattr - protect 'security.ima'
+ *
+ * Ensure that not just anyone can modify or remove 'security.ima'.
+ */
+static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ if ((strcmp(xattr_name, XATTR_NAME_IMA) == 0)
+ && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ return ima_protect_xattr(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+}
+
+int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+ return ima_protect_xattr(dentry, xattr_name, NULL, 0);
+}
+
static int __init init_ima(void)
{
int error;
diff --git a/security/security.c b/security/security.c
index c373c5f..53c6285 100644
--- a/security/security.c
+++ b/security/security.c
@@ -556,6 +556,9 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
if (ret)
return ret;
+ ret = ima_inode_setxattr(dentry, name, value, size);
+ if (ret)
+ return ret;
return evm_inode_setxattr(dentry, name, value, size);
}

@@ -591,6 +594,9 @@ int security_inode_removexattr(struct dentry *dentry, const char *name)
ret = security_ops->inode_removexattr(dentry, name);
if (ret)
return ret;
+ ret = ima_inode_removexattr(dentry, name);
+ if (ret)
+ return ret;
return evm_inode_removexattr(dentry, name);
}

--
1.7.1.1

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