|
From: Dmitry K. <d.k...@sa...> - 2014-10-03 11:08:44
|
Changing immutable flag allows root to modify inode attributes
and file content. Protecting immutable state prevents root without
CAP_LINUX_IMMUTABLE capability getting unwanted access to the file.
This patch includes S_IMMUTABLE to HMAC calculation.
New hook evm_vfs_ioctl_post() is provided to recalculate HMAC
when S_IMMUTABLE might change.
Signed-off-by: Dmitry Kasatkin <d.k...@sa...>
---
fs/compat_ioctl.c | 3 +++
fs/ioctl.c | 3 +++
include/linux/evm.h | 7 +++++++
security/integrity/evm/Kconfig | 13 +++++++++++++
security/integrity/evm/evm.h | 1 +
security/integrity/evm/evm_crypto.c | 4 ++++
security/integrity/evm/evm_main.c | 22 ++++++++++++++++++++++
7 files changed, 53 insertions(+)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e822890..c8210d6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -57,6 +57,7 @@
#include <linux/i2c-dev.h>
#include <linux/atalk.h>
#include <linux/gfp.h>
+#include <linux/evm.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
@@ -1587,6 +1588,8 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
default:
if (f.file->f_op->compat_ioctl) {
error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
+ if (!error)
+ evm_vfs_ioctl_post(f.file, cmd, arg);
if (error != -ENOIOCTLCMD)
goto out_fput;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8ac3fad..cd140b9 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -15,6 +15,7 @@
#include <linux/writeback.h>
#include <linux/buffer_head.h>
#include <linux/falloc.h>
+#include <linux/evm.h>
#include <asm/ioctls.h>
@@ -43,6 +44,8 @@ static long vfs_ioctl(struct file *filp, unsigned int cmd,
error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
if (error == -ENOIOCTLCMD)
error = -ENOTTY;
+ if (!error)
+ evm_vfs_ioctl_post(filp, cmd, arg);
out:
return error;
}
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 344c1c4..e68b0fa 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -31,6 +31,8 @@ extern void evm_inode_post_setxattr(struct dentry *dentry,
extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
+extern void evm_vfs_ioctl_post(struct file *filp, unsigned int cmd,
+ unsigned long arg);
extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);
@@ -96,6 +98,11 @@ static inline void evm_inode_post_removexattr(struct dentry *dentry,
return;
}
+static inline void evm_vfs_ioctl_post(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+}
+
static inline int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm)
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index 8bf72a8..9564ba4 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -25,6 +25,19 @@ config EVM_ATTR_FSUUID
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.
+config EVM_ATTR_IMMUTABLE
+ bool "IMMUTABLE"
+ default n
+ depends on EVM
+ help
+ Include file IMMUTABLE flag for HMAC calculation.
+
+ Default value is 'unselected'.
+
+ WARNING: changing the HMAC calculation method or adding
+ additional info to the calculation, requires existing EVM
+ labeled file systems to be relabeled.
+
config EVM_EXTRA_SMACK_XATTRS
bool "Additional SMACK xattrs"
depends on EVM && SECURITY_SMACK
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 348c3a9..42ea25a 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -29,6 +29,7 @@ extern char *evm_hmac;
extern char *evm_hash;
#define EVM_ATTR_FSUUID 0x0001
+#define EVM_ATTR_IMMUTABLE 0x0002
extern int evm_hmac_attrs;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index b4bf1a7..8ad33ea 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -131,6 +131,10 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
if (evm_hmac_attrs & EVM_ATTR_FSUUID)
crypto_shash_update(desc, inode->i_sb->s_uuid,
sizeof(inode->i_sb->s_uuid));
+ if (evm_hmac_attrs & EVM_ATTR_IMMUTABLE) {
+ __u8 immutable = !!IS_IMMUTABLE(inode);
+ crypto_shash_update(desc, &immutable, sizeof(immutable));
+ }
crypto_shash_final(desc, digest);
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 29e05d2..3309079 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -81,6 +81,9 @@ static void __init evm_init_config(void)
#ifdef CONFIG_EVM_ATTR_FSUUID
evm_hmac_attrs |= EVM_ATTR_FSUUID;
#endif
+#ifdef CONFIG_EVM_ATTR_IMMUTABLE
+ evm_hmac_attrs |= EVM_ATTR_IMMUTABLE;
+#endif
pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
}
@@ -441,6 +444,25 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
evm_update_evmxattr(dentry, NULL, NULL, 0);
}
+void evm_vfs_ioctl_post(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct inode *inode;
+
+ switch (cmd) {
+ case FS_IOC_SETFLAGS:
+ case FS_IOC32_SETFLAGS:
+ /* S_IMMUTABLE may be possibly changed - update HMAC */
+ inode = file_inode(filp);
+ mutex_lock(&inode->i_mutex);
+ evm_update_evmxattr(filp->f_dentry, NULL, NULL, 0);
+ mutex_unlock(&inode->i_mutex);
+ break;
+ default:
+ break;
+ }
+}
+
/*
* evm_inode_init_security - initializes security.evm
*/
--
1.9.1
|