Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp328279imm; Fri, 31 Aug 2018 01:22:35 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZBACOoqDgUX32U88RlzPbZGWmNTGjxOxxOvThp/ljXZMKa9rW7rlmn+/b7K9OcqVJmiLMF X-Received: by 2002:a17:902:246a:: with SMTP id m39-v6mr14046534plg.57.1535703754966; Fri, 31 Aug 2018 01:22:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1535703754; cv=none; d=google.com; s=arc-20160816; b=AhXQi8OniQRn3jvOZA1om3j98mE9oGV0aD1Fc4aspFVqVuOLstJhXZJqX8k44j5uu9 5bM5HqWpKNLUpy7RUU6sqaveQbqVajsVLXqOlrHBzQAV+hduCBAvMG3BT5+PmiZD+NxT +02iQ2+fREAWQgKY6d/t0Iv4gB/M7H6XEWY6E5Suv4j0mkvmK0JOPliKEYc7SWll2MeE tNi4tZIH0GlmNWMd9EbFGk1EZxO+d7JupThsz2LFUH3OUEg0WOJPOURf/jlwBcB0rPKd PJ3xEGQpRPObSXUJRsviiiElC7wdXwaxZHC+sJ3lLE9zaQHMd5uN+F2d2maizXzOMPXh utAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=Z2Ah1iDloG8pwtDHjXpN7yxsSr0sfWdDV2gbgl9p3qQ=; b=WZKwEwyQYNNyhDZ6J/que2PlXpofLDr4iNVrrP7cGY2I5EKY7C7f6ZLCps6IXaA1CE BE13wc+6FB4c047fr4vwK2aozMqhNk6O5W1Uv3tcLNTnGJ0DkL1RH4/guKuLBG0fmAo6 5+Dl/dUFfNytvODnIFiKIMnsMn0Y9+OTxDz3pKIkWVSvLfKPiibAEnzyvEzrRqZ+IXoC F9IbQofC154/S2NItz3UzneHyNrPAfcqS6Snnpe3Nfer8TUjh6S33fZfJsDL7pMeDGwA cl1YgtoMsJL4/1znadJgAy6fFl4yv4/yZNYcXpVYqoTfj3gpFQWzckrUIvmDuDGYcQLC mvag== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y1-v6si8876147pgo.644.2018.08.31.01.22.20; Fri, 31 Aug 2018 01:22:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727801AbeHaM0y (ORCPT + 99 others); Fri, 31 Aug 2018 08:26:54 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42108 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727229AbeHaM0y (ORCPT ); Fri, 31 Aug 2018 08:26:54 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 42B6E4077D73; Fri, 31 Aug 2018 08:20:36 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-12-30.pek2.redhat.com [10.72.12.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id E1FDD10D178A; Fri, 31 Aug 2018 08:20:27 +0000 (UTC) From: Lianbo Jiang To: linux-kernel@vger.kernel.org Cc: mingo@redhat.com, tglx@linutronix.de, hpa@zytor.com, ebiederm@xmission.com, joro@8bytes.org, thomas.lendacky@amd.com, dyoung@redhat.com, kexec@lists.infradead.org, iommu@lists.linux-foundation.org, bhe@redhat.com Subject: [PATCH 5/5 V6] kdump/vmcore: support encrypted old memory with SME enabled Date: Fri, 31 Aug 2018 16:19:30 +0800 Message-Id: <20180831081930.31561-6-lijiang@redhat.com> In-Reply-To: <20180831081930.31561-1-lijiang@redhat.com> References: <20180831081930.31561-1-lijiang@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Fri, 31 Aug 2018 08:20:36 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Fri, 31 Aug 2018 08:20:36 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lijiang@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In kdump kernel, we need to dump the old memory into vmcore file,if SME is enabled in the first kernel, we have to remap the old memory with the memory encryption mask, which will be automatically decrypted when we read from DRAM. For SME kdump, there are two cases that doesn't support: ---------------------------------------------- | first-kernel | second-kernel | kdump support | | (mem_encrypt=on|off) | (yes|no) | |--------------+---------------+---------------| | on | on | yes | | off | off | yes | | on | off | no | | off | on | no | |______________|_______________|_______________| 1. SME is enabled in the first kernel, but SME is disabled in kdump kernel In this case, because the old memory is encrypted, we can't decrypt the old memory. 2. SME is disabled in the first kernel, but SME is enabled in kdump kernel On the one hand, the old memory is unencrypted, the old memory can be dumped as usual, we don't need to enable SME in kdump kernel; On the other hand, it will increase the complexity of the code, we will have to consider how to pass the SME flag from the first kernel to the kdump kernel, it is really too expensive to do this. This patches are only for SME kdump, the patches don't support SEV kdump. Signed-off-by: Lianbo Jiang --- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/crash_dump_encrypt.c | 53 ++++++++++++++++++++++++++++ fs/proc/vmcore.c | 21 +++++++---- include/linux/crash_dump.h | 12 +++++++ 4 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 arch/x86/kernel/crash_dump_encrypt.c diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 8824d01c0c35..dfbeae0e35ce 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_KEXEC_CORE) += machine_kexec_$(BITS).o obj-$(CONFIG_KEXEC_CORE) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_KEXEC_FILE) += kexec-bzimage64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o +obj-$(CONFIG_AMD_MEM_ENCRYPT) += crash_dump_encrypt.o obj-y += kprobes/ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o diff --git a/arch/x86/kernel/crash_dump_encrypt.c b/arch/x86/kernel/crash_dump_encrypt.c new file mode 100644 index 000000000000..e1b1a577f197 --- /dev/null +++ b/arch/x86/kernel/crash_dump_encrypt.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Memory preserving reboot related code. + * + * Created by: Lianbo Jiang (lijiang@redhat.com) + * Copyright (C) RedHat Corporation, 2018. All rights reserved + */ + +#include +#include +#include +#include + +/** + * copy_oldmem_page_encrypted - copy one page from "oldmem encrypted" + * @pfn: page frame number to be copied + * @buf: target memory address for the copy; this can be in kernel address + * space or user address space (see @userbuf) + * @csize: number of bytes to copy + * @offset: offset in bytes into the page (based on pfn) to begin the copy + * @userbuf: if set, @buf is in user address space, use copy_to_user(), + * otherwise @buf is in kernel address space, use memcpy(). + * + * Copy a page from "oldmem encrypted". For this page, there is no pte + * mapped in the current kernel. We stitch up a pte, similar to + * kmap_atomic. + */ + +ssize_t copy_oldmem_page_encrypted(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + + vaddr = (__force void *)ioremap_encrypted(pfn << PAGE_SHIFT, + PAGE_SIZE); + if (!vaddr) + return -ENOMEM; + + if (userbuf) { + if (copy_to_user((void __user *)buf, vaddr + offset, csize)) { + iounmap((void __iomem *)vaddr); + return -EFAULT; + } + } else + memcpy(buf, vaddr + offset, csize); + + set_iounmap_nonlazy(); + iounmap((void __iomem *)vaddr); + return csize; +} diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index cbde728f8ac6..3065c8bada6a 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include "internal.h" /* List representing chunks of contiguous memory areas and their offsets in @@ -98,7 +101,8 @@ static int pfn_is_ram(unsigned long pfn) /* Reads a page from the oldmem device from given offset. */ static ssize_t read_from_oldmem(char *buf, size_t count, - u64 *ppos, int userbuf) + u64 *ppos, int userbuf, + bool encrypted) { unsigned long pfn, offset; size_t nr_bytes; @@ -120,8 +124,11 @@ static ssize_t read_from_oldmem(char *buf, size_t count, if (pfn_is_ram(pfn) == 0) memset(buf, 0, nr_bytes); else { - tmp = copy_oldmem_page(pfn, buf, nr_bytes, - offset, userbuf); + tmp = encrypted ? copy_oldmem_page_encrypted(pfn, + buf, nr_bytes, offset, userbuf) + : copy_oldmem_page(pfn, buf, nr_bytes, + offset, userbuf); + if (tmp < 0) return tmp; } @@ -155,7 +162,7 @@ void __weak elfcorehdr_free(unsigned long long addr) */ ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos) { - return read_from_oldmem(buf, count, ppos, 0); + return read_from_oldmem(buf, count, ppos, 0, false); } /* @@ -163,7 +170,7 @@ ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos) */ ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos) { - return read_from_oldmem(buf, count, ppos, 0); + return read_from_oldmem(buf, count, ppos, 0, sme_active()); } /* @@ -173,6 +180,7 @@ int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { + prot = pgprot_encrypted(prot); return remap_pfn_range(vma, from, pfn, size, prot); } @@ -351,7 +359,8 @@ static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos, m->offset + m->size - *fpos, buflen); start = m->paddr + *fpos - m->offset; - tmp = read_from_oldmem(buffer, tsz, &start, userbuf); + tmp = read_from_oldmem(buffer, tsz, &start, userbuf, + sme_active()); if (tmp < 0) return tmp; buflen -= tsz; diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h index 3e4ba9d753c8..a7e7be8b0502 100644 --- a/include/linux/crash_dump.h +++ b/include/linux/crash_dump.h @@ -26,6 +26,18 @@ extern int remap_oldmem_pfn_range(struct vm_area_struct *vma, extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, unsigned long, int); +#ifdef CONFIG_AMD_MEM_ENCRYPT +extern ssize_t copy_oldmem_page_encrypted(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, + int userbuf); +#else +static inline +ssize_t copy_oldmem_page_encrypted(unsigned long pfn, char *buf, size_t csize, + unsigned long offset, int userbuf) +{ + return 0; +} +#endif void vmcore_cleanup(void); /* Architecture code defines this if there are other possible ELF -- 2.17.1