Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux...
authorJames Morris <james.l.morris@oracle.com>
Wed, 19 Nov 2014 10:36:07 +0000 (21:36 +1100)
committerJames Morris <james.l.morris@oracle.com>
Wed, 19 Nov 2014 10:36:07 +0000 (21:36 +1100)
18 files changed:
Documentation/kernel-parameters.txt
Documentation/security/IMA-templates.txt
fs/read_write.c
include/linux/fs.h
include/linux/integrity.h
init/main.c
security/integrity/digsig.c
security/integrity/evm/evm_main.c
security/integrity/iint.c
security/integrity/ima/Kconfig
security/integrity/ima/ima_api.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity.h

index 4fb49e0..c73d271 100644 (file)
@@ -1330,6 +1330,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Formats: { "ima" | "ima-ng" }
                        Default: "ima-ng"
 
+       ima_template_fmt=
+                       [IMA] Define a custom template format.
+                       Format: { "field1|...|fieldN" }
+
        ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
                        Format: <min_file_size>
                        Set the minimal file size for using asynchronous hash.
index a4e102d..839b5da 100644 (file)
@@ -27,25 +27,22 @@ Managing templates with these structures is very simple. To support
 a new data type, developers define the field identifier and implement
 two functions, init() and show(), respectively to generate and display
 measurement entries. Defining a new template descriptor requires
-specifying the template format, a string of field identifiers separated
-by the '|' character. While in the current implementation it is possible
-to define new template descriptors only by adding their definition in the
-template specific code (ima_template.c), in a future version it will be
-possible to register a new template on a running kernel by supplying to IMA
-the desired format string. In this version, IMA initializes at boot time
-all defined template descriptors by translating the format into an array
-of template fields structures taken from the set of the supported ones.
+specifying the template format (a string of field identifiers separated
+by the '|' character) through the 'ima_template_fmt' kernel command line
+parameter. At boot time, IMA initializes the chosen template descriptor
+by translating the format into an array of template fields structures taken
+from the set of the supported ones.
 
 After the initialization step, IMA will call ima_alloc_init_template()
 (new function defined within the patches for the new template management
 mechanism) to generate a new measurement entry by using the template
 descriptor chosen through the kernel configuration or through the newly
-introduced 'ima_template=' kernel command line parameter. It is during this
-phase that the advantages of the new architecture are clearly shown:
-the latter function will not contain specific code to handle a given template
-but, instead, it simply calls the init() method of the template fields
-associated to the chosen template descriptor and store the result (pointer
-to allocated data and data length) in the measurement entry structure.
+introduced 'ima_template' and 'ima_template_fmt' kernel command line parameters.
+It is during this phase that the advantages of the new architecture are
+clearly shown: the latter function will not contain specific code to handle
+a given template but, instead, it simply calls the init() method of the template
+fields associated to the chosen template descriptor and store the result
+(pointer to allocated data and data length) in the measurement entry structure.
 
 The same mechanism is employed to display measurements entries.
 The functions ima[_ascii]_measurements_show() retrieve, for each entry,
@@ -86,4 +83,6 @@ currently the following methods are supported:
  - select a template descriptor among those supported in the kernel
    configuration ('ima-ng' is the default choice);
  - specify a template descriptor name from the kernel command line through
-   the 'ima_template=' parameter.
+   the 'ima_template=' parameter;
+ - register a new template descriptor with custom format through the kernel
+   command line parameter 'ima_template_fmt='.
index 009d854..f45b2ae 100644 (file)
@@ -412,6 +412,23 @@ ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *p
 
 EXPORT_SYMBOL(new_sync_read);
 
+ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
+                  loff_t *pos)
+{
+       ssize_t ret;
+
+       if (file->f_op->read)
+               ret = file->f_op->read(file, buf, count, pos);
+       else if (file->f_op->aio_read)
+               ret = do_sync_read(file, buf, count, pos);
+       else if (file->f_op->read_iter)
+               ret = new_sync_read(file, buf, count, pos);
+       else
+               ret = -EINVAL;
+
+       return ret;
+}
+
 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 {
        ssize_t ret;
@@ -426,12 +443,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
        ret = rw_verify_area(READ, file, pos, count);
        if (ret >= 0) {
                count = ret;
-               if (file->f_op->read)
-                       ret = file->f_op->read(file, buf, count, pos);
-               else if (file->f_op->aio_read)
-                       ret = do_sync_read(file, buf, count, pos);
-               else
-                       ret = new_sync_read(file, buf, count, pos);
+               ret = __vfs_read(file, buf, count, pos);
                if (ret > 0) {
                        fsnotify_access(file);
                        add_rchar(current, ret);
index 9418772..c213b48 100644 (file)
@@ -1553,6 +1553,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
                              struct iovec *fast_pointer,
                              struct iovec **ret_pointer);
 
+extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
 extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
 extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
 extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
index 83222ce..c2d6082 100644 (file)
@@ -24,6 +24,7 @@ enum integrity_status {
 #ifdef CONFIG_INTEGRITY
 extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
 extern void integrity_inode_free(struct inode *inode);
+extern void __init integrity_load_keys(void);
 
 #else
 static inline struct integrity_iint_cache *
@@ -36,5 +37,10 @@ static inline void integrity_inode_free(struct inode *inode)
 {
        return;
 }
+
+static inline void integrity_load_keys(void)
+{
+}
 #endif /* CONFIG_INTEGRITY */
+
 #endif /* _LINUX_INTEGRITY_H */
index bb1aed9..9fc795f 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/context_tracking.h>
 #include <linux/random.h>
 #include <linux/list.h>
+#include <linux/integrity.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -1027,8 +1028,11 @@ static noinline void __init kernel_init_freeable(void)
         * Ok, we have completed the initial bootup, and
         * we're essentially up and running. Get rid of the
         * initmem segments and start the user-mode stuff..
+        *
+        * rootfs is available now, try loading the public keys
+        * and default modules
         */
 
-       /* rootfs is available now, try loading default modules */
+       integrity_load_keys();
        load_default_modules();
 }
index 8d4fbff..5e3bd72 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/rbtree.h>
+#include <linux/slab.h>
 #include <linux/cred.h>
 #include <linux/key-type.h>
 #include <linux/digsig.h>
@@ -63,7 +63,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
        return -EOPNOTSUPP;
 }
 
-int integrity_init_keyring(const unsigned int id)
+int __init integrity_init_keyring(const unsigned int id)
 {
        const struct cred *cred = current_cred();
        int err = 0;
@@ -84,3 +84,37 @@ int integrity_init_keyring(const unsigned int id)
        }
        return err;
 }
+
+int __init integrity_load_x509(const unsigned int id, char *path)
+{
+       key_ref_t key;
+       char *data;
+       int rc;
+
+       if (!keyring[id])
+               return -EINVAL;
+
+       rc = integrity_read_file(path, &data);
+       if (rc < 0)
+               return rc;
+
+       key = key_create_or_update(make_key_ref(keyring[id], 1),
+                                  "asymmetric",
+                                  NULL,
+                                  data,
+                                  rc,
+                                  ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                                   KEY_USR_VIEW | KEY_USR_READ),
+                                  KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
+       if (IS_ERR(key)) {
+               rc = PTR_ERR(key);
+               pr_err("Problem loading X.509 certificate (%d): %s\n",
+                      rc, path);
+       } else {
+               pr_notice("Loaded X.509 cert '%s': %s\n",
+                         key_ref_to_ptr(key)->description, path);
+               key_ref_put(key);
+       }
+       kfree(data);
+       return 0;
+}
index 9685af3..b392fe6 100644 (file)
@@ -162,9 +162,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                                        (const char *)xattr_data, xattr_len,
                                        calc.digest, sizeof(calc.digest));
                if (!rc) {
-                       /* we probably want to replace rsa with hmac here */
-                       evm_update_evmxattr(dentry, xattr_name, xattr_value,
-                                  xattr_value_len);
+                       /* Replace RSA with HMAC if not mounted readonly and
+                        * not immutable
+                        */
+                       if (!IS_RDONLY(dentry->d_inode) &&
+                           !IS_IMMUTABLE(dentry->d_inode))
+                               evm_update_evmxattr(dentry, xattr_name,
+                                                   xattr_value,
+                                                   xattr_value_len);
                }
                break;
        default:
index a521edf..dbb6d14 100644 (file)
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/rbtree.h>
+#include <linux/file.h>
+#include <linux/uaccess.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;
 
-int iint_initialized;
-
 /*
  * __integrity_iint_find - return the iint associated with an inode
  */
@@ -166,7 +166,89 @@ static int __init integrity_iintcache_init(void)
        iint_cache =
            kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
                              0, SLAB_PANIC, init_once);
-       iint_initialized = 1;
        return 0;
 }
 security_initcall(integrity_iintcache_init);
+
+
+/*
+ * integrity_kernel_read - read data from the file
+ *
+ * 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.
+ *
+ */
+int integrity_kernel_read(struct file *file, loff_t offset,
+                         char *addr, unsigned long count)
+{
+       mm_segment_t old_fs;
+       char __user *buf = (char __user *)addr;
+       ssize_t ret;
+
+       if (!(file->f_mode & FMODE_READ))
+               return -EBADF;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       ret = __vfs_read(file, buf, count, &offset);
+       set_fs(old_fs);
+
+       return ret;
+}
+
+/*
+ * integrity_read_file - read entire file content into the buffer
+ *
+ * This is function opens a file, allocates the buffer of required
+ * size, read entire file content to the buffer and closes the file
+ *
+ * It is used only by init code.
+ *
+ */
+int __init integrity_read_file(const char *path, char **data)
+{
+       struct file *file;
+       loff_t size;
+       char *buf;
+       int rc = -EINVAL;
+
+       file = filp_open(path, O_RDONLY, 0);
+       if (IS_ERR(file)) {
+               rc = PTR_ERR(file);
+               pr_err("Unable to open file: %s (%d)", path, rc);
+               return rc;
+       }
+
+       size = i_size_read(file_inode(file));
+       if (size <= 0)
+               goto out;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       rc = integrity_kernel_read(file, 0, buf, size);
+       if (rc < 0)
+               kfree(buf);
+       else if (rc != size)
+               rc = -EIO;
+       else
+               *data = buf;
+out:
+       fput(file);
+       return rc;
+}
+
+/*
+ * integrity_load_keys - load integrity keys hook
+ *
+ * Hooks is called from init/main.c:kernel_init_freeable()
+ * when rootfs is ready
+ */
+void __init integrity_load_keys(void)
+{
+       ima_load_x509();
+}
index e099875..b80a93e 100644 (file)
@@ -131,3 +131,28 @@ config IMA_TRUSTED_KEYRING
        help
           This option requires that all keys added to the .ima
           keyring be signed by a key on the system trusted keyring.
+
+config IMA_LOAD_X509
+       bool "Load X509 certificate onto the '.ima' trusted keyring"
+       depends on IMA_TRUSTED_KEYRING
+       default n
+       help
+          File signature verification is based on the public keys
+          loaded on the .ima trusted keyring. These public keys are
+          X509 certificates signed by a trusted key on the
+          .system keyring.  This option enables X509 certificate
+          loading from the kernel onto the '.ima' trusted keyring.
+
+config IMA_X509_PATH
+       string "IMA X509 certificate path"
+       depends on IMA_LOAD_X509
+       default "/etc/keys/x509_ima.der"
+       help
+          This option defines IMA X509 certificate path.
+
+config IMA_APPRAISE_SIGNED_INIT
+       bool "Require signed user-space initialization"
+       depends on IMA_LOAD_X509
+       default n
+       help
+          This option requires user-space init to be signed.
index 8688597..b0dc922 100644 (file)
@@ -173,8 +173,7 @@ int ima_get_action(struct inode *inode, int mask, int function)
 {
        int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
 
-       if (!ima_appraise)
-               flags &= ~IMA_APPRAISE;
+       flags &= ima_policy_flag;
 
        return ima_match_policy(inode, function, mask, flags);
 }
@@ -325,11 +324,11 @@ const char *ima_d_path(struct path *path, char **pathbuf)
 {
        char *pathname = NULL;
 
-       *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+       *pathbuf = __getname();
        if (*pathbuf) {
                pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
                if (IS_ERR(pathname)) {
-                       kfree(*pathbuf);
+                       __putname(*pathbuf);
                        *pathbuf = NULL;
                        pathname = NULL;
                }
index d34e7df..5df4d96 100644 (file)
@@ -67,36 +67,6 @@ MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
 static struct crypto_shash *ima_shash_tfm;
 static struct crypto_ahash *ima_ahash_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 = -EINVAL;
-
-       if (!(file->f_mode & FMODE_READ))
-               return -EBADF;
-
-       old_fs = get_fs();
-       set_fs(get_ds());
-       if (file->f_op->read)
-               ret = file->f_op->read(file, buf, count, &offset);
-       else if (file->f_op->aio_read)
-               ret = do_sync_read(file, buf, count, &offset);
-       else if (file->f_op->read_iter)
-               ret = new_sync_read(file, buf, count, &offset);
-       set_fs(old_fs);
-       return ret;
-}
-
 int __init ima_init_crypto(void)
 {
        long rc;
@@ -324,7 +294,8 @@ static int ima_calc_file_hash_atfm(struct file *file,
                }
                /* read buffer */
                rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
-               rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len);
+               rc = integrity_kernel_read(file, offset, rbuf[active],
+                                          rbuf_len);
                if (rc != rbuf_len)
                        goto out3;
 
@@ -417,7 +388,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
        while (offset < i_size) {
                int rbuf_len;
 
-               rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
+               rbuf_len = integrity_kernel_read(file, offset, rbuf, PAGE_SIZE);
                if (rbuf_len < 0) {
                        rc = rbuf_len;
                        break;
index da92fcc..461215e 100644 (file)
@@ -118,6 +118,7 @@ static int ima_measurements_show(struct seq_file *m, void *v)
        /* the list never shrinks, so we don't need a lock here */
        struct ima_queue_entry *qe = v;
        struct ima_template_entry *e;
+       char *template_name;
        int namelen;
        u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
        bool is_ima_template = false;
@@ -128,6 +129,9 @@ static int ima_measurements_show(struct seq_file *m, void *v)
        if (e == NULL)
                return -1;
 
+       template_name = (e->template_desc->name[0] != '\0') ?
+           e->template_desc->name : e->template_desc->fmt;
+
        /*
         * 1st: PCRIndex
         * PCR used is always the same (config option) in
@@ -139,14 +143,14 @@ static int ima_measurements_show(struct seq_file *m, void *v)
        ima_putc(m, e->digest, TPM_DIGEST_SIZE);
 
        /* 3rd: template name size */
-       namelen = strlen(e->template_desc->name);
+       namelen = strlen(template_name);
        ima_putc(m, &namelen, sizeof(namelen));
 
        /* 4th:  template name */
-       ima_putc(m, e->template_desc->name, namelen);
+       ima_putc(m, template_name, namelen);
 
        /* 5th:  template length (except for 'ima' template) */
-       if (strcmp(e->template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0)
+       if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
                is_ima_template = true;
 
        if (!is_ima_template)
@@ -200,6 +204,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
        /* the list never shrinks, so we don't need a lock here */
        struct ima_queue_entry *qe = v;
        struct ima_template_entry *e;
+       char *template_name;
        int i;
 
        /* get entry */
@@ -207,6 +212,9 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
        if (e == NULL)
                return -1;
 
+       template_name = (e->template_desc->name[0] != '\0') ?
+           e->template_desc->name : e->template_desc->fmt;
+
        /* 1st: PCR used (config option) */
        seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
 
@@ -214,7 +222,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
        ima_print_digest(m, e->digest, TPM_DIGEST_SIZE);
 
        /* 3th:  template name */
-       seq_printf(m, " %s", e->template_desc->name);
+       seq_printf(m, " %s", template_name);
 
        /* 4th:  template specific data */
        for (i = 0; i < e->template_desc->num_fields; i++) {
@@ -288,7 +296,12 @@ static struct dentry *runtime_measurements_count;
 static struct dentry *violations;
 static struct dentry *ima_policy;
 
-static atomic_t policy_opencount = ATOMIC_INIT(1);
+enum ima_fs_flags {
+       IMA_FS_BUSY,
+};
+
+static unsigned long ima_fs_flags;
+
 /*
  * ima_open_policy: sequentialize access to the policy file
  */
@@ -297,9 +310,9 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
        /* No point in being allowed to open it if you aren't going to write */
        if (!(filp->f_flags & O_WRONLY))
                return -EACCES;
-       if (atomic_dec_and_test(&policy_opencount))
-               return 0;
-       return -EBUSY;
+       if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
+               return -EBUSY;
+       return 0;
 }
 
 /*
@@ -311,10 +324,16 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
  */
 static int ima_release_policy(struct inode *inode, struct file *file)
 {
+       const char *cause = valid_policy ? "completed" : "failed";
+
+       pr_info("IMA: policy update %s\n", cause);
+       integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+                           "policy_update", cause, !valid_policy, 0);
+
        if (!valid_policy) {
                ima_delete_rules();
                valid_policy = 1;
-               atomic_set(&policy_opencount, 1);
+               clear_bit(IMA_FS_BUSY, &ima_fs_flags);
                return 0;
        }
        ima_update_policy();
index 9164fc8..5e4c29d 100644 (file)
 #include <crypto/hash_info.h>
 #include "ima.h"
 
+#ifdef CONFIG_IMA_X509_PATH
+#define IMA_X509_PATH  CONFIG_IMA_X509_PATH
+#else
+#define IMA_X509_PATH  "/etc/keys/x509_ima.der"
+#endif
+
 /* name for boot aggregate entry */
 static const char *boot_aggregate_name = "boot_aggregate";
 int ima_used_chip;
@@ -91,6 +97,17 @@ err_out:
        return result;
 }
 
+#ifdef CONFIG_IMA_LOAD_X509
+void __init ima_load_x509(void)
+{
+       int unset_flags = ima_policy_flag & IMA_APPRAISE;
+
+       ima_policy_flag &= ~unset_flags;
+       integrity_load_x509(INTEGRITY_KEYRING_IMA, IMA_X509_PATH);
+       ima_policy_flag |= unset_flags;
+}
+#endif
+
 int __init ima_init(void)
 {
        u8 pcr_i[TPM_DIGEST_SIZE];
index 62f59ec..eeee00d 100644 (file)
@@ -143,7 +143,7 @@ void ima_file_free(struct file *file)
        struct inode *inode = file_inode(file);
        struct integrity_iint_cache *iint;
 
-       if (!iint_initialized || !S_ISREG(inode->i_mode))
+       if (!ima_policy_flag || !S_ISREG(inode->i_mode))
                return;
 
        iint = integrity_iint_find(inode);
@@ -246,7 +246,8 @@ out_digsig:
                rc = -EACCES;
        kfree(xattr_value);
 out_free:
-       kfree(pathbuf);
+       if (pathbuf)
+               __putname(pathbuf);
 out:
        mutex_unlock(&inode->i_mutex);
        if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
index cdc620b..d1eefb9 100644 (file)
@@ -100,7 +100,13 @@ static struct ima_rule_entry default_appraise_rules[] = {
        {.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
        {.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
+#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
        {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER},
+#else
+       /* force signature */
+       {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID,
+        .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
+#endif
 };
 
 static LIST_HEAD(ima_default_rules);
@@ -356,19 +362,8 @@ void __init ima_init_policy(void)
  */
 void ima_update_policy(void)
 {
-       static const char op[] = "policy_update";
-       const char *cause = "already-exists";
-       int result = 1;
-       int audit_info = 0;
-
-       if (ima_rules == &ima_default_rules) {
-               ima_rules = &ima_policy_rules;
-               ima_update_policy_flag();
-               cause = "complete";
-               result = 0;
-       }
-       integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
-                           NULL, op, cause, result, audit_info);
+       ima_rules = &ima_policy_rules;
+       ima_update_policy_flag();
 }
 
 enum {
@@ -686,13 +681,12 @@ ssize_t ima_parse_add_rule(char *rule)
        ssize_t result, len;
        int audit_info = 0;
 
-       /* Prevent installed policy from changing */
-       if (ima_rules != &ima_default_rules) {
-               integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
-                                   NULL, op, "already-exists",
-                                   -EACCES, audit_info);
-               return -EACCES;
-       }
+       p = strsep(&rule, "\n");
+       len = strlen(p) + 1;
+       p += strspn(p, " \t");
+
+       if (*p == '#' || *p == '\0')
+               return len;
 
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry) {
@@ -703,14 +697,6 @@ ssize_t ima_parse_add_rule(char *rule)
 
        INIT_LIST_HEAD(&entry->list);
 
-       p = strsep(&rule, "\n");
-       len = strlen(p) + 1;
-
-       if (*p == '#') {
-               kfree(entry);
-               return len;
-       }
-
        result = ima_parse_rule(p, entry);
        if (result) {
                kfree(entry);
index e854862..0b7404e 100644 (file)
@@ -24,6 +24,7 @@ static struct ima_template_desc defined_templates[] = {
        {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
        {.name = "ima-ng", .fmt = "d-ng|n-ng"},
        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
+       {.name = "", .fmt = ""},        /* placeholder for a custom format */
 };
 
 static struct ima_template_field supported_fields[] = {
@@ -41,19 +42,28 @@ static struct ima_template_field supported_fields[] = {
 
 static struct ima_template_desc *ima_template;
 static struct ima_template_desc *lookup_template_desc(const char *name);
+static int template_desc_init_fields(const char *template_fmt,
+                                    struct ima_template_field ***fields,
+                                    int *num_fields);
 
 static int __init ima_template_setup(char *str)
 {
        struct ima_template_desc *template_desc;
        int template_len = strlen(str);
 
+       if (ima_template)
+               return 1;
+
        /*
         * Verify that a template with the supplied name exists.
         * If not, use CONFIG_IMA_DEFAULT_TEMPLATE.
         */
        template_desc = lookup_template_desc(str);
-       if (!template_desc)
+       if (!template_desc) {
+               pr_err("template %s not found, using %s\n",
+                      str, CONFIG_IMA_DEFAULT_TEMPLATE);
                return 1;
+       }
 
        /*
         * Verify whether the current hash algorithm is supported
@@ -70,6 +80,25 @@ static int __init ima_template_setup(char *str)
 }
 __setup("ima_template=", ima_template_setup);
 
+static int __init ima_template_fmt_setup(char *str)
+{
+       int num_templates = ARRAY_SIZE(defined_templates);
+
+       if (ima_template)
+               return 1;
+
+       if (template_desc_init_fields(str, NULL, NULL) < 0) {
+               pr_err("format string '%s' not valid, using template %s\n",
+                      str, CONFIG_IMA_DEFAULT_TEMPLATE);
+               return 1;
+       }
+
+       defined_templates[num_templates - 1].fmt = str;
+       ima_template = defined_templates + num_templates - 1;
+       return 1;
+}
+__setup("ima_template_fmt=", ima_template_fmt_setup);
+
 static struct ima_template_desc *lookup_template_desc(const char *name)
 {
        int i;
@@ -113,43 +142,46 @@ static int template_desc_init_fields(const char *template_fmt,
                                     struct ima_template_field ***fields,
                                     int *num_fields)
 {
-       char *c, *template_fmt_copy, *template_fmt_ptr;
+       const char *template_fmt_ptr;
+       struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
        int template_num_fields = template_fmt_size(template_fmt);
-       int i, result = 0;
+       int i, len;
 
-       if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX)
+       if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {
+               pr_err("format string '%s' contains too many fields\n",
+                      template_fmt);
                return -EINVAL;
-
-       /* copying is needed as strsep() modifies the original buffer */
-       template_fmt_copy = kstrdup(template_fmt, GFP_KERNEL);
-       if (template_fmt_copy == NULL)
-               return -ENOMEM;
-
-       *fields = kzalloc(template_num_fields * sizeof(*fields), GFP_KERNEL);
-       if (*fields == NULL) {
-               result = -ENOMEM;
-               goto out;
        }
 
-       template_fmt_ptr = template_fmt_copy;
-       for (i = 0; (c = strsep(&template_fmt_ptr, "|")) != NULL &&
-            i < template_num_fields; i++) {
-               struct ima_template_field *f = lookup_template_field(c);
+       for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields;
+            i++, template_fmt_ptr += len + 1) {
+               char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1];
+
+               len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr;
+               if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) {
+                       pr_err("Invalid field with length %d\n", len);
+                       return -EINVAL;
+               }
 
-               if (!f) {
-                       result = -ENOENT;
-                       goto out;
+               memcpy(tmp_field_id, template_fmt_ptr, len);
+               tmp_field_id[len] = '\0';
+               found_fields[i] = lookup_template_field(tmp_field_id);
+               if (!found_fields[i]) {
+                       pr_err("field '%s' not found\n", tmp_field_id);
+                       return -ENOENT;
                }
-               (*fields)[i] = f;
        }
-       *num_fields = i;
-out:
-       if (result < 0) {
-               kfree(*fields);
-               *fields = NULL;
+
+       if (fields && num_fields) {
+               *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL);
+               if (*fields == NULL)
+                       return -ENOMEM;
+
+               memcpy(*fields, found_fields, i * sizeof(*fields));
+               *num_fields = i;
        }
-       kfree(template_fmt_copy);
-       return result;
+
+       return 0;
 }
 
 struct ima_template_desc *ima_template_desc_current(void)
@@ -163,8 +195,15 @@ struct ima_template_desc *ima_template_desc_current(void)
 int __init ima_init_template(void)
 {
        struct ima_template_desc *template = ima_template_desc_current();
+       int result;
+
+       result = template_desc_init_fields(template->fmt,
+                                          &(template->fields),
+                                          &(template->num_fields));
+       if (result < 0)
+               pr_err("template %s init failed, result: %d\n",
+                      (strlen(template->name) ?
+                      template->name : template->fmt), result);
 
-       return template_desc_init_fields(template->fmt,
-                                        &(template->fields),
-                                        &(template->num_fields));
+       return result;
 }
index c0379d1..caa1f6c 100644 (file)
@@ -119,6 +119,10 @@ struct integrity_iint_cache {
  */
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
+int integrity_kernel_read(struct file *file, loff_t offset,
+                         char *addr, unsigned long count);
+int __init integrity_read_file(const char *path, char **data);
+
 #define INTEGRITY_KEYRING_EVM          0
 #define INTEGRITY_KEYRING_MODULE       1
 #define INTEGRITY_KEYRING_IMA          2
@@ -129,7 +133,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
                            const char *digest, int digestlen);
 
-int integrity_init_keyring(const unsigned int id);
+int __init integrity_init_keyring(const unsigned int id);
+int __init integrity_load_x509(const unsigned int id, char *path);
 #else
 
 static inline int integrity_digsig_verify(const unsigned int id,
@@ -143,6 +148,7 @@ static inline int integrity_init_keyring(const unsigned int id)
 {
        return 0;
 }
+
 #endif /* CONFIG_INTEGRITY_SIGNATURE */
 
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
@@ -156,6 +162,14 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig,
 }
 #endif
 
+#ifdef CONFIG_IMA_LOAD_X509
+void __init ima_load_x509(void);
+#else
+static inline void ima_load_x509(void)
+{
+}
+#endif
+
 #ifdef CONFIG_INTEGRITY_AUDIT
 /* declarations */
 void integrity_audit_msg(int audit_msgno, struct inode *inode,
@@ -169,6 +183,3 @@ static inline void integrity_audit_msg(int audit_msgno, struct inode *inode,
 {
 }
 #endif
-
-/* set during initialization */
-extern int iint_initialized;