Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 IBM Corporation
0004  *
0005  * Authors:
0006  * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
0007  * Mimi Zohar <zohar@linux.vnet.ibm.com>
0008  */
0009 
0010 #include <linux/seq_file.h>
0011 #include <linux/vmalloc.h>
0012 #include <linux/kexec.h>
0013 #include <linux/of.h>
0014 #include <linux/ima.h>
0015 #include "ima.h"
0016 
0017 #ifdef CONFIG_IMA_KEXEC
0018 static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
0019                      unsigned long segment_size)
0020 {
0021     struct ima_queue_entry *qe;
0022     struct seq_file file;
0023     struct ima_kexec_hdr khdr;
0024     int ret = 0;
0025 
0026     /* segment size can't change between kexec load and execute */
0027     file.buf = vmalloc(segment_size);
0028     if (!file.buf) {
0029         ret = -ENOMEM;
0030         goto out;
0031     }
0032 
0033     file.size = segment_size;
0034     file.read_pos = 0;
0035     file.count = sizeof(khdr);  /* reserved space */
0036 
0037     memset(&khdr, 0, sizeof(khdr));
0038     khdr.version = 1;
0039     list_for_each_entry_rcu(qe, &ima_measurements, later) {
0040         if (file.count < file.size) {
0041             khdr.count++;
0042             ima_measurements_show(&file, qe);
0043         } else {
0044             ret = -EINVAL;
0045             break;
0046         }
0047     }
0048 
0049     if (ret < 0)
0050         goto out;
0051 
0052     /*
0053      * fill in reserved space with some buffer details
0054      * (eg. version, buffer size, number of measurements)
0055      */
0056     khdr.buffer_size = file.count;
0057     if (ima_canonical_fmt) {
0058         khdr.version = cpu_to_le16(khdr.version);
0059         khdr.count = cpu_to_le64(khdr.count);
0060         khdr.buffer_size = cpu_to_le64(khdr.buffer_size);
0061     }
0062     memcpy(file.buf, &khdr, sizeof(khdr));
0063 
0064     print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1,
0065                  file.buf, file.count < 100 ? file.count : 100,
0066                  true);
0067 
0068     *buffer_size = file.count;
0069     *buffer = file.buf;
0070 out:
0071     if (ret == -EINVAL)
0072         vfree(file.buf);
0073     return ret;
0074 }
0075 
0076 /*
0077  * Called during kexec_file_load so that IMA can add a segment to the kexec
0078  * image for the measurement list for the next kernel.
0079  *
0080  * This function assumes that kexec_mutex is held.
0081  */
0082 void ima_add_kexec_buffer(struct kimage *image)
0083 {
0084     struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE,
0085                   .buf_min = 0, .buf_max = ULONG_MAX,
0086                   .top_down = true };
0087     unsigned long binary_runtime_size;
0088 
0089     /* use more understandable variable names than defined in kbuf */
0090     void *kexec_buffer = NULL;
0091     size_t kexec_buffer_size;
0092     size_t kexec_segment_size;
0093     int ret;
0094 
0095     /*
0096      * Reserve an extra half page of memory for additional measurements
0097      * added during the kexec load.
0098      */
0099     binary_runtime_size = ima_get_binary_runtime_size();
0100     if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
0101         kexec_segment_size = ULONG_MAX;
0102     else
0103         kexec_segment_size = ALIGN(ima_get_binary_runtime_size() +
0104                        PAGE_SIZE / 2, PAGE_SIZE);
0105     if ((kexec_segment_size == ULONG_MAX) ||
0106         ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) {
0107         pr_err("Binary measurement list too large.\n");
0108         return;
0109     }
0110 
0111     ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
0112                   kexec_segment_size);
0113     if (!kexec_buffer) {
0114         pr_err("Not enough memory for the kexec measurement buffer.\n");
0115         return;
0116     }
0117 
0118     kbuf.buffer = kexec_buffer;
0119     kbuf.bufsz = kexec_buffer_size;
0120     kbuf.memsz = kexec_segment_size;
0121     ret = kexec_add_buffer(&kbuf);
0122     if (ret) {
0123         pr_err("Error passing over kexec measurement buffer.\n");
0124         vfree(kexec_buffer);
0125         return;
0126     }
0127 
0128     image->ima_buffer_addr = kbuf.mem;
0129     image->ima_buffer_size = kexec_segment_size;
0130     image->ima_buffer = kexec_buffer;
0131 
0132     pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
0133          kbuf.mem);
0134 }
0135 #endif /* IMA_KEXEC */
0136 
0137 /*
0138  * Restore the measurement list from the previous kernel.
0139  */
0140 void __init ima_load_kexec_buffer(void)
0141 {
0142     void *kexec_buffer = NULL;
0143     size_t kexec_buffer_size = 0;
0144     int rc;
0145 
0146     rc = ima_get_kexec_buffer(&kexec_buffer, &kexec_buffer_size);
0147     switch (rc) {
0148     case 0:
0149         rc = ima_restore_measurement_list(kexec_buffer_size,
0150                           kexec_buffer);
0151         if (rc != 0)
0152             pr_err("Failed to restore the measurement list: %d\n",
0153                 rc);
0154 
0155         ima_free_kexec_buffer();
0156         break;
0157     case -ENOTSUPP:
0158         pr_debug("Restoring the measurement list not supported\n");
0159         break;
0160     case -ENOENT:
0161         pr_debug("No measurement list to restore\n");
0162         break;
0163     default:
0164         pr_debug("Error restoring the measurement list: %d\n", rc);
0165     }
0166 }