Merge tag 'integrity-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2020 19:06:07 +0000 (11:06 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2020 19:06:07 +0000 (11:06 -0800)
Pull integrity subsystem updates from Mimi Zohar:
 "Just three patches here. Other integrity changes are being upstreamed
  via EFI (defines a common EFI secure and trusted boot IMA policy) and
  BPF LSM (exporting the IMA file cache hash info based on inode).

  The three patches included here:

   - bug fix: fail calculating the file hash, when a file not opened for
     read and the attempt to re-open it for read fails.

   - defer processing the "ima_appraise" boot command line option to
     avoid enabling different modes (e.g. fix, log) to when the secure
     boot flag is available on arm.

   - defines "ima-buf" as the default IMA buffer measurement template in
     preparation for the builtin integrity "critical data" policy"

* tag 'integrity-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  ima: Don't modify file descriptor mode on the fly
  ima: select ima-buf template for buffer measurement
  ima: defer arch_ima_get_secureboot() call to IMA init time

include/linux/ima.h
security/integrity/ima/ima.h
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c

index 7233a2751754b80aa73d84f93d4e0b60886fb288..7db9cca1af34fef18074189324418e38ea1c81dd 100644 (file)
@@ -32,6 +32,12 @@ extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
 extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
 extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
 
+#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
+extern void ima_appraise_parse_cmdline(void);
+#else
+static inline void ima_appraise_parse_cmdline(void) {}
+#endif
+
 #ifdef CONFIG_IMA_KEXEC
 extern void ima_add_kexec_buffer(struct kimage *image);
 #endif
index 6ebefec616e442c7271e346ae85ecbb998b65cb6..8e8b1e3cb847a2feebf1ed26f07ba58f5cb03b61 100644 (file)
@@ -156,6 +156,7 @@ int template_desc_init_fields(const char *template_fmt,
                              const struct ima_template_field ***fields,
                              int *num_fields);
 struct ima_template_desc *ima_template_desc_current(void);
+struct ima_template_desc *ima_template_desc_buf(void);
 struct ima_template_desc *lookup_template_desc(const char *name);
 bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
 int ima_restore_measurement_entry(struct ima_template_entry *entry);
index 3dd8c2e4314ea0f99cbc07a412f46753ddcba895..8361941ee0a12120b6a154f29fbbc6b8802cd77e 100644 (file)
@@ -5,6 +5,7 @@
  * Author:
  * Mimi Zohar <zohar@us.ibm.com>
  */
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/fs.h>
 
 #include "ima.h"
 
-static int __init default_appraise_setup(char *str)
-{
 #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
+static char *ima_appraise_cmdline_default __initdata;
+core_param(ima_appraise, ima_appraise_cmdline_default, charp, 0);
+
+void __init ima_appraise_parse_cmdline(void)
+{
+       const char *str = ima_appraise_cmdline_default;
        bool sb_state = arch_ima_get_secureboot();
        int appraisal_state = ima_appraise;
 
+       if (!str)
+               return;
+
        if (strncmp(str, "off", 3) == 0)
                appraisal_state = 0;
        else if (strncmp(str, "log", 3) == 0)
@@ -42,11 +50,8 @@ static int __init default_appraise_setup(char *str)
        } else {
                ima_appraise = appraisal_state;
        }
-#endif
-       return 1;
 }
-
-__setup("ima_appraise=", default_appraise_setup);
+#endif
 
 /*
  * is_ima_appraise_enabled - return appraise status
index 21989fa0c10741b144f42d5cdf476c9020272b23..f6a7e9643b546b1fecad77ef87684fedb5c45526 100644 (file)
@@ -537,7 +537,7 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
        loff_t i_size;
        int rc;
        struct file *f = file;
-       bool new_file_instance = false, modified_mode = false;
+       bool new_file_instance = false;
 
        /*
         * For consistency, fail file's opened with the O_DIRECT flag on
@@ -555,18 +555,10 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
                                O_TRUNC | O_CREAT | O_NOCTTY | O_EXCL);
                flags |= O_RDONLY;
                f = dentry_open(&file->f_path, flags, file->f_cred);
-               if (IS_ERR(f)) {
-                       /*
-                        * Cannot open the file again, lets modify f_mode
-                        * of original and continue
-                        */
-                       pr_info_ratelimited("Unable to reopen file for reading.\n");
-                       f = file;
-                       f->f_mode |= FMODE_READ;
-                       modified_mode = true;
-               } else {
-                       new_file_instance = true;
-               }
+               if (IS_ERR(f))
+                       return PTR_ERR(f);
+
+               new_file_instance = true;
        }
 
        i_size = i_size_read(file_inode(f));
@@ -581,8 +573,6 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
 out:
        if (new_file_instance)
                fput(f);
-       else if (modified_mode)
-               f->f_mode &= ~FMODE_READ;
        return rc;
 }
 
index cb2deaa188e7f57ba00713c230c4369e635be392..f87cb29329e918e4a65391b76077f697e9dc496d 100644 (file)
@@ -413,7 +413,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
  */
 int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
 {
-       struct ima_template_desc *template;
+       struct ima_template_desc *template = NULL;
        struct file *file = vma->vm_file;
        char filename[NAME_MAX];
        char *pathbuf = NULL;
@@ -832,7 +832,7 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
                                            .filename = eventname,
                                            .buf = buf,
                                            .buf_len = size};
-       struct ima_template_desc *template = NULL;
+       struct ima_template_desc *template;
        struct {
                struct ima_digest_data hdr;
                char digest[IMA_MAX_DIGEST_SIZE];
@@ -844,6 +844,13 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
        if (!ima_policy_flag)
                return;
 
+       template = ima_template_desc_buf();
+       if (!template) {
+               ret = -EINVAL;
+               audit_cause = "ima_template_desc_buf";
+               goto out;
+       }
+
        /*
         * Both LSM hooks and auxilary based buffer measurements are
         * based on policy.  To avoid code duplication, differentiate
@@ -862,19 +869,6 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size,
        if (!pcr)
                pcr = CONFIG_IMA_MEASURE_PCR_IDX;
 
-       if (!template) {
-               template = lookup_template_desc("ima-buf");
-               ret = template_desc_init_fields(template->fmt,
-                                               &(template->fields),
-                                               &(template->num_fields));
-               if (ret < 0) {
-                       pr_err("template %s init failed, result: %d\n",
-                              (strlen(template->name) ?
-                               template->name : template->fmt), ret);
-                       return;
-               }
-       }
-
        iint.ima_hash = &hash.hdr;
        iint.ima_hash->algo = ima_hash_algo;
        iint.ima_hash->length = hash_digest_size[ima_hash_algo];
@@ -934,6 +928,7 @@ static int __init init_ima(void)
 {
        int error;
 
+       ima_appraise_parse_cmdline();
        ima_init_template_list();
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
index 9b5adeaa47fc819c4c9fc6396871db2848770505..823a0c1379cb3997b12fa0964aec45f822076713 100644 (file)
@@ -628,7 +628,7 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
        struct ima_rule_entry *entry;
        int action = 0, actmask = flags | (flags << 1);
 
-       if (template_desc)
+       if (template_desc && !*template_desc)
                *template_desc = ima_template_desc_current();
 
        rcu_read_lock();
index 1e89e2d3851f997f5f455c3e82f9854932b3280b..e22e510ae92d46a6ac3dc5915371e20de47ad01d 100644 (file)
@@ -55,6 +55,7 @@ static const struct ima_template_field supported_fields[] = {
 #define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
 
 static struct ima_template_desc *ima_template;
+static struct ima_template_desc *ima_buf_template;
 
 /**
  * ima_template_has_modsig - Check whether template has modsig-related fields.
@@ -252,11 +253,36 @@ struct ima_template_desc *ima_template_desc_current(void)
        return ima_template;
 }
 
+struct ima_template_desc *ima_template_desc_buf(void)
+{
+       if (!ima_buf_template) {
+               ima_init_template_list();
+               ima_buf_template = lookup_template_desc("ima-buf");
+       }
+       return ima_buf_template;
+}
+
 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 result;
+       }
+
+       template = ima_template_desc_buf();
+       if (!template) {
+               pr_err("Failed to get ima-buf template\n");
+               return -EINVAL;
+       }
+
        result = template_desc_init_fields(template->fmt,
                                           &(template->fields),
                                           &(template->num_fields));