1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2016 IBM Corporation 4 * 5 * Authors: 6 * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> 7 * Mimi Zohar <zohar@linux.vnet.ibm.com> 8 */ 9 10 #include <linux/seq_file.h> 11 #include <linux/vmalloc.h> 12 #include <linux/kexec.h> 13 #include <linux/of.h> 14 #include "ima.h" 15 16 #ifdef CONFIG_IMA_KEXEC 17 static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, 18 unsigned long segment_size) 19 { 20 struct ima_queue_entry *qe; 21 struct seq_file file; 22 struct ima_kexec_hdr khdr; 23 int ret = 0; 24 25 /* segment size can't change between kexec load and execute */ 26 file.buf = vmalloc(segment_size); 27 if (!file.buf) { 28 ret = -ENOMEM; 29 goto out; 30 } 31 32 file.size = segment_size; 33 file.read_pos = 0; 34 file.count = sizeof(khdr); /* reserved space */ 35 36 memset(&khdr, 0, sizeof(khdr)); 37 khdr.version = 1; 38 list_for_each_entry_rcu(qe, &ima_measurements, later) { 39 if (file.count < file.size) { 40 khdr.count++; 41 ima_measurements_show(&file, qe); 42 } else { 43 ret = -EINVAL; 44 break; 45 } 46 } 47 48 if (ret < 0) 49 goto out; 50 51 /* 52 * fill in reserved space with some buffer details 53 * (eg. version, buffer size, number of measurements) 54 */ 55 khdr.buffer_size = file.count; 56 if (ima_canonical_fmt) { 57 khdr.version = cpu_to_le16(khdr.version); 58 khdr.count = cpu_to_le64(khdr.count); 59 khdr.buffer_size = cpu_to_le64(khdr.buffer_size); 60 } 61 memcpy(file.buf, &khdr, sizeof(khdr)); 62 63 print_hex_dump(KERN_DEBUG, "ima dump: ", DUMP_PREFIX_NONE, 64 16, 1, file.buf, 65 file.count < 100 ? file.count : 100, true); 66 67 *buffer_size = file.count; 68 *buffer = file.buf; 69 out: 70 if (ret == -EINVAL) 71 vfree(file.buf); 72 return ret; 73 } 74 75 /* 76 * Called during kexec_file_load so that IMA can add a segment to the kexec 77 * image for the measurement list for the next kernel. 78 * 79 * This function assumes that kexec_mutex is held. 80 */ 81 void ima_add_kexec_buffer(struct kimage *image) 82 { 83 struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE, 84 .buf_min = 0, .buf_max = ULONG_MAX, 85 .top_down = true }; 86 unsigned long binary_runtime_size; 87 88 /* use more understandable variable names than defined in kbuf */ 89 void *kexec_buffer = NULL; 90 size_t kexec_buffer_size; 91 size_t kexec_segment_size; 92 int ret; 93 94 /* 95 * Reserve an extra half page of memory for additional measurements 96 * added during the kexec load. 97 */ 98 binary_runtime_size = ima_get_binary_runtime_size(); 99 if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) 100 kexec_segment_size = ULONG_MAX; 101 else 102 kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + 103 PAGE_SIZE / 2, PAGE_SIZE); 104 if ((kexec_segment_size == ULONG_MAX) || 105 ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { 106 pr_err("Binary measurement list too large.\n"); 107 return; 108 } 109 110 ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, 111 kexec_segment_size); 112 if (!kexec_buffer) { 113 pr_err("Not enough memory for the kexec measurement buffer.\n"); 114 return; 115 } 116 117 kbuf.buffer = kexec_buffer; 118 kbuf.bufsz = kexec_buffer_size; 119 kbuf.memsz = kexec_segment_size; 120 ret = kexec_add_buffer(&kbuf); 121 if (ret) { 122 pr_err("Error passing over kexec measurement buffer.\n"); 123 vfree(kexec_buffer); 124 return; 125 } 126 127 image->ima_buffer_addr = kbuf.mem; 128 image->ima_buffer_size = kexec_segment_size; 129 image->ima_buffer = kexec_buffer; 130 131 pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n", 132 kbuf.mem); 133 } 134 #endif /* IMA_KEXEC */ 135 136 /* 137 * Restore the measurement list from the previous kernel. 138 */ 139 void ima_load_kexec_buffer(void) 140 { 141 void *kexec_buffer = NULL; 142 size_t kexec_buffer_size = 0; 143 int rc; 144 145 rc = ima_get_kexec_buffer(&kexec_buffer, &kexec_buffer_size); 146 switch (rc) { 147 case 0: 148 rc = ima_restore_measurement_list(kexec_buffer_size, 149 kexec_buffer); 150 if (rc != 0) 151 pr_err("Failed to restore the measurement list: %d\n", 152 rc); 153 154 ima_free_kexec_buffer(); 155 break; 156 case -ENOTSUPP: 157 pr_debug("Restoring the measurement list not supported\n"); 158 break; 159 case -ENOENT: 160 pr_debug("No measurement list to restore\n"); 161 break; 162 default: 163 pr_debug("Error restoring the measurement list: %d\n", rc); 164 } 165 } 166