]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Jun 2014 14:39:39 +0000 (07:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Jun 2014 14:39:39 +0000 (07:39 -0700)
Pull more security layer updates from Serge Hallyn:
 "A few more commits had previously failed to make it through
  security-next into linux-next but this week made it into linux-next.
  At least commit "ima: introduce ima_kernel_read()" was deemed critical
  by Mimi to make this merge window.

  This is a temporary tree just for this request.  Mimi has pointed me
  to some previous threads about keeping maintainer trees at the
  previous release, which I'll certainly do for anything long-term,
  after talking with James"

* 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security:
  ima: introduce ima_kernel_read()
  evm: prohibit userspace writing 'security.evm' HMAC value
  ima: check inode integrity cache in violation check
  ima: prevent unnecessary policy checking
  evm: provide option to protect additional SMACK xattrs
  evm: replace HMAC version with attribute mask
  ima: prevent new digsig xattr from being replaced

security/integrity/evm/Kconfig
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_main.c

index d35b4915b00d4722e76464baba6b272ce86332f0..d606f3d12d6bfb8f27d849a3b4fa9fc9ee411875 100644 (file)
@@ -12,15 +12,41 @@ config EVM
 
          If you are unsure how to answer this question, answer N.
 
-config EVM_HMAC_VERSION
-       int "EVM HMAC version"
+if EVM
+
+menu "EVM options"
+
+config EVM_ATTR_FSUUID
+       bool "FSUUID (version 2)"
+       default y
        depends on EVM
-       default 2
        help
-         This options adds EVM HMAC version support.
-         1 - original version
-         2 - add per filesystem unique identifier (UUID) (default)
+         Include filesystem UUID for HMAC calculation.
+
+         Default value is 'selected', which is former version 2.
+         if 'not selected', it is former version 1
 
-         WARNING: changing the HMAC calculation method or adding 
+         WARNING: changing the HMAC calculation method or adding
          additional info to the calculation, requires existing EVM
-         labeled file systems to be relabeled.  
+         labeled file systems to be relabeled.
+
+config EVM_EXTRA_SMACK_XATTRS
+       bool "Additional SMACK xattrs"
+       depends on EVM && SECURITY_SMACK
+       default n
+       help
+         Include additional SMACK xattrs for HMAC calculation.
+
+         In addition to the original security xattrs (eg. security.selinux,
+         security.SMACK64, security.capability, and security.ima) included
+         in the HMAC calculation, enabling this option includes newly defined
+         Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and
+         security.SMACK64MMAP.
+
+         WARNING: changing the HMAC calculation method or adding
+         additional info to the calculation, requires existing EVM
+         labeled file systems to be relabeled.
+
+endmenu
+
+endif
index 37c88ddb3cfe459e88822742e3cd25b15fb6f992..88bfe77efa1cf10ccdcb5bb50e6e949f05f017bf 100644 (file)
 extern int evm_initialized;
 extern char *evm_hmac;
 extern char *evm_hash;
-extern int evm_hmac_version;
+
+#define EVM_ATTR_FSUUID                0x0001
+
+extern int evm_hmac_attrs;
 
 extern struct crypto_shash *hmac_tfm;
 extern struct crypto_shash *hash_tfm;
index 6b540f1822e0b43c175466615ff78db50b0df0f5..5e9687f02e1b14e56e56d3a303afbef23ea79dca 100644 (file)
@@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
        hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
        hmac_misc.mode = inode->i_mode;
        crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
-       if (evm_hmac_version > 1)
+       if (evm_hmac_attrs & EVM_ATTR_FSUUID)
                crypto_shash_update(desc, inode->i_sb->s_uuid,
                                    sizeof(inode->i_sb->s_uuid));
        crypto_shash_final(desc, digest);
index 6e0bd933b6a9a8a815f5d57c147f1d18dfbfec36..3bcb80df4d01f1ca30927c7e61c6b2b19b5ca15f 100644 (file)
@@ -32,7 +32,7 @@ static char *integrity_status_msg[] = {
 };
 char *evm_hmac = "hmac(sha1)";
 char *evm_hash = "sha1";
-int evm_hmac_version = CONFIG_EVM_HMAC_VERSION;
+int evm_hmac_attrs;
 
 char *evm_config_xattrnames[] = {
 #ifdef CONFIG_SECURITY_SELINUX
@@ -40,6 +40,11 @@ char *evm_config_xattrnames[] = {
 #endif
 #ifdef CONFIG_SECURITY_SMACK
        XATTR_NAME_SMACK,
+#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
+       XATTR_NAME_SMACKEXEC,
+       XATTR_NAME_SMACKTRANSMUTE,
+       XATTR_NAME_SMACKMMAP,
+#endif
 #endif
 #ifdef CONFIG_IMA_APPRAISE
        XATTR_NAME_IMA,
@@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str)
 }
 __setup("evm=", evm_set_fixmode);
 
+static void __init evm_init_config(void)
+{
+#ifdef CONFIG_EVM_ATTR_FSUUID
+       evm_hmac_attrs |= EVM_ATTR_FSUUID;
+#endif
+       pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
+}
+
 static int evm_find_protected_xattrs(struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
@@ -287,12 +300,20 @@ out:
  * @xattr_value: pointer to the new extended attribute value
  * @xattr_value_len: pointer to the new extended attribute value length
  *
- * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
- * the current value is valid.
+ * Before allowing the 'security.evm' protected xattr to be updated,
+ * verify the existing value is valid.  As only the kernel should have
+ * access to the EVM encrypted key needed to calculate the HMAC, prevent
+ * userspace from writing HMAC value.  Writing 'security.evm' requires
+ * requires CAP_SYS_ADMIN privileges.
  */
 int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
                       const void *xattr_value, size_t xattr_value_len)
 {
+       const struct evm_ima_xattr_data *xattr_data = xattr_value;
+
+       if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
+           && (xattr_data->type == EVM_XATTR_HMAC))
+               return -EPERM;
        return evm_protect_xattr(dentry, xattr_name, xattr_value,
                                 xattr_value_len);
 }
@@ -432,6 +453,8 @@ static int __init init_evm(void)
 {
        int error;
 
+       evm_init_config();
+
        error = evm_init_secfs();
        if (error < 0) {
                pr_info("Error registering secfs\n");
index 291bf0f3a46d7989c1d4cf77fdba0237a6d0fb1f..d3113d4aaa3c3f41d0395f4b0862f37389b8997f 100644 (file)
@@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
        return 0;
 }
 
-static void ima_reset_appraise_flags(struct inode *inode)
+static void ima_reset_appraise_flags(struct inode *inode, int digsig)
 {
        struct integrity_iint_cache *iint;
 
@@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode)
                return;
 
        iint->flags &= ~IMA_DONE_MASK;
+       if (digsig)
+               iint->flags |= IMA_DIGSIG;
        return;
 }
 
 int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
                       const void *xattr_value, size_t xattr_value_len)
 {
+       const struct evm_ima_xattr_data *xvalue = xattr_value;
        int result;
 
        result = ima_protect_xattr(dentry, xattr_name, xattr_value,
                                   xattr_value_len);
        if (result == 1) {
-               ima_reset_appraise_flags(dentry->d_inode);
+               ima_reset_appraise_flags(dentry->d_inode,
+                        (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
                result = 0;
        }
        return result;
@@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
 
        result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
        if (result == 1) {
-               ima_reset_appraise_flags(dentry->d_inode);
+               ima_reset_appraise_flags(dentry->d_inode, 0);
                result = 0;
        }
        return result;
index 1bde8e62776620e6e5ed2cb2900d39c91df992f8..ccd0ac8fa9a0b5db445b901fb2c643ba8801edf2 100644 (file)
 
 static struct crypto_shash *ima_shash_tfm;
 
+/**
+ * ima_kernel_read - read file content
+ *
+ * This is a function for reading file content instead of kernel_read().
+ * It does not perform locking checks to ensure it cannot be blocked.
+ * It does not perform security checks because it is irrelevant for IMA.
+ *
+ */
+static int ima_kernel_read(struct file *file, loff_t offset,
+                          char *addr, unsigned long count)
+{
+       mm_segment_t old_fs;
+       char __user *buf = addr;
+       ssize_t ret;
+
+       if (!(file->f_mode & FMODE_READ))
+               return -EBADF;
+       if (!file->f_op->read && !file->f_op->aio_read)
+               return -EINVAL;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       if (file->f_op->read)
+               ret = file->f_op->read(file, buf, count, &offset);
+       else
+               ret = do_sync_read(file, buf, count, &offset);
+       set_fs(old_fs);
+       return ret;
+}
+
 int ima_init_crypto(void)
 {
        long rc;
@@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
        while (offset < i_size) {
                int rbuf_len;
 
-               rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
+               rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
                if (rbuf_len < 0) {
                        rc = rbuf_len;
                        break;
index dcc98cf542d83fb4768ff3bd2ec113c204c7ecb6..09baa335ebc79ed9c7054272dc38534e02c85175 100644 (file)
@@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file)
 {
        struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
-       int must_measure;
        bool send_tomtou = false, send_writers = false;
        char *pathbuf = NULL;
        const char *pathname;
@@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file)
        mutex_lock(&inode->i_mutex);    /* file metadata: permissions, xattr */
 
        if (mode & FMODE_WRITE) {
-               if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
-                       send_tomtou = true;
-               goto out;
+               if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
+                       struct integrity_iint_cache *iint;
+                       iint = integrity_iint_find(inode);
+                       /* IMA_MEASURE is set from reader side */
+                       if (iint && (iint->flags & IMA_MEASURE))
+                               send_tomtou = true;
+               }
+       } else {
+               if ((atomic_read(&inode->i_writecount) > 0) &&
+                   ima_must_measure(inode, MAY_READ, FILE_CHECK))
+                       send_writers = true;
        }
 
-       must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK);
-       if (!must_measure)
-               goto out;
-
-       if (atomic_read(&inode->i_writecount) > 0)
-               send_writers = true;
-out:
        mutex_unlock(&inode->i_mutex);
 
        if (!send_tomtou && !send_writers)