]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
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 9164e1534ec988ce153bb0d3214cc6a049219355..d15100de6cdddd7101838a2803b978ccd4545d9b 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 bb05fd52de850ad388cdcd228d62e145804d611e..07df431c1f2132d6e46917d335a47f94b12f8335 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 ea7e77536f3cae49274c920012dfa02fa6137d5d..576ae2c6d418b3e492b3eeb57c40744ee00d14fc 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 bf22de8b7ce0728fe40922ceae49e31dca306fe0..4f39fb93f278a052df82d1f3e78a9bb321526863 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 a9649b04b9f1d8acb47ea5f80f20b2b09703f6a3..6c52bf7ea7f01015da3f9cb1b556c4df15794cc9 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 aaae80c4e376bff477ca9e879bc0bde0e5d43c48..1c68c500c26ff20d1c85ae11323d691709a0777c 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 8351b2fd48e0ec509614c960117e9e8561cd6969..8a91711ca79b2af3999f981d1fe7a0dfd5c1b78e 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 dcd1aaac4ff0a300fb38e37af317fcf8a3a9cb1e..9284055ee13a5505e5db8d7da5d2a44e0e4a3d05 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 56ce24a18b66a33959724e8f60d18de18046f19a..69a8626a35c0ebefc332edfff10aa5a0094193c3 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,