Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 22:40:37 +0000 (15:40 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 22:40:37 +0000 (15:40 -0700)
Pull integrity updates from James Morris:
 "From Mimi:

   - add run time support for specifying additional security xattrs
     included in the security.evm HMAC/signature

   - some code clean up and bug fixes"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  EVM: unlock on error path in evm_read_xattrs()
  EVM: prevent array underflow in evm_write_xattrs()
  EVM: Fix null dereference on xattr when xattr fails to allocate
  EVM: fix memory leak of temporary buffer 'temp'
  IMA: use list_splice_tail_init_rcu() instead of its open coded variant
  ima: use match_string() helper
  ima: fix updating the ima_appraise flag
  ima: based on policy verify firmware signatures (pre-allocated buffer)
  ima: define a new policy condition based on the filesystem name
  EVM: Allow runtime modification of the set of verified xattrs
  EVM: turn evm_config_xattrnames into a list
  integrity: Add an integrity directory in securityfs
  ima: Remove unused variable ima_initialized
  ima: Unify logging
  ima: Reflect correct permissions for policy

16 files changed:
Documentation/ABI/testing/evm
Documentation/ABI/testing/ima_policy
include/uapi/linux/audit.h
security/integrity/evm/Kconfig
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/evm/evm_secfs.c
security/integrity/iint.c
security/integrity/ima/ima.h
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_kexec.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
security/integrity/integrity.h

index d12cb2eae9ee658e552c81c9009e2759a9142d58..201d10319fa18b588a42246814b13b67047a7dd3 100644 (file)
@@ -57,3 +57,16 @@ Description:
                dracut (via 97masterkey and 98integrity) and systemd (via
                core/ima-setup) have support for loading keys at boot
                time.
+
+What:          security/integrity/evm/evm_xattrs
+Date:          April 2018
+Contact:       Matthew Garrett <mjg59@google.com>
+Description:
+               Shows the set of extended attributes used to calculate or
+               validate the EVM signature, and allows additional attributes
+               to be added at runtime. Any signatures generated after
+               additional attributes are added (and on files posessing those
+               additional attributes) will only be valid if the same
+               additional attributes are configured on system boot. Writing
+               a single period (.) will lock the xattr list from any further
+               modification.
index b8465e00ba5fb7d06e434e9508302b71b1809f5b..74c6702de74e24369bc4d3e314d534898052ec2b 100644 (file)
@@ -21,7 +21,7 @@ Description:
                        audit | hash | dont_hash
                condition:= base | lsm  [option]
                        base:   [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
-                               [euid=] [fowner=]]
+                               [euid=] [fowner=] [fsname=]]
                        lsm:    [[subj_user=] [subj_role=] [subj_type=]
                                 [obj_user=] [obj_role=] [obj_type=]]
                        option: [[appraise_type=]] [permit_directio]
index 04f9bd249094efdec6e58940613dcdd726e53d25..c35aee9ad4a6f7f7ffc3819f5c69425f42353a7f 100644 (file)
 #define AUDIT_INTEGRITY_HASH       1803 /* Integrity HASH type */
 #define AUDIT_INTEGRITY_PCR        1804 /* PCR invalidation msgs */
 #define AUDIT_INTEGRITY_RULE       1805 /* policy rule */
+#define AUDIT_INTEGRITY_EVM_XATTR   1806 /* New EVM-covered xattr */
 
 #define AUDIT_KERNEL           2000    /* Asynchronous audit record. NOT A REQUEST. */
 
index e825e0ae78e72fdd548a0f10de2f865d84e41543..d593346d0bba48d22454b5ee4e8724204ce1c394 100644 (file)
@@ -42,6 +42,17 @@ config EVM_EXTRA_SMACK_XATTRS
          additional info to the calculation, requires existing EVM
          labeled file systems to be relabeled.
 
+config EVM_ADD_XATTRS
+       bool "Add additional EVM extended attributes at runtime"
+       depends on EVM
+       default n
+       help
+         Allow userland to provide additional xattrs for HMAC calculation.
+
+         When this option is enabled, root can add additional xattrs to the
+         list used by EVM by writing them into
+         /sys/kernel/security/integrity/evm/evm_xattrs.
+
 config EVM_LOAD_X509
        bool "Load an X509 certificate onto the '.evm' trusted keyring"
        depends on EVM && INTEGRITY_TRUSTED_KEYRING
index 45c4a89c02ffd17bd4a2f920e5c3f4e88c5c0e8f..1257c3c247236a2c5cee6efe9cd1a7d48852c112 100644 (file)
 #define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP_COMPLETE | \
                       EVM_ALLOW_METADATA_WRITES)
 
+struct xattr_list {
+       struct list_head list;
+       char *name;
+};
+
 extern int evm_initialized;
 
 #define EVM_ATTR_FSUUID                0x0001
@@ -40,7 +45,7 @@ extern struct crypto_shash *hmac_tfm;
 extern struct crypto_shash *hash_tfm;
 
 /* List of EVM protected security xattrs */
-extern char *evm_config_xattrnames[];
+extern struct list_head evm_config_xattrnames;
 
 int evm_init_key(void);
 int evm_update_evmxattr(struct dentry *dentry,
index facf9cdd577d963a9fa1ecb185652bd306951f3d..b605243108556d399f71cc9a248b12eea9db3d1e 100644 (file)
@@ -192,8 +192,8 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                                char type, char *digest)
 {
        struct inode *inode = d_backing_inode(dentry);
+       struct xattr_list *xattr;
        struct shash_desc *desc;
-       char **xattrname;
        size_t xattr_size = 0;
        char *xattr_value = NULL;
        int error;
@@ -209,14 +209,14 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                return PTR_ERR(desc);
 
        error = -ENODATA;
-       for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
+       list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
                bool is_ima = false;
 
-               if (strcmp(*xattrname, XATTR_NAME_IMA) == 0)
+               if (strcmp(xattr->name, XATTR_NAME_IMA) == 0)
                        is_ima = true;
 
                if ((req_xattr_name && req_xattr_value)
-                   && !strcmp(*xattrname, req_xattr_name)) {
+                   && !strcmp(xattr->name, req_xattr_name)) {
                        error = 0;
                        crypto_shash_update(desc, (const u8 *)req_xattr_value,
                                             req_xattr_value_len);
@@ -224,7 +224,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                                ima_present = true;
                        continue;
                }
-               size = vfs_getxattr_alloc(dentry, *xattrname,
+               size = vfs_getxattr_alloc(dentry, xattr->name,
                                          &xattr_value, xattr_size, GFP_NOFS);
                if (size == -ENOMEM) {
                        error = -ENOMEM;
index 9ea9c19a545c3abbe0dff5e1ea4e8d32f314d471..f9eff5041e4ca7b17d70e63319b4018939a78f78 100644 (file)
@@ -35,28 +35,29 @@ static const char * const integrity_status_msg[] = {
 };
 int evm_hmac_attrs;
 
-char *evm_config_xattrnames[] = {
+static struct xattr_list evm_config_default_xattrnames[] = {
 #ifdef CONFIG_SECURITY_SELINUX
-       XATTR_NAME_SELINUX,
+       {.name = XATTR_NAME_SELINUX},
 #endif
 #ifdef CONFIG_SECURITY_SMACK
-       XATTR_NAME_SMACK,
+       {.name = XATTR_NAME_SMACK},
 #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
-       XATTR_NAME_SMACKEXEC,
-       XATTR_NAME_SMACKTRANSMUTE,
-       XATTR_NAME_SMACKMMAP,
+       {.name = XATTR_NAME_SMACKEXEC},
+       {.name = XATTR_NAME_SMACKTRANSMUTE},
+       {.name = XATTR_NAME_SMACKMMAP},
 #endif
 #endif
 #ifdef CONFIG_SECURITY_APPARMOR
-       XATTR_NAME_APPARMOR,
+       {.name = XATTR_NAME_APPARMOR},
 #endif
 #ifdef CONFIG_IMA_APPRAISE
-       XATTR_NAME_IMA,
+       {.name = XATTR_NAME_IMA},
 #endif
-       XATTR_NAME_CAPS,
-       NULL
+       {.name = XATTR_NAME_CAPS},
 };
 
+LIST_HEAD(evm_config_xattrnames);
+
 static int evm_fixmode;
 static int __init evm_set_fixmode(char *str)
 {
@@ -68,6 +69,17 @@ __setup("evm=", evm_set_fixmode);
 
 static void __init evm_init_config(void)
 {
+       int i, xattrs;
+
+       xattrs = ARRAY_SIZE(evm_config_default_xattrnames);
+
+       pr_info("Initialising EVM extended attributes:\n");
+       for (i = 0; i < xattrs; i++) {
+               pr_info("%s\n", evm_config_default_xattrnames[i].name);
+               list_add_tail(&evm_config_default_xattrnames[i].list,
+                             &evm_config_xattrnames);
+       }
+
 #ifdef CONFIG_EVM_ATTR_FSUUID
        evm_hmac_attrs |= EVM_ATTR_FSUUID;
 #endif
@@ -82,15 +94,15 @@ static bool evm_key_loaded(void)
 static int evm_find_protected_xattrs(struct dentry *dentry)
 {
        struct inode *inode = d_backing_inode(dentry);
-       char **xattr;
+       struct xattr_list *xattr;
        int error;
        int count = 0;
 
        if (!(inode->i_opflags & IOP_XATTR))
                return -EOPNOTSUPP;
 
-       for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
-               error = __vfs_getxattr(dentry, inode, *xattr, NULL, 0);
+       list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
+               error = __vfs_getxattr(dentry, inode, xattr->name, NULL, 0);
                if (error < 0) {
                        if (error == -ENODATA)
                                continue;
@@ -211,24 +223,25 @@ out:
 
 static int evm_protected_xattr(const char *req_xattr_name)
 {
-       char **xattrname;
        int namelen;
        int found = 0;
+       struct xattr_list *xattr;
 
        namelen = strlen(req_xattr_name);
-       for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
-               if ((strlen(*xattrname) == namelen)
-                   && (strncmp(req_xattr_name, *xattrname, namelen) == 0)) {
+       list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
+               if ((strlen(xattr->name) == namelen)
+                   && (strncmp(req_xattr_name, xattr->name, namelen) == 0)) {
                        found = 1;
                        break;
                }
                if (strncmp(req_xattr_name,
-                           *xattrname + XATTR_SECURITY_PREFIX_LEN,
+                           xattr->name + XATTR_SECURITY_PREFIX_LEN,
                            strlen(req_xattr_name)) == 0) {
                        found = 1;
                        break;
                }
        }
+
        return found;
 }
 
@@ -544,35 +557,35 @@ void __init evm_load_x509(void)
 static int __init init_evm(void)
 {
        int error;
+       struct list_head *pos, *q;
+       struct xattr_list *xattr;
 
        evm_init_config();
 
        error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
        if (error)
-               return error;
+               goto error;
 
        error = evm_init_secfs();
        if (error < 0) {
                pr_info("Error registering secfs\n");
-               return error;
+               goto error;
        }
 
-       return 0;
-}
-
-/*
- * evm_display_config - list the EVM protected security extended attributes
- */
-static int __init evm_display_config(void)
-{
-       char **xattrname;
+error:
+       if (error != 0) {
+               if (!list_empty(&evm_config_xattrnames)) {
+                       list_for_each_safe(pos, q, &evm_config_xattrnames) {
+                               xattr = list_entry(pos, struct xattr_list,
+                                                  list);
+                               list_del(pos);
+                       }
+               }
+       }
 
-       for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++)
-               pr_info("%s\n", *xattrname);
-       return 0;
+       return error;
 }
 
-pure_initcall(evm_display_config);
 late_initcall(init_evm);
 
 MODULE_DESCRIPTION("Extended Verification Module");
index feba03bbedae25f4a4e6b89cfda2990451c41391..637eb999e3406df16d084f50e779ed73f34b2ca4 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/audit.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include "evm.h"
 
+static struct dentry *evm_dir;
 static struct dentry *evm_init_tpm;
+static struct dentry *evm_symlink;
+
+#ifdef CONFIG_EVM_ADD_XATTRS
+static struct dentry *evm_xattrs;
+static DEFINE_MUTEX(xattr_list_mutex);
+static int evm_xattrs_locked;
+#endif
 
 /**
  * evm_read_key - read() for <securityfs>/evm
@@ -107,13 +117,203 @@ static const struct file_operations evm_key_ops = {
        .write          = evm_write_key,
 };
 
+#ifdef CONFIG_EVM_ADD_XATTRS
+/**
+ * evm_read_xattrs - read() for <securityfs>/evm_xattrs
+ *
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       char *temp;
+       int offset = 0;
+       ssize_t rc, size = 0;
+       struct xattr_list *xattr;
+
+       if (*ppos != 0)
+               return 0;
+
+       rc = mutex_lock_interruptible(&xattr_list_mutex);
+       if (rc)
+               return -ERESTARTSYS;
+
+       list_for_each_entry(xattr, &evm_config_xattrnames, list)
+               size += strlen(xattr->name) + 1;
+
+       temp = kmalloc(size + 1, GFP_KERNEL);
+       if (!temp) {
+               mutex_unlock(&xattr_list_mutex);
+               return -ENOMEM;
+       }
+
+       list_for_each_entry(xattr, &evm_config_xattrnames, list) {
+               sprintf(temp + offset, "%s\n", xattr->name);
+               offset += strlen(xattr->name) + 1;
+       }
+
+       mutex_unlock(&xattr_list_mutex);
+       rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+       kfree(temp);
+
+       return rc;
+}
+
+/**
+ * evm_write_xattrs - write() for <securityfs>/evm_xattrs
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       int len, err;
+       struct xattr_list *xattr, *tmp;
+       struct audit_buffer *ab;
+       struct iattr newattrs;
+       struct inode *inode;
+
+       if (!capable(CAP_SYS_ADMIN) || evm_xattrs_locked)
+               return -EPERM;
+
+       if (*ppos != 0)
+               return -EINVAL;
+
+       if (count > XATTR_NAME_MAX)
+               return -E2BIG;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_EVM_XATTR);
+       if (IS_ERR(ab))
+               return PTR_ERR(ab);
+
+       xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
+       if (!xattr) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       xattr->name = memdup_user_nul(buf, count);
+       if (IS_ERR(xattr->name)) {
+               err = PTR_ERR(xattr->name);
+               xattr->name = NULL;
+               goto out;
+       }
+
+       /* Remove any trailing newline */
+       len = strlen(xattr->name);
+       if (len && xattr->name[len-1] == '\n')
+               xattr->name[len-1] = '\0';
+
+       if (strcmp(xattr->name, ".") == 0) {
+               evm_xattrs_locked = 1;
+               newattrs.ia_mode = S_IFREG | 0440;
+               newattrs.ia_valid = ATTR_MODE;
+               inode = evm_xattrs->d_inode;
+               inode_lock(inode);
+               err = simple_setattr(evm_xattrs, &newattrs);
+               inode_unlock(inode);
+               audit_log_format(ab, "locked");
+               if (!err)
+                       err = count;
+               goto out;
+       }
+
+       audit_log_format(ab, "xattr=");
+       audit_log_untrustedstring(ab, xattr->name);
+
+       if (strncmp(xattr->name, XATTR_SECURITY_PREFIX,
+                   XATTR_SECURITY_PREFIX_LEN) != 0) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Guard against races in evm_read_xattrs */
+       mutex_lock(&xattr_list_mutex);
+       list_for_each_entry(tmp, &evm_config_xattrnames, list) {
+               if (strcmp(xattr->name, tmp->name) == 0) {
+                       err = -EEXIST;
+                       mutex_unlock(&xattr_list_mutex);
+                       goto out;
+               }
+       }
+       list_add_tail_rcu(&xattr->list, &evm_config_xattrnames);
+       mutex_unlock(&xattr_list_mutex);
+
+       audit_log_format(ab, " res=0");
+       audit_log_end(ab);
+       return count;
+out:
+       audit_log_format(ab, " res=%d", err);
+       audit_log_end(ab);
+       if (xattr) {
+               kfree(xattr->name);
+               kfree(xattr);
+       }
+       return err;
+}
+
+static const struct file_operations evm_xattr_ops = {
+       .read           = evm_read_xattrs,
+       .write          = evm_write_xattrs,
+};
+
+static int evm_init_xattrs(void)
+{
+       evm_xattrs = securityfs_create_file("evm_xattrs", 0660, evm_dir, NULL,
+                                           &evm_xattr_ops);
+       if (!evm_xattrs || IS_ERR(evm_xattrs))
+               return -EFAULT;
+
+       return 0;
+}
+#else
+static int evm_init_xattrs(void)
+{
+       return 0;
+}
+#endif
+
 int __init evm_init_secfs(void)
 {
        int error = 0;
 
-       evm_init_tpm = securityfs_create_file("evm", S_IRUSR | S_IRGRP,
-                                             NULL, NULL, &evm_key_ops);
-       if (!evm_init_tpm || IS_ERR(evm_init_tpm))
+       evm_dir = securityfs_create_dir("evm", integrity_dir);
+       if (!evm_dir || IS_ERR(evm_dir))
+               return -EFAULT;
+
+       evm_init_tpm = securityfs_create_file("evm", 0660,
+                                             evm_dir, NULL, &evm_key_ops);
+       if (!evm_init_tpm || IS_ERR(evm_init_tpm)) {
                error = -EFAULT;
+               goto out;
+       }
+
+       evm_symlink = securityfs_create_symlink("evm", NULL,
+                                               "integrity/evm/evm", NULL);
+       if (!evm_symlink || IS_ERR(evm_symlink)) {
+               error = -EFAULT;
+               goto out;
+       }
+
+       if (evm_init_xattrs() != 0) {
+               error = -EFAULT;
+               goto out;
+       }
+
+       return 0;
+out:
+       securityfs_remove(evm_symlink);
+       securityfs_remove(evm_init_tpm);
+       securityfs_remove(evm_dir);
        return error;
 }
index f266e4b3b7d4614345b8aa6f24806b2f3476b9db..149faa81f6f05aa2e2723f97c35aa6c85c56eb0e 100644 (file)
 #include <linux/rbtree.h>
 #include <linux/file.h>
 #include <linux/uaccess.h>
+#include <linux/security.h>
 #include "integrity.h"
 
 static struct rb_root integrity_iint_tree = RB_ROOT;
 static DEFINE_RWLOCK(integrity_iint_lock);
 static struct kmem_cache *iint_cache __read_mostly;
 
+struct dentry *integrity_dir;
+
 /*
  * __integrity_iint_find - return the iint associated with an inode
  */
@@ -211,3 +214,18 @@ void __init integrity_load_keys(void)
        ima_load_x509();
        evm_load_x509();
 }
+
+static int __init integrity_fs_init(void)
+{
+       integrity_dir = securityfs_create_dir("integrity", NULL);
+       if (IS_ERR(integrity_dir)) {
+               pr_err("Unable to create integrity sysfs dir: %ld\n",
+                      PTR_ERR(integrity_dir));
+               integrity_dir = NULL;
+               return PTR_ERR(integrity_dir);
+       }
+
+       return 0;
+}
+
+late_initcall(integrity_fs_init)
index 35fe91aa1fc95ad6001adccbd85fa3856918879f..354bb5716ce329a39e43413a9ed373008c901b1e 100644 (file)
@@ -53,7 +53,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 extern int ima_policy_flag;
 
 /* set during initialization */
-extern int ima_initialized;
 extern int ima_used_chip;
 extern int ima_hash_algo;
 extern int ima_appraise;
index fa540c0469dac649ca7583834caacf7cc955b594..ae9d5c766a3ce9313110fb663178d0840d4eabcd 100644 (file)
@@ -15,6 +15,9 @@
  *     implemenents security file system for reporting
  *     current measurement list and IMA statistics
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fcntl.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -336,7 +339,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
        if (data[0] == '/') {
                result = ima_read_policy(data);
        } else if (ima_appraise & IMA_APPRAISE_POLICY) {
-               pr_err("IMA: signed policy file (specified as an absolute pathname) required\n");
+               pr_err("signed policy file (specified as an absolute pathname) required\n");
                integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
                                    "policy_update", "signed policy required",
                                    1, 0);
@@ -356,6 +359,7 @@ out:
 }
 
 static struct dentry *ima_dir;
+static struct dentry *ima_symlink;
 static struct dentry *binary_runtime_measurements;
 static struct dentry *ascii_runtime_measurements;
 static struct dentry *runtime_measurements_count;
@@ -417,7 +421,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
                valid_policy = 0;
        }
 
-       pr_info("IMA: policy update %s\n", cause);
+       pr_info("policy update %s\n", cause);
        integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
                            "policy_update", cause, !valid_policy, 0);
 
@@ -434,6 +438,8 @@ static int ima_release_policy(struct inode *inode, struct file *file)
        ima_policy = NULL;
 #elif defined(CONFIG_IMA_WRITE_POLICY)
        clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#elif defined(CONFIG_IMA_READ_POLICY)
+       inode->i_mode &= ~S_IWUSR;
 #endif
        return 0;
 }
@@ -448,10 +454,15 @@ static const struct file_operations ima_measure_policy_ops = {
 
 int __init ima_fs_init(void)
 {
-       ima_dir = securityfs_create_dir("ima", NULL);
+       ima_dir = securityfs_create_dir("ima", integrity_dir);
        if (IS_ERR(ima_dir))
                return -1;
 
+       ima_symlink = securityfs_create_symlink("ima", NULL, "integrity/ima",
+                                               NULL);
+       if (IS_ERR(ima_symlink))
+               goto out;
+
        binary_runtime_measurements =
            securityfs_create_file("binary_runtime_measurements",
                                   S_IRUSR | S_IRGRP, ima_dir, NULL,
@@ -491,6 +502,7 @@ out:
        securityfs_remove(runtime_measurements_count);
        securityfs_remove(ascii_runtime_measurements);
        securityfs_remove(binary_runtime_measurements);
+       securityfs_remove(ima_symlink);
        securityfs_remove(ima_dir);
        securityfs_remove(ima_policy);
        return -1;
index e473eee913cba9414b76ce882611bb6d7bb5a482..16bd18747cfa0280c400f647854e6cbbe09e6d1d 100644 (file)
@@ -10,6 +10,8 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/seq_file.h>
 #include <linux/vmalloc.h>
 #include <linux/kexec.h>
index 74d0bd7e76d7159234c036df6c053532f58ab4a4..dca44cf7838eaddf882212faedc9759a391f7723 100644 (file)
@@ -32,8 +32,6 @@
 
 #include "ima.h"
 
-int ima_initialized;
-
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise = IMA_APPRAISE_ENFORCE;
 #else
@@ -61,14 +59,11 @@ static int __init hash_setup(char *str)
                goto out;
        }
 
-       for (i = 0; i < HASH_ALGO__LAST; i++) {
-               if (strcmp(str, hash_algo_name[i]) == 0) {
-                       ima_hash_algo = i;
-                       break;
-               }
-       }
-       if (i == HASH_ALGO__LAST)
+       i = match_string(hash_algo_name, HASH_ALGO__LAST, str);
+       if (i < 0)
                return 1;
+
+       ima_hash_algo = i;
 out:
        hash_setup_done = 1;
        return 1;
@@ -449,6 +444,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
 
 static int read_idmap[READING_MAX_ID] = {
        [READING_FIRMWARE] = FIRMWARE_CHECK,
+       [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK,
        [READING_MODULE] = MODULE_CHECK,
        [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
        [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
@@ -517,10 +513,9 @@ static int __init init_ima(void)
                error = ima_init();
        }
 
-       if (!error) {
-               ima_initialized = 1;
+       if (!error)
                ima_update_policy_flag();
-       }
+
        return error;
 }
 
index d89bebf85421e7134aff233a52545218efabf512..cdcc9a7b4e24825bcc9c41d0e81c14b03993acb0 100644 (file)
@@ -33,6 +33,7 @@
 #define IMA_INMASK     0x0040
 #define IMA_EUID       0x0080
 #define IMA_PCR                0x0100
+#define IMA_FSNAME     0x0200
 
 #define UNKNOWN                0
 #define MEASURE                0x0001  /* same as IMA_MEASURE */
@@ -74,6 +75,7 @@ struct ima_rule_entry {
                void *args_p;   /* audit value */
                int type;       /* audit type */
        } lsm[MAX_LSM_RULES];
+       char *fsname;
 };
 
 /*
@@ -273,6 +275,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
        if ((rule->flags & IMA_FSMAGIC)
            && rule->fsmagic != inode->i_sb->s_magic)
                return false;
+       if ((rule->flags & IMA_FSNAME)
+           && strcmp(rule->fsname, inode->i_sb->s_type->name))
+               return false;
        if ((rule->flags & IMA_FSUUID) &&
            !uuid_equal(&rule->fsuuid, &inode->i_sb->s_uuid))
                return false;
@@ -435,6 +440,17 @@ void ima_update_policy_flag(void)
                ima_policy_flag &= ~IMA_APPRAISE;
 }
 
+static int ima_appraise_flag(enum ima_hooks func)
+{
+       if (func == MODULE_CHECK)
+               return IMA_APPRAISE_MODULES;
+       else if (func == FIRMWARE_CHECK)
+               return IMA_APPRAISE_FIRMWARE;
+       else if (func == POLICY_CHECK)
+               return IMA_APPRAISE_POLICY;
+       return 0;
+}
+
 /**
  * ima_init_policy - initialize the default measure rules.
  *
@@ -473,9 +489,11 @@ void __init ima_init_policy(void)
         * Insert the appraise rules requiring file signatures, prior to
         * any other appraise rules.
         */
-       for (i = 0; i < secure_boot_entries; i++)
-               list_add_tail(&secure_boot_rules[i].list,
-                             &ima_default_rules);
+       for (i = 0; i < secure_boot_entries; i++) {
+               list_add_tail(&secure_boot_rules[i].list, &ima_default_rules);
+               temp_ima_appraise |=
+                   ima_appraise_flag(secure_boot_rules[i].func);
+       }
 
        for (i = 0; i < appraise_entries; i++) {
                list_add_tail(&default_appraise_rules[i].list,
@@ -509,22 +527,9 @@ int ima_check_policy(void)
  */
 void ima_update_policy(void)
 {
-       struct list_head *first, *last, *policy;
-
-       /* append current policy with the new rules */
-       first = (&ima_temp_rules)->next;
-       last = (&ima_temp_rules)->prev;
-       policy = &ima_policy_rules;
-
-       synchronize_rcu();
+       struct list_head *policy = &ima_policy_rules;
 
-       last->next = policy;
-       rcu_assign_pointer(list_next_rcu(policy->prev), first);
-       first->prev = policy->prev;
-       policy->prev = last;
-
-       /* prepare for the next policy rules addition */
-       INIT_LIST_HEAD(&ima_temp_rules);
+       list_splice_tail_init_rcu(&ima_temp_rules, policy, synchronize_rcu);
 
        if (ima_rules != policy) {
                ima_policy_flag = 0;
@@ -540,7 +545,7 @@ enum {
        Opt_audit, Opt_hash, Opt_dont_hash,
        Opt_obj_user, Opt_obj_role, Opt_obj_type,
        Opt_subj_user, Opt_subj_role, Opt_subj_type,
-       Opt_func, Opt_mask, Opt_fsmagic,
+       Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname,
        Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
        Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
        Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
@@ -565,6 +570,7 @@ static match_table_t policy_tokens = {
        {Opt_func, "func=%s"},
        {Opt_mask, "mask=%s"},
        {Opt_fsmagic, "fsmagic=%s"},
+       {Opt_fsname, "fsname=%s"},
        {Opt_fsuuid, "fsuuid=%s"},
        {Opt_uid_eq, "uid=%s"},
        {Opt_euid_eq, "euid=%s"},
@@ -776,6 +782,17 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        if (!result)
                                entry->flags |= IMA_FSMAGIC;
                        break;
+               case Opt_fsname:
+                       ima_log_string(ab, "fsname", args[0].from);
+
+                       entry->fsname = kstrdup(args[0].from, GFP_KERNEL);
+                       if (!entry->fsname) {
+                               result = -ENOMEM;
+                               break;
+                       }
+                       result = 0;
+                       entry->flags |= IMA_FSNAME;
+                       break;
                case Opt_fsuuid:
                        ima_log_string(ab, "fsuuid", args[0].from);
 
@@ -917,12 +934,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
        }
        if (!result && (entry->action == UNKNOWN))
                result = -EINVAL;
-       else if (entry->func == MODULE_CHECK)
-               temp_ima_appraise |= IMA_APPRAISE_MODULES;
-       else if (entry->func == FIRMWARE_CHECK)
-               temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
-       else if (entry->func == POLICY_CHECK)
-               temp_ima_appraise |= IMA_APPRAISE_POLICY;
+       else if (entry->action == APPRAISE)
+               temp_ima_appraise |= ima_appraise_flag(entry->func);
+
        audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
        return result;
@@ -1104,6 +1118,12 @@ int ima_policy_show(struct seq_file *m, void *v)
                seq_puts(m, " ");
        }
 
+       if (entry->flags & IMA_FSNAME) {
+               snprintf(tbuf, sizeof(tbuf), "%s", entry->fsname);
+               seq_printf(m, pt(Opt_fsname), tbuf);
+               seq_puts(m, " ");
+       }
+
        if (entry->flags & IMA_PCR) {
                snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr);
                seq_printf(m, pt(Opt_pcr), tbuf);
index 5afaa53decc50416ad5963a82ddecb47f4c2f9c5..43752002c2223ca0315237b3dc2bf5df9ac5c4c0 100644 (file)
@@ -13,6 +13,8 @@
  *      Library of supported template fields.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "ima_template_lib.h"
 
 static bool ima_template_hash_algo_allowed(u8 algo)
index 5e58e02ba8dc97ff1c4a88f5722109f4783d3f62..0bb372eed62aea4fb92795255f38a0fab3a61528 100644 (file)
@@ -143,6 +143,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
 #define INTEGRITY_KEYRING_MODULE       2
 #define INTEGRITY_KEYRING_MAX          3
 
+extern struct dentry *integrity_dir;
+
 #ifdef CONFIG_INTEGRITY_SIGNATURE
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,