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 |