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