ima: Support additional conditionals in the KEXEC_CMDLINE hook function
authorTyler Hicks <tyhicks@linux.microsoft.com>
Thu, 9 Jul 2020 06:19:11 +0000 (01:19 -0500)
committerMimi Zohar <zohar@linux.ibm.com>
Mon, 20 Jul 2020 17:28:16 +0000 (13:28 -0400)
Take the properties of the kexec kernel's inode and the current task
ownership into consideration when matching a KEXEC_CMDLINE operation to
the rules in the IMA policy. This allows for some uniformity when
writing IMA policy rules for KEXEC_KERNEL_CHECK, KEXEC_INITRAMFS_CHECK,
and KEXEC_CMDLINE operations.

Prior to this patch, it was not possible to write a set of rules like
this:

 dont_measure func=KEXEC_KERNEL_CHECK obj_type=foo_t
 dont_measure func=KEXEC_INITRAMFS_CHECK obj_type=foo_t
 dont_measure func=KEXEC_CMDLINE obj_type=foo_t
 measure func=KEXEC_KERNEL_CHECK
 measure func=KEXEC_INITRAMFS_CHECK
 measure func=KEXEC_CMDLINE

The inode information associated with the kernel being loaded by a
kexec_kernel_load(2) syscall can now be included in the decision to
measure or not

Additonally, the uid, euid, and subj_* conditionals can also now be
used in KEXEC_CMDLINE rules. There was no technical reason as to why
those conditionals weren't being considered previously other than
ima_match_rules() didn't have a valid inode to use so it immediately
bailed out for KEXEC_CMDLINE operations rather than going through the
full list of conditional comparisons.

Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: kexec@lists.infradead.org
Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
include/linux/ima.h
kernel/kexec_file.c
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_asymmetric_keys.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_queue_keys.c

index 9164e15..d15100d 100644 (file)
@@ -25,7 +25,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
                              enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
-extern void ima_kexec_cmdline(const void *buf, int size);
+extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
 
 #ifdef CONFIG_IMA_KEXEC
 extern void ima_add_kexec_buffer(struct kimage *image);
@@ -103,7 +103,7 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
        return -EOPNOTSUPP;
 }
 
-static inline void ima_kexec_cmdline(const void *buf, int size) {}
+static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
 #endif /* CONFIG_IMA */
 
 #ifndef CONFIG_IMA_KEXEC
index bb05fd5..07df431 100644 (file)
@@ -287,7 +287,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
                        goto out;
                }
 
-               ima_kexec_cmdline(image->cmdline_buf,
+               ima_kexec_cmdline(kernel_fd, image->cmdline_buf,
                                  image->cmdline_buf_len - 1);
        }
 
index ea7e775..576ae2c 100644 (file)
@@ -265,7 +265,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
                           struct evm_ima_xattr_data *xattr_value,
                           int xattr_len, const struct modsig *modsig, int pcr,
                           struct ima_template_desc *template_desc);
-void process_buffer_measurement(const void *buf, int size,
+void process_buffer_measurement(struct inode *inode, const void *buf, int size,
                                const char *eventname, enum ima_hooks func,
                                int pcr, const char *keyring);
 void ima_audit_measurement(struct integrity_iint_cache *iint,
index bf22de8..4f39fb9 100644 (file)
@@ -162,7 +162,7 @@ err_out:
 
 /**
  * ima_get_action - appraise & measure decision based on policy.
- * @inode: pointer to inode to measure
+ * @inode: pointer to the inode associated with the object being validated
  * @cred: pointer to credentials structure to validate
  * @secid: secid of the task being validated
  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
index a9649b0..6c52bf7 100644 (file)
@@ -328,7 +328,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
 
                rc = is_binary_blacklisted(digest, digestsize);
                if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
-                       process_buffer_measurement(digest, digestsize,
+                       process_buffer_measurement(NULL, digest, digestsize,
                                                   "blacklisted-hash", NONE,
                                                   pcr, NULL);
        }
index aaae80c..1c68c50 100644 (file)
@@ -58,7 +58,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
         * if the IMA policy is configured to measure a key linked
         * to the given keyring.
         */
-       process_buffer_measurement(payload, payload_len,
+       process_buffer_measurement(NULL, payload, payload_len,
                                   keyring->description, KEY_CHECK, 0,
                                   keyring->description);
 }
index 8351b2f..8a91711 100644 (file)
@@ -726,6 +726,7 @@ int ima_load_data(enum kernel_load_data_id id)
 
 /*
  * process_buffer_measurement - Measure the buffer to ima log.
+ * @inode: inode associated with the object being measured (NULL for KEY_CHECK)
  * @buf: pointer to the buffer that needs to be added to the log.
  * @size: size of buffer(in bytes).
  * @eventname: event name to be used for the buffer entry.
@@ -735,7 +736,7 @@ int ima_load_data(enum kernel_load_data_id id)
  *
  * Based on policy, the buffer is measured into the ima log.
  */
-void process_buffer_measurement(const void *buf, int size,
+void process_buffer_measurement(struct inode *inode, const void *buf, int size,
                                const char *eventname, enum ima_hooks func,
                                int pcr, const char *keyring)
 {
@@ -768,7 +769,7 @@ void process_buffer_measurement(const void *buf, int size,
         */
        if (func) {
                security_task_getsecid(current, &secid);
-               action = ima_get_action(NULL, current_cred(), secid, 0, func,
+               action = ima_get_action(inode, current_cred(), secid, 0, func,
                                        &pcr, &template, keyring);
                if (!(action & IMA_MEASURE))
                        return;
@@ -823,16 +824,26 @@ out:
 
 /**
  * ima_kexec_cmdline - measure kexec cmdline boot args
+ * @kernel_fd: file descriptor of the kexec kernel being loaded
  * @buf: pointer to buffer
  * @size: size of buffer
  *
  * Buffers can only be measured, not appraised.
  */
-void ima_kexec_cmdline(const void *buf, int size)
+void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
 {
-       if (buf && size != 0)
-               process_buffer_measurement(buf, size, "kexec-cmdline",
-                                          KEXEC_CMDLINE, 0, NULL);
+       struct fd f;
+
+       if (!buf || !size)
+               return;
+
+       f = fdget(kernel_fd);
+       if (!f.file)
+               return;
+
+       process_buffer_measurement(file_inode(f.file), buf, size,
+                                  "kexec-cmdline", KEXEC_CMDLINE, 0, NULL);
+       fdput(f);
 }
 
 static int __init init_ima(void)
index dcd1aaa..9284055 100644 (file)
@@ -443,13 +443,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
 {
        int i;
 
-       if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) {
-               if ((rule->flags & IMA_FUNC) && (rule->func == func)) {
-                       if (func == KEY_CHECK)
-                               return ima_match_keyring(rule, keyring, cred);
-                       return true;
-               }
-               return false;
+       if (func == KEY_CHECK) {
+               return (rule->flags & IMA_FUNC) && (rule->func == func) &&
+                      ima_match_keyring(rule, keyring, cred);
        }
        if ((rule->flags & IMA_FUNC) &&
            (rule->func != func && func != POST_SETATTR))
@@ -1035,10 +1031,9 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
                if (entry->action & ~(MEASURE | DONT_MEASURE))
                        return false;
 
-               if (entry->flags & ~(IMA_FUNC | IMA_PCR))
-                       return false;
-
-               if (ima_rule_contains_lsm_cond(entry))
+               if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID |
+                                    IMA_FOWNER | IMA_FSUUID | IMA_EUID |
+                                    IMA_PCR | IMA_FSNAME))
                        return false;
 
                break;
index 56ce24a..69a8626 100644 (file)
@@ -158,7 +158,7 @@ void ima_process_queued_keys(void)
 
        list_for_each_entry_safe(entry, tmp, &ima_keys, list) {
                if (!timer_expired)
-                       process_buffer_measurement(entry->payload,
+                       process_buffer_measurement(NULL, entry->payload,
                                                   entry->payload_len,
                                                   entry->keyring_name,
                                                   KEY_CHECK, 0,