From patchwork Wed Feb 14 15:38:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556702 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6896E5CDC9 for ; Wed, 14 Feb 2024 15:38:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; cv=none; b=Ct216E6w/2mMHXAiKlfSmRSFHXV40yjKg29DoPz8gfTD7TD6kpDAakiP56RNwV4srt1WBLy1x5zkVTiNxyecbX6DtfCoajm2ZOaEwywJ+7gxOztWUMAU8MojBP+fPH7tdndRgtKEJkT4EfhXgfv6TuFYyG7x4VNaaCg0fVx5SS8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; c=relaxed/simple; bh=6YY03EJ7DtnV78pgcfMzbqgsT+gtRkKMsc3o0XHKTOk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VX6Lkut+6RX6msAT5dQDdqJyJQG7AhNIfmHYax63h/mtgCbW8sF6/7m5MBuUdvhFN3wVMBtHM/REmO/8+b61wTzdaA8fdAIZgNWUktSqiPPV25mUIlxwrF9ylNNlDZQNF04WIYTvGgkV5MRXpZf8LCSuIIAcfPyPiSc5l7H2lEg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=RaG36p9p; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="RaG36p9p" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id C2E2F20B2001; Wed, 14 Feb 2024 07:38:34 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com C2E2F20B2001 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925115; bh=H4nru9EiBeb6SuxSRWzkQUgOGrA4PpjrQdLheaVABOI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RaG36p9prffTLNngBM150+19tPW9v+d5YNOgJpUgyhjdta4Qg+boE50AcFcpROV5X 54GPUWCI3/b66gS2V/N/AFBYE7MYEy9tDsnKoouJGU+jT0qgPhWwuK29DdUQqSnVax Jd9VxvME6BSkFgFFIkQehR5beJJzAuLLX1GS1cjE= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 1/8] ima: define and call ima_alloc_kexec_file_buf Date: Wed, 14 Feb 2024 07:38:20 -0800 Message-Id: <20240214153827.1087657-2-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Carrying the IMA measurement list across kexec requires allocating a buffer and copying the measurement records. Separate allocating the buffer and copying the measurement records into separate functions in order to allocate the buffer at kexec 'load' and copy the measurements at kexec 'execute'. This patch includes the following changes: - Refactor ima_dump_measurement_list() to move the memory allocation to a separate function ima_alloc_kexec_file_buf() which allocates buffer of size 'kexec_segment_size' at kexec 'load'. - Make the local variable ima_kexec_file in ima_dump_measurement_list() as local static to the file, so that it can be accessed from ima_alloc_kexec_file_buf(). - Make necessary changes to the function ima_add_kexec_buffer() to call the above two functions. Suggested-by: Stefan Berger Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima_kexec.c | 107 +++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index dadc1d138118..a9cb5e882e2e 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,62 +15,98 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +static struct seq_file ima_kexec_file; + +static void ima_reset_kexec_file(struct seq_file *sf) +{ + sf->buf = NULL; + sf->size = 0; + sf->read_pos = 0; + sf->count = 0; +} + +static void ima_free_kexec_file_buf(struct seq_file *sf) +{ + vfree(sf->buf); + ima_reset_kexec_file(sf); +} + +static int ima_alloc_kexec_file_buf(size_t segment_size) +{ + /* + * kexec 'load' may be called multiple times. + * Free and realloc the buffer only if the segment_size is + * changed from the previous kexec 'load' call. + */ + if (ima_kexec_file.buf && + ima_kexec_file.size == segment_size && + ima_kexec_file.read_pos == 0 && + ima_kexec_file.count == sizeof(struct ima_kexec_hdr)) + return 0; + + ima_free_kexec_file_buf(&ima_kexec_file); + + /* segment size can't change between kexec load and execute */ + ima_kexec_file.buf = vmalloc(segment_size); + if (!ima_kexec_file.buf) + return -ENOMEM; + + ima_kexec_file.size = segment_size; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ + + return 0; +} + static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, unsigned long segment_size) { struct ima_queue_entry *qe; - struct seq_file file; struct ima_kexec_hdr khdr; - int ret = 0; - /* segment size can't change between kexec load and execute */ - file.buf = vmalloc(segment_size); - if (!file.buf) { - ret = -ENOMEM; - goto out; + if (!ima_kexec_file.buf) { + *buffer_size = 0; + *buffer = NULL; + pr_err("%s: Kexec file buf not allocated\n", __func__); + return -EINVAL; } - file.size = segment_size; - file.read_pos = 0; - file.count = sizeof(khdr); /* reserved space */ - memset(&khdr, 0, sizeof(khdr)); khdr.version = 1; + + /* Copy as many IMA measurements list records as possible */ list_for_each_entry_rcu(qe, &ima_measurements, later) { - if (file.count < file.size) { + if (ima_kexec_file.count < ima_kexec_file.size) { khdr.count++; - ima_measurements_show(&file, qe); + ima_measurements_show(&ima_kexec_file, qe); } else { - ret = -EINVAL; + pr_err("%s: IMA log file is too big for Kexec buf\n", + __func__); break; } } - if (ret < 0) - goto out; - /* * fill in reserved space with some buffer details * (eg. version, buffer size, number of measurements) */ - khdr.buffer_size = file.count; + khdr.buffer_size = ima_kexec_file.count; if (ima_canonical_fmt) { khdr.version = cpu_to_le16(khdr.version); khdr.count = cpu_to_le64(khdr.count); khdr.buffer_size = cpu_to_le64(khdr.buffer_size); } - memcpy(file.buf, &khdr, sizeof(khdr)); + memcpy(ima_kexec_file.buf, &khdr, sizeof(khdr)); print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, - file.buf, file.count < 100 ? file.count : 100, + ima_kexec_file.buf, ima_kexec_file.count < 100 ? + ima_kexec_file.count : 100, true); - *buffer_size = file.count; - *buffer = file.buf; -out: - if (ret == -EINVAL) - vfree(file.buf); - return ret; + *buffer_size = ima_kexec_file.count; + *buffer = ima_kexec_file.buf; + + return 0; } /* @@ -108,13 +144,20 @@ void ima_add_kexec_buffer(struct kimage *image) return; } - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, - kexec_segment_size); - if (!kexec_buffer) { + ret = ima_alloc_kexec_file_buf(kexec_segment_size); + if (ret < 0) { pr_err("Not enough memory for the kexec measurement buffer.\n"); return; } + ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, + kexec_segment_size); + if (ret < 0) { + pr_err("%s: Failed to dump IMA measurements. Error:%d.\n", + __func__, ret); + return; + } + kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; @@ -129,6 +172,12 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_buffer_size = kexec_segment_size; image->ima_buffer = kexec_buffer; + /* + * kexec owns kexec_buffer after kexec_add_buffer() is called + * and it will vfree() that buffer. + */ + ima_reset_kexec_file(&ima_kexec_file); + kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } From patchwork Wed Feb 14 15:38:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556699 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id AF68D5CDD1 for ; Wed, 14 Feb 2024 15:38:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; cv=none; b=HXRi4J6WnmWo3oJbed6cH5YXq2MGTImgnC/6GKUDnW7gBF9g/OPnljWxA1cRStfEgxMtWG9KbmxiUiFTmN+Pq7wwSlofzikQj81maPuI20JyYfgY7zPLrHlx45eGGgzI2FCWwMQLneqx1lZZ1Dy8eid5m7TwGKlVcIGdskzAe2E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; c=relaxed/simple; bh=zs/KuCw6ct70oTbY1eooDG1TbcwAYr82QH362DGDqWc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kfEbHuiU+YOimGGSg5r47KKh1lVlDwwouut1LtUcKzxkaIjVAwB2fbVSFew//CkRFRgtLcwy8joQ+dMpnYVlNq4uE1mEglI+vi0yTz+Ng+l6e34vXQwEwW4FvSv0Y22CCQ/bUU2TmY9Hh0Cl3LIPLcw57R0iMCPmoi5j7hiTaYg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=glvPVa/T; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="glvPVa/T" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 15EB520B2002; Wed, 14 Feb 2024 07:38:35 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 15EB520B2002 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925115; bh=LcTxsTc0b07a3hDiMEx1iG60zRqK/2o70VjBYmhDdOM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=glvPVa/TGtuDhEkFVwkKEi0Q1Qkf14az1akcGyEfTWaMQe7uhhAiGP/bQD5a555OC Odh4zVp4Uabf3N3DwFvfEnU3L2C6eXDBgUnW1zLs/EcFJKuxn5m8IA2IWfQJ1Vdoox XqZqLMN+4QZxxMEDAXkVsHo1qRSeDdVyK+p/0osg= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 2/8] kexec: define functions to map and unmap segments Date: Wed, 14 Feb 2024 07:38:21 -0800 Message-Id: <20240214153827.1087657-3-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently, the mechanism to map and unmap segments to the kimage structure is not available to the subsystems outside of kexec. This functionality is needed when IMA is allocating the memory segments during kexec 'load' operation. Implement functions to map and unmap segments to kimage. Implement kimage_map_segment() to enable mapping of IMA buffer source pages to the kimage structure post kexec 'load'. This function, accepting a kimage pointer, an address, and a size, will gather the source pages within the specified address range, create an array of page pointers, and map these to a contiguous virtual address range. The function returns the start of this range if successful, or NULL if unsuccessful. Implement kimage_unmap_segment() for unmapping segments using vunmap(). Relocate 'for_each_kimage_entry()' macro from kexec_core.c to kexec.h for broader accessibility. Signed-off-by: Tushar Sugandhi Reviewed-by: Stefan Berger --- include/linux/kexec.h | 13 ++++++++++ kernel/kexec_core.c | 59 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 400cb6c02176..3145447eb77a 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -486,6 +486,11 @@ static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { static inline void arch_crash_handle_hotplug_event(struct kimage *image) { } #endif +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION) ? \ + boot_phys_to_virt((entry & PAGE_MASK)) : ptr + 1) + int crash_check_update_elfcorehdr(void); #ifndef crash_hotplug_cpu_support @@ -507,6 +512,10 @@ extern bool kexec_file_dbg_print; kexec_file_dbg_print ? KERN_INFO : KERN_DEBUG, \ ##__VA_ARGS__) +extern void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size); +extern void kimage_unmap_segment(void *buffer); + #else /* !CONFIG_KEXEC_CORE */ struct pt_regs; struct task_struct; @@ -514,6 +523,10 @@ static inline void __crash_kexec(struct pt_regs *regs) { } static inline void crash_kexec(struct pt_regs *regs) { } static inline int kexec_should_crash(struct task_struct *p) { return 0; } static inline int kexec_crash_loaded(void) { return 0; } +static inline void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size) +{ return NULL; } +static inline void kimage_unmap_segment(void *buffer) { } #define kexec_in_progress false #endif /* CONFIG_KEXEC_CORE */ diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index d08fc7b5db97..612ad8783bab 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -582,11 +582,6 @@ void kimage_terminate(struct kimage *image) *image->entry = IND_DONE; } -#define for_each_kimage_entry(image, ptr, entry) \ - for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ - ptr = (entry & IND_INDIRECTION) ? \ - boot_phys_to_virt((entry & PAGE_MASK)) : ptr + 1) - static void kimage_free_entry(kimage_entry_t entry) { struct page *page; @@ -909,6 +904,60 @@ int kimage_load_segment(struct kimage *image, return result; } +void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size) +{ + unsigned long eaddr = addr + size; + unsigned long src_page_addr, dest_page_addr; + unsigned int npages; + struct page **src_pages; + int i; + kimage_entry_t *ptr, entry; + void *vaddr = NULL; + + /* + * Collect the source pages and map them in a contiguous VA range. + */ + npages = PFN_UP(eaddr) - PFN_DOWN(addr); + src_pages = kmalloc_array(npages, sizeof(*src_pages), GFP_KERNEL); + if (!src_pages) { + pr_err("%s: Could not allocate ima pages array.\n", __func__); + return NULL; + } + + i = 0; + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) + dest_page_addr = entry & PAGE_MASK; + else if (entry & IND_SOURCE) { + if (dest_page_addr >= addr && dest_page_addr < eaddr) { + src_page_addr = entry & PAGE_MASK; + src_pages[i++] = + virt_to_page(__va(src_page_addr)); + if (i == npages) + break; + dest_page_addr += PAGE_SIZE; + } + } + } + + /* Sanity check. */ + WARN_ON(i < npages); + + vaddr = vmap(src_pages, npages, VM_MAP, PAGE_KERNEL); + kfree(src_pages); + + if (!vaddr) + pr_err("%s: Could not map ima buffer.\n", __func__); + + return vaddr; +} + +void kimage_unmap_segment(void *segment_buffer) +{ + vunmap(segment_buffer); +} + struct kexec_load_limit { /* Mutex protects the limit count. */ struct mutex mutex; From patchwork Wed Feb 14 15:38:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556700 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D482D5A4E1 for ; Wed, 14 Feb 2024 15:38:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; cv=none; b=gvTdchQbITPOaijErGOyfe6adZUfai2VXCIwoREOHbv9c3HPrqjdV46MIrKLRFJDkDLfhuKDh2ZlhllqPYDNEK+pwj7uO5jyzD9quq5gDfA0hxmDni+b9KPZQZ8OKu2dAI0vVhmbkXHItWAclqSCQsfZc0VKNAo78RF2cWt/WVU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; c=relaxed/simple; bh=m4gCm3J16zB805fp6gH1DCk1yV7y2jB5xxHkWeop2Lk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HFgZrqwj/WLrOnUQoIJgBx2prY4wzAen7g0wxZs+o9/18373AvqgjlwzsXzufdHgnC4m40OV6+2kD3djNT4WEK6niG+26CaqNGc0ABQgJY30kvGeaQXKNKIAsFgpm1/I5uGOhGRgAUY45RR4TZseFYk7m1jZ2Ok7gh0FwNy9K/o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=KJ9JAEoj; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="KJ9JAEoj" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 4D8A620B2003; Wed, 14 Feb 2024 07:38:35 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 4D8A620B2003 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925115; bh=7AfuizgJ5ElWTHZgEiEhqrG4GwZkXPqkkrHChqJjnRk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KJ9JAEojMDPIpCYEicWI2Hvf0bgAdnLVRsk0Jo3mrdAf52Wi8BCW/dWl9YKie8pUK 8dbavId1j6BOTH15o/t+X7gfydphHDfI4qTuTBJK9GQ+cc0wY1+/nn6zlwzMwv1TWf iuctBCpIy27AhGJWW34NKDsC7pQDBGQn0dX+Y2ZQ= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 3/8] ima: kexec: skip IMA segment validation after kexec soft reboot Date: Wed, 14 Feb 2024 07:38:22 -0800 Message-Id: <20240214153827.1087657-4-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 kexec_calculate_store_digests() calculates and stores the digest of the segment at kexec_file_load syscall where the IMA segment is also allocated. With this series, the IMA segment will be updated with the measurement log at kexec soft reboot. Therefore, it may fail digest verification in verify_sha256_digest() after kexec soft reboot into the new Kernel. Therefore, the digest calculation, storage, and verification of the IMA segment needs to be skipped. Skip IMA segment from calculating and storing digest in function kexec_calculate_store_digests() so that it is not added to the 'purgatory_sha_regions'. Since verify_sha256_digest() only verifies 'purgatory_sha_regions', no change is needed in verify_sha256_digest() in this context. With this change, the IMA segment is not included in the digest calculation, storage, and verification. Signed-off-by: Tushar Sugandhi --- include/linux/kexec.h | 3 +++ kernel/kexec_file.c | 8 ++++++++ security/integrity/ima/ima_kexec.c | 3 +++ 3 files changed, 14 insertions(+) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 3145447eb77a..73f0dd0e1787 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -358,6 +358,9 @@ struct kimage { phys_addr_t ima_buffer_addr; size_t ima_buffer_size; + + unsigned long ima_segment_index; + bool is_ima_segment_index_set; #endif /* Core ELF header buffer */ diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index bef2f6f2571b..0e3689bfb0bb 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -750,6 +750,14 @@ static int kexec_calculate_store_digests(struct kimage *image) if (ksegment->kbuf == pi->purgatory_buf) continue; + /* + * Skip the segment if ima_segment_index is set and matches + * the current index + */ + if (image->is_ima_segment_index_set && + i == image->ima_segment_index) + continue; + ret = crypto_shash_update(desc, ksegment->kbuf, ksegment->bufsz); if (ret) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index a9cb5e882e2e..ccb072617c2d 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -161,6 +161,7 @@ void ima_add_kexec_buffer(struct kimage *image) kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; + image->is_ima_segment_index_set = false; ret = kexec_add_buffer(&kbuf); if (ret) { pr_err("Error passing over kexec measurement buffer.\n"); @@ -171,6 +172,8 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_buffer_addr = kbuf.mem; image->ima_buffer_size = kexec_segment_size; image->ima_buffer = kexec_buffer; + image->ima_segment_index = image->nr_segments - 1; + image->is_ima_segment_index_set = true; /* * kexec owns kexec_buffer after kexec_add_buffer() is called From patchwork Wed Feb 14 15:38:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556701 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 39EDB53813 for ; Wed, 14 Feb 2024 15:38:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; cv=none; b=Dn44lvUn8ce0CPL342SD7o1g5Q95RKHfiaU+DB2gR8uWipXyYcolIT356vIniPcN0/uLe4tXh0QEUSGEtt9q5NLXR+LxsCfoL6OYXCJtB/BmKexwA2MYNW/ZVc2Yy4OCwlssxs75cESUpFrIdNOMg/DPkoS+IO8CjPwY9Drixv4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925117; c=relaxed/simple; bh=mNicHZYNXVv1kO+WNnxq2LeD3blJAbNwWQK4uojjX9I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DboERXTuJ4PdLjHFf0VbrUg5E6gR83MFW/vvqQWm2EsyAZY5eCgxsdEYEdzwg61eCYY1XhNEAcHRDskslIjiHtnJHaMNixHEp0L6iYa2k80odblKJ1j/L9KTOXFviQrZAgpiwCwgsmdvkR+oYrW6wEf7Q4BKb7kgroFW5STFhKQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=PG5wG3U+; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="PG5wG3U+" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 86AAF20B2004; Wed, 14 Feb 2024 07:38:35 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 86AAF20B2004 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925115; bh=sDdfGVOWH8CiNXECHZEt8PdafbEcCfqmlR/LFkbkEQo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PG5wG3U+GogNtZZnl3J6SLq0IwmIJ6bg77pmcFeZVkO+zBz8FfXVJRxmRUpj2mS8C RX44MoXorvTMidy81kT5mtnWtdgRd0wuJZByojKiobNjiq5MuuCu1bw85IOtj47BNa dnxHOBZTtLaYuwL5b1TdalCmXL7weURSXLKOpsrw= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 4/8] ima: kexec: define functions to copy IMA log at soft boot Date: Wed, 14 Feb 2024 07:38:23 -0800 Message-Id: <20240214153827.1087657-5-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 IMA log is copied to the new Kernel during kexec 'load' using ima_dump_measurement_list(). The log copy at kexec 'load' may result in loss of IMA measurements during kexec soft reboot. It needs to be copied over during kexec 'execute'. Setup the needed infrastructure to move the IMA log copy from kexec 'load' to 'execute'. Define a new IMA hook ima_update_kexec_buffer() as a stub function. It will be used to call ima_dump_measurement_list() during kexec 'execute'. Implement kimage_file_post_load() and ima_kexec_post_load() functions to be invoked after the new Kernel image has been loaded for kexec. ima_kexec_post_load() maps the IMA buffer to a segment in the newly loaded Kernel. It also registers the reboot notifier_block to trigger ima_update_kexec_buffer() at exec 'execute'. Signed-off-by: Tushar Sugandhi Reviewed-by: Stefan Berger --- include/linux/ima.h | 3 ++ kernel/kexec_file.c | 5 ++++ security/integrity/ima/ima_kexec.c | 46 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/include/linux/ima.h b/include/linux/ima.h index 86b57757c7b1..006db20f852d 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -49,6 +49,9 @@ static inline void ima_appraise_parse_cmdline(void) {} #ifdef CONFIG_IMA_KEXEC extern void ima_add_kexec_buffer(struct kimage *image); +extern void ima_kexec_post_load(struct kimage *image); +#else +static inline void ima_kexec_post_load(struct kimage *image) {} #endif #else diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 0e3689bfb0bb..fe59cb7c179d 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -186,6 +186,11 @@ kimage_validate_signature(struct kimage *image) } #endif +void kimage_file_post_load(struct kimage *image) +{ + ima_kexec_post_load(image); +} + /* * In file mode list of segments is prepared by kernel. Copy relevant * data from user space, do error checking, prepare segment list diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index ccb072617c2d..1d4d6c122d82 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -12,10 +12,14 @@ #include #include #include +#include +#include #include "ima.h" #ifdef CONFIG_IMA_KEXEC static struct seq_file ima_kexec_file; +static void *ima_kexec_buffer; +static bool ima_kexec_update_registered; static void ima_reset_kexec_file(struct seq_file *sf) { @@ -184,6 +188,48 @@ void ima_add_kexec_buffer(struct kimage *image) kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } + +/* + * Called during kexec execute so that IMA can update the measurement list. + */ +static int ima_update_kexec_buffer(struct notifier_block *self, + unsigned long action, void *data) +{ + return NOTIFY_OK; +} + +struct notifier_block update_buffer_nb = { + .notifier_call = ima_update_kexec_buffer, +}; + +/* + * Create a mapping for the source pages that contain the IMA buffer + * so we can update it later. + */ +void ima_kexec_post_load(struct kimage *image) +{ + if (ima_kexec_buffer) { + kimage_unmap_segment(ima_kexec_buffer); + ima_kexec_buffer = NULL; + } + + if (!image->ima_buffer_addr) + return; + + ima_kexec_buffer = kimage_map_segment(image, + image->ima_buffer_addr, + image->ima_buffer_size); + if (!ima_kexec_buffer) { + pr_err("%s: Could not map measurements buffer.\n", __func__); + return; + } + + if (!ima_kexec_update_registered) { + register_reboot_notifier(&update_buffer_nb); + ima_kexec_update_registered = true; + } +} + #endif /* IMA_KEXEC */ /* From patchwork Wed Feb 14 15:38:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556704 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 286445D467 for ; Wed, 14 Feb 2024 15:38:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; cv=none; b=ngCmj1fOnBEWxNBRo6WPX0Qn6epyfSHWAw/NgK8RP5YpKMdYXzvMcpe+Uq7fNb0RbxILMxE4JsPQ2JPm2mAy3ts5ijDMLaeXe3DVFV4ILdzdEa+jA/G06spQdTVNXFIRj1931hB7FM/QDHX4plGj3Gz9Fq7+E7DyPRdps4xqnic= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; c=relaxed/simple; bh=2FUau0fiARE/5o6MdioIQEDQ2ej6OVBys6g2KKA9RZ4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Q44cio9wk2Bq4BFL4TtC2UD+giQUoBhuNiDUxX7uJA4jdlBTrqinkHLsi0IKwKt1tDLs+7tCO8/yy6X8J/7tx2gjONZdUYhkPKZlZs1n2xMYs1ebMrcfEdTKN8WzkvESNyRWf1e4/MdvzysBwCughEDxJC2/9/0am/jsegFsbww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=X36gxMzU; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="X36gxMzU" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id BF2F120B2005; Wed, 14 Feb 2024 07:38:35 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com BF2F120B2005 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925115; bh=ZlIccf7Ox9/YKL2es1yXhbAiKARAN1cP73a//eRxN5g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X36gxMzUPc70JtXNRuKZiHxPx50rW99EylvQtZD3RWl+bRX+tsTbjn+LjZ7HUbx0G xhBnsOojVkxrp3OgqaL9nXPxm8cK1wvt4lqGA6+q02kR3zucWoOOn8sUqW+cHQQ+Ji 2yji3N+cGifW/1Y+syvRgjjsR1pm7SpdSbdZiKZU= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 5/8] ima: kexec: move IMA log copy from kexec load to execute Date: Wed, 14 Feb 2024 07:38:24 -0800 Message-Id: <20240214153827.1087657-6-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 ima_dump_measurement_list() is called during kexec 'load', which may result in loss of IMA measurements during kexec soft reboot. It needs to be called during kexec 'execute'. This patch includes the following changes: - Call kimage_file_post_load() from kexec_file_load() syscall only for kexec soft reboot scenarios and not for KEXEC_FILE_ON_CRASH. It will map the IMA segment, and register reboot notifier for the function ima_update_kexec_buffer() which would copy the IMA log at kexec soft reboot. - Make kexec_segment_size variable local static to the file, for it to be accessible both during kexec 'load' and 'execute'. - Move ima_dump_measurement_list() call from ima_add_kexec_buffer() to ima_update_kexec_buffer(). - Remove ima_reset_kexec_file() call from ima_add_kexec_buffer(), now that the buffer is being copied at kexec 'execute', and resetting the file at kexec 'load' will corrupt the buffer. Signed-off-by: Tushar Sugandhi --- kernel/kexec_file.c | 3 ++ security/integrity/ima/ima_kexec.c | 45 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index fe59cb7c179d..2d5df320c34f 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -410,6 +410,9 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, kimage_terminate(image); + if (!(flags & KEXEC_FILE_ON_CRASH)) + kimage_file_post_load(image); + ret = machine_kexec_post_load(image); if (ret) goto out; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 1d4d6c122d82..98fc9b9782a2 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -19,6 +19,7 @@ #ifdef CONFIG_IMA_KEXEC static struct seq_file ima_kexec_file; static void *ima_kexec_buffer; +static size_t kexec_segment_size; static bool ima_kexec_update_registered; static void ima_reset_kexec_file(struct seq_file *sf) @@ -129,7 +130,6 @@ void ima_add_kexec_buffer(struct kimage *image) /* use more understandable variable names than defined in kbuf */ void *kexec_buffer = NULL; size_t kexec_buffer_size; - size_t kexec_segment_size; int ret; /* @@ -154,14 +154,6 @@ void ima_add_kexec_buffer(struct kimage *image) return; } - ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, - kexec_segment_size); - if (ret < 0) { - pr_err("%s: Failed to dump IMA measurements. Error:%d.\n", - __func__, ret); - return; - } - kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; @@ -179,12 +171,6 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_segment_index = image->nr_segments - 1; image->is_ima_segment_index_set = true; - /* - * kexec owns kexec_buffer after kexec_add_buffer() is called - * and it will vfree() that buffer. - */ - ima_reset_kexec_file(&ima_kexec_file); - kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } @@ -195,7 +181,34 @@ void ima_add_kexec_buffer(struct kimage *image) static int ima_update_kexec_buffer(struct notifier_block *self, unsigned long action, void *data) { - return NOTIFY_OK; + void *buf = NULL; + size_t buf_size; + int ret = NOTIFY_OK; + + if (!kexec_in_progress) { + pr_info("%s: No kexec in progress.\n", __func__); + return ret; + } + + if (!ima_kexec_buffer) { + pr_err("%s: Kexec buffer not set.\n", __func__); + return ret; + } + + ret = ima_dump_measurement_list(&buf_size, &buf, + kexec_segment_size); + + if (!buf) { + pr_err("%s: Dump measurements failed. Error:%d\n", + __func__, ret); + goto out; + } + memcpy(ima_kexec_buffer, buf, buf_size); +out: + kimage_unmap_segment(ima_kexec_buffer); + ima_kexec_buffer = NULL; + + return ret; } struct notifier_block update_buffer_nb = { From patchwork Wed Feb 14 15:38:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556703 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 286805D471 for ; Wed, 14 Feb 2024 15:38:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; cv=none; b=QjfM0WpbQgLdSRkU1vXwSSwN+1cUjeOUWMY42GIWPvTL4TGH2PBoQ6DDmHrjVqp3LVvBVCUQ0VQZyF+uALeRvrGK6zlVk1/Aqjl7wLnnAnmq9XX8XFGG8IGdLXwgz6tgoI4IqPjvM5D9Tt7gLDvLYugWkyThpngwycKzDyGGUho= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; c=relaxed/simple; bh=jIHknSlxs+BUMwIIgb4jM+RIhY4agxYER8tHl42HWjk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=CNk6HjDY0TeSvMx1gwxqVE71/ewN6D8MCASerFDcJ57Wq8TmKQn1AhXXTTA82gfp0d66ZmwX9u5UEkBU8jLc2yP//mYfWsixtgDyDxCFOyQfY4mWOSbg+L6sF9/6U8/6JdBE+QHSAIY3yEhdi0aB4LJ2naMD7PULBZbkoWBHhCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=Se9qOXVf; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="Se9qOXVf" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 03D1A20B2006; Wed, 14 Feb 2024 07:38:36 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 03D1A20B2006 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925116; bh=nv8cVzvekpqI1MThlLDGdnsjUpyj1mzzoaYEfh3bbqI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Se9qOXVfkBNkCkLEVMaWKuVYz0npEpoYTgPdPGBLvZAVYE2D94cUzsfGfUTqKmu8e kaLZoxKGkLDmz3fjrriIIVjr2H2VsweKvJu1qoW53r2ocIiQdhbMPb/qzI9e2hOOOi KXYG6HLfpJQam/aDf5BdBbEyrkqXKsz7EZ2SQISI= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 6/8] ima: suspend measurements during buffer copy at kexec execute Date: Wed, 14 Feb 2024 07:38:25 -0800 Message-Id: <20240214153827.1087657-7-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 New measurements added to the IMA log while the log is being copied during the kexec 'execute' may not get copied over. This can cause the measurement log to be out of sync with the TPM PCRs that IMA extends, which could result in breaking the integrity of the measurements after kexec soft reboot. Implement and call the functions ima_measurements_suspend() and ima_measurements_resume() from ima_update_kexec_buffer(). Add a check in the ima_add_template_entry() function not to measure events when 'suspend_ima_measurements' flag is set. This ensures the integrity of the IMA log while it is being copied over to the new Kernel during kexec 'execute'. Reviewed-by: Stefan Berger Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_kexec.c | 7 +++++++ security/integrity/ima/ima_queue.c | 32 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c996..49a6047dd8eb 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -161,6 +161,8 @@ bool ima_template_has_modsig(const struct ima_template_desc *ima_template); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); +void ima_measurements_suspend(void); +void ima_measurements_resume(void); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); void ima_init_template_list(void); diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 98fc9b9782a2..dbeeb7f1355e 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -184,6 +184,7 @@ static int ima_update_kexec_buffer(struct notifier_block *self, void *buf = NULL; size_t buf_size; int ret = NOTIFY_OK; + bool resume = false; if (!kexec_in_progress) { pr_info("%s: No kexec in progress.\n", __func__); @@ -195,12 +196,15 @@ static int ima_update_kexec_buffer(struct notifier_block *self, return ret; } + ima_measurements_suspend(); + ret = ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size); if (!buf) { pr_err("%s: Dump measurements failed. Error:%d\n", __func__, ret); + resume = true; goto out; } memcpy(ima_kexec_buffer, buf, buf_size); @@ -208,6 +212,9 @@ static int ima_update_kexec_buffer(struct notifier_block *self, kimage_unmap_segment(ima_kexec_buffer); ima_kexec_buffer = NULL; + if (resume) + ima_measurements_resume(); + return ret; } diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 532da87ce519..5946a26a2849 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -44,6 +44,11 @@ struct ima_h_table ima_htable = { */ static DEFINE_MUTEX(ima_extend_list_mutex); +/* + * Used internally by the kernel to suspend-resume ima measurements. + */ +static atomic_t suspend_ima_measurements; + /* lookup up the digest value in the hash table, and return the entry */ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, int pcr) @@ -148,6 +153,20 @@ static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) return result; } +void ima_measurements_suspend(void) +{ + mutex_lock(&ima_extend_list_mutex); + atomic_set(&suspend_ima_measurements, 1); + mutex_unlock(&ima_extend_list_mutex); +} + +void ima_measurements_resume(void) +{ + mutex_lock(&ima_extend_list_mutex); + atomic_set(&suspend_ima_measurements, 0); + mutex_unlock(&ima_extend_list_mutex); +} + /* * Add template entry to the measurement list and hash table, and * extend the pcr. @@ -176,6 +195,19 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, } } + /* + * suspend_ima_measurements will be set if the system is + * undergoing kexec soft boot to a new kernel. + * suspending measurements in this short window ensures the + * consistency of the IMA measurement list during copying + * of the kexec buffer. + */ + if (atomic_read(&suspend_ima_measurements)) { + audit_cause = "measurements_suspended"; + audit_info = 0; + goto out; + } + result = ima_add_digest_entry(entry, !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)); if (result < 0) { From patchwork Wed Feb 14 15:38:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556706 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7495C5D489 for ; Wed, 14 Feb 2024 15:38:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; cv=none; b=l7QoJRorLB1PqYFAYdWq0VIh0LD+203wnorOZelMWcB8M1Pqgc7CqH3aUjaiHiki/4DPNn49TSVGT3NmjkcUWVxXvmpYkPD0bDrlzM1I1uHvYjMsxqTtbuCDkQ1Qh5vHxbhU4C0GiFkeGS/vldcHGNAwrfR+f0V5bg0GXFIBObM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; c=relaxed/simple; bh=LFOE4QfHLCoZdqDBOYLliesLUmy3zpjFlCHbtirdXv8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cD6HrcZ4qR93K57F9zk+e/ItbPE8DrTY4z4iccySgl6tUOkQ2EgR2GNOGTOToXfIIi86OCiXfUAG1qngxgCpoxIwuq59zVnt7jlOFU1TU3cI4e0zIGPqyB1On3RpfFb6GO/Obo2ExtYAmyByc30ivL7WFAtqYqkfmmjgCtn3WM8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=YuVe+QzZ; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="YuVe+QzZ" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 3BF4D20B2007; Wed, 14 Feb 2024 07:38:36 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 3BF4D20B2007 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925116; bh=CcMxEE00BfbxjifOUQ879ZZ/YFkEWU5bGzGcN0fH3v0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YuVe+QzZsWcw/2ZScAxIBKZeRZXUJEP0aDYGy/VTZgW1CRMx+XpsRt+2nUDQZT4+B 9opK1/PJ9+bPqAK4CFP7CmQBkLfkCW91yj6oqqBu18v3brCrmVKpvBPBkkzEo69ght 1J+XwhAXIRR/lIFPMwZq7NuSpfeGOas/V3LA33W4= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 7/8] ima: make the kexec extra memory configurable Date: Wed, 14 Feb 2024 07:38:26 -0800 Message-Id: <20240214153827.1087657-8-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The extra memory allocated for carrying the IMA measurement list across kexec is hard-coded as half a PAGE. Make it configurable. Define a Kconfig option, IMA_KEXEC_EXTRA_MEMORY_KB, to configure the extra memory (in kb) to be allocated for IMA measurements added during kexec soft reboot. Ensure the default value of the option is set such that extra half a page of memory for additional measurements is allocated for the additional measurements. Update ima_add_kexec_buffer() function to allocate memory based on the Kconfig option value, rather than the currently hard-coded one. Suggested-by: Stefan Berger Reviewed-by: Stefan Berger Signed-off-by: Tushar Sugandhi --- security/integrity/ima/Kconfig | 9 +++++++++ security/integrity/ima/ima_kexec.c | 15 ++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index b98bfe9efd0c..4c0fc53d6aa3 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -320,4 +320,13 @@ config IMA_DISABLE_HTABLE help This option disables htable to allow measurement of duplicate records. +config IMA_KEXEC_EXTRA_MEMORY_KB + int + depends on IMA_KEXEC + default 0 + help + IMA_KEXEC_EXTRA_MEMORY_KB determines the extra memory to be + allocated (in kb) for IMA measurements added during kexec soft reboot. + If set to the default value, an extra half a page of memory for those + additional measurements will be allocated. endif diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index dbeeb7f1355e..50903d4ce880 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -126,6 +126,7 @@ void ima_add_kexec_buffer(struct kimage *image) .buf_min = 0, .buf_max = ULONG_MAX, .top_down = true }; unsigned long binary_runtime_size; + unsigned long extra_size; /* use more understandable variable names than defined in kbuf */ void *kexec_buffer = NULL; @@ -133,15 +134,19 @@ void ima_add_kexec_buffer(struct kimage *image) int ret; /* - * Reserve an extra half page of memory for additional measurements - * added during the kexec load. + * Reserve extra memory for measurements added during kexec. */ - binary_runtime_size = ima_get_binary_runtime_size(); + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0) + extra_size = PAGE_SIZE / 2; + else + extra_size = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024; + binary_runtime_size = ima_get_binary_runtime_size() + extra_size; + if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) kexec_segment_size = ULONG_MAX; else - kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + - PAGE_SIZE / 2, PAGE_SIZE); + kexec_segment_size = ALIGN(binary_runtime_size, PAGE_SIZE); + if ((kexec_segment_size == ULONG_MAX) || ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { pr_err("Binary measurement list too large.\n"); From patchwork Wed Feb 14 15:38:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13556705 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 607225D47F for ; Wed, 14 Feb 2024 15:38:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; cv=none; b=iF8S7FoWJgGcHKV8ugoi3NmjYU44aXwKuqxfWQPALLO1xKHPDfD/NY3Lg/Vv/DoswwPTwJdsrXX+qaQnYbXJcxEFmYX2ZDjSsfrwH9/GvjJJvWNxtftih+5D+xlCitLadDnuor4oHevR2RluHf9+ip5ptD1zFPS2gXCTVfNUqp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707925118; c=relaxed/simple; bh=Xz/+z5gr8HifANxnPt07MWN2+HV0YL5BY94izlFqzuQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iKTRLyz7tiZZPcyMEQke+tS4b76zPWKdu63KNlFd1XVDWgt7MzTtuUpcH+MUGNNjHysU9HEUXaE7BaG1Nc+mytA8D62ct5l8F5SMOWjsNDSaBgzsYMVdG+X2A2BW2hAlQTPJ03s4ehy82Nd1C++dv/mx2nKSh3B3Yt9YVPFK14g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=CwcSJxEj; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="CwcSJxEj" Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id A72D720B2008; Wed, 14 Feb 2024 07:38:36 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com A72D720B2008 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1707925116; bh=S9UPRKSI8CaypUVC1iW3GsRtiy2NP5QedIfKvKIgtkE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CwcSJxEjSO3aOk2cfjVq2nAr5tWEi4lkIw/dfuT8gZHa3sgbAQQcspcW9byYZ3ZAN /thdUY/PcC43kJZmltp1yb+WU7yKgbXt3XEaPw3lD0a3CM7JMfia0wVo0QfgaFLlSu 4mVXPshTUUh9s1HNZyOwzx9ddDBkkSDZf0msx11A= From: Tushar Sugandhi To: zohar@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, stefanb@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v5 8/8] ima: measure kexec load and exec events as critical data Date: Wed, 14 Feb 2024 07:38:27 -0800 Message-Id: <20240214153827.1087657-9-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> References: <20240214153827.1087657-1-tusharsu@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-integrity@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The amount of memory allocated at kexec load, even with the extra memory allocated, might not be large enough for the entire measurement list. The indeterminate interval between kexec 'load' and 'execute' could exacerbate this problem. Define two new IMA events, 'kexec_load' and 'kexec_execute', to be measured as critical data at kexec 'load' and 'execute' respectively. Report the allocated kexec segment size, IMA binary log size and the runtime measurements count as part of those events. These events, and the values reported through them, serve as markers in the IMA log to verify the IMA events are captured during kexec soft reboot. The presence of a 'kexec_load' event in between the last two 'boot_aggregate' events in the IMA log implies this is a kexec soft reboot, and not a cold-boot. And the absence of 'kexec_execute' event after kexec soft reboot implies missing events in that window which results in inconsistency with TPM PCR quotes, necessitating a cold boot for a successful remote attestation. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima_kexec.c | 34 +++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 50903d4ce880..31495a043959 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -17,6 +17,8 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +#define IMA_KEXEC_EVENT_LEN 256 + static struct seq_file ima_kexec_file; static void *ima_kexec_buffer; static size_t kexec_segment_size; @@ -38,6 +40,10 @@ static void ima_free_kexec_file_buf(struct seq_file *sf) static int ima_alloc_kexec_file_buf(size_t segment_size) { + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; + size_t buf_size; + long len; + /* * kexec 'load' may be called multiple times. * Free and realloc the buffer only if the segment_size is @@ -47,7 +53,7 @@ static int ima_alloc_kexec_file_buf(size_t segment_size) ima_kexec_file.size == segment_size && ima_kexec_file.read_pos == 0 && ima_kexec_file.count == sizeof(struct ima_kexec_hdr)) - return 0; + goto out; ima_free_kexec_file_buf(&ima_kexec_file); @@ -60,6 +66,18 @@ static int ima_alloc_kexec_file_buf(size_t segment_size) ima_kexec_file.read_pos = 0; ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ +out: + buf_size = ima_get_binary_runtime_size(); + len = atomic_long_read(&ima_htable.len); + + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;" + "ima_runtime_measurements_count=%ld;", + segment_size, buf_size, len); + + ima_measure_critical_data("ima_kexec", "kexec_load", ima_kexec_event, + strlen(ima_kexec_event), false, NULL, 0); + return 0; } @@ -186,10 +204,12 @@ void ima_add_kexec_buffer(struct kimage *image) static int ima_update_kexec_buffer(struct notifier_block *self, unsigned long action, void *data) { + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; void *buf = NULL; size_t buf_size; int ret = NOTIFY_OK; bool resume = false; + long len; if (!kexec_in_progress) { pr_info("%s: No kexec in progress.\n", __func__); @@ -201,6 +221,18 @@ static int ima_update_kexec_buffer(struct notifier_block *self, return ret; } + buf_size = ima_get_binary_runtime_size(); + len = atomic_long_read(&ima_htable.len); + + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;" + "ima_runtime_measurements_count=%ld;", + kexec_segment_size, buf_size, len); + + ima_measure_critical_data("ima_kexec", "kexec_execute", + ima_kexec_event, strlen(ima_kexec_event), + false, NULL, 0); + ima_measurements_suspend(); ret = ima_dump_measurement_list(&buf_size, &buf,