From patchwork Fri Nov 29 09:47:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janosch Frank X-Patchwork-Id: 11266813 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D8B26C1 for ; Fri, 29 Nov 2019 10:01:54 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9D8332176D for ; Fri, 29 Nov 2019 10:01:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9D8332176D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.ibm.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:56570 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iad5z-0003QF-AH for patchwork-qemu-devel@patchwork.kernel.org; Fri, 29 Nov 2019 05:01:51 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:47273) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iactD-0002k6-MD for qemu-devel@nongnu.org; Fri, 29 Nov 2019 04:48:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iactA-0003K9-Mw for qemu-devel@nongnu.org; Fri, 29 Nov 2019 04:48:38 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:39890) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iactA-00037S-C6 for qemu-devel@nongnu.org; Fri, 29 Nov 2019 04:48:36 -0500 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id xAT9mWHv137717 for ; Fri, 29 Nov 2019 04:48:33 -0500 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2wjvfg8e5t-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 29 Nov 2019 04:48:33 -0500 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 29 Nov 2019 09:48:30 -0000 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Fri, 29 Nov 2019 09:48:28 -0000 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id xAT9mQtM58392824 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 29 Nov 2019 09:48:26 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7BBBBA4040; Fri, 29 Nov 2019 09:48:26 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6C6D3A4053; Fri, 29 Nov 2019 09:48:24 +0000 (GMT) Received: from localhost.localdomain (unknown [9.145.188.128]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP; Fri, 29 Nov 2019 09:48:24 +0000 (GMT) From: Janosch Frank To: qemu-devel@nongnu.org Subject: [PATCH v2 03/13] s390x: protvirt: Support unpack facility Date: Fri, 29 Nov 2019 04:47:59 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191129094809.26684-1-frankja@linux.ibm.com> References: <20191129094809.26684-1-frankja@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19112909-0016-0000-0000-000002CDD4F7 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19112909-0017-0000-0000-0000332FBEDF Message-Id: <20191129094809.26684-4-frankja@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95,18.0.572 definitions=2019-11-29_02:2019-11-29,2019-11-29 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 mlxlogscore=999 adultscore=0 clxscore=1015 spamscore=0 priorityscore=1501 suspectscore=3 lowpriorityscore=0 phishscore=0 bulkscore=0 malwarescore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-1911290086 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, pmorel@linux.ibm.com, david@redhat.com, cohuck@redhat.com, borntraeger@de.ibm.com, qemu-s390x@nongnu.org, mihajlov@linux.ibm.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" When a guest has saved a ipib of type 5 and call diagnose308 with subcode 10, we have to setup the protected processing environment via Ultravisor calls. The calls are done by KVM and are exposed via an API. The following steps are necessary: 1. Create a VM (register it with the Ultravisor) 2. Create secure CPUs for all of our current cpus 3. Forward the secure header to the Ultravisor (has all information on how to decrypt the image and VM information) 4. Protect image pages from the host and decrypt them 5. Verify the image integrity Only after step 5 a protected VM is allowed to run. Signed-off-by: Janosch Frank --- hw/s390x/Makefile.objs | 1 + hw/s390x/ipl.c | 33 ++++++++ hw/s390x/ipl.h | 2 + hw/s390x/pv.c | 118 ++++++++++++++++++++++++++++ hw/s390x/pv.h | 26 ++++++ hw/s390x/s390-virtio-ccw.c | 26 ++++++ target/s390x/cpu_features_def.inc.h | 1 + 7 files changed, 207 insertions(+) create mode 100644 hw/s390x/pv.c create mode 100644 hw/s390x/pv.h diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index e02ed80b68..a46a1c7894 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -31,6 +31,7 @@ obj-y += tod-qemu.o obj-$(CONFIG_KVM) += tod-kvm.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o obj-$(CONFIG_KVM) += s390-stattrib-kvm.o +obj-$(CONFIG_KVM) += pv.o obj-y += s390-ccw.o obj-y += ap-device.o obj-y += ap-bridge.o diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index a077926f36..50501fcd27 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -33,6 +33,7 @@ #include "qemu/cutils.h" #include "qemu/option.h" #include "exec/exec-all.h" +#include "pv.h" #define KERN_IMAGE_START 0x010000UL #define LINUX_MAGIC_ADDR 0x010008UL @@ -668,6 +669,38 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu) cpu_physical_memory_unmap(addr, len, 1, len); } +int s390_ipl_prepare_pv_header(void) +{ + int rc; + IplParameterBlock *iplb = s390_ipl_get_iplb_secure(); + IPLBlockPV *ipib_pv = &iplb->pv; + void *hdr = g_malloc(ipib_pv->pv_header_len); + + cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr, + ipib_pv->pv_header_len); + rc = s390_pv_set_sec_parms((uint64_t)hdr, + ipib_pv->pv_header_len); + g_free(hdr); + return rc; +} + +int s390_ipl_pv_unpack(void) +{ + int i, rc; + IplParameterBlock *iplb = s390_ipl_get_iplb_secure(); + IPLBlockPV *ipib_pv = &iplb->pv; + + for (i = 0; i < ipib_pv->num_comp; i++) { + rc = s390_pv_unpack(ipib_pv->components[i].addr, + TARGET_PAGE_ALIGN(ipib_pv->components[i].size), + ipib_pv->components[i].tweak_pref); + if (rc) { + return rc; + } + } + return rc; +} + void s390_ipl_prepare_cpu(S390CPU *cpu) { S390IPLState *ipl = get_ipl_device(); diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 7b8a493509..e848602c16 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock; int s390_ipl_set_loadparm(uint8_t *loadparm); int s390_ipl_pv_check_comp(IplParameterBlock *iplb); void s390_ipl_update_diag308(IplParameterBlock *iplb); +int s390_ipl_prepare_pv_header(void); +int s390_ipl_pv_unpack(void); void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); IplParameterBlock *s390_ipl_get_iplb_secure(void); diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c new file mode 100644 index 0000000000..0218070322 --- /dev/null +++ b/hw/s390x/pv.c @@ -0,0 +1,118 @@ +/* + * Secure execution functions + * + * Copyright IBM Corp. 2019 + * Author(s): + * Janosch Frank + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" +#include + +#include + +#include "qemu/error-report.h" +#include "sysemu/kvm.h" +#include "pv.h" + +static int s390_pv_cmd(uint32_t cmd, void *data) +{ + int rc; + struct kvm_pv_cmd pv_cmd = { + .cmd = cmd, + .data = (uint64_t)data, + }; + + rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); + if (rc) { + error_report("KVM PV command failed cmd: %d rc: %d", cmd, rc); + exit(1); + } + return rc; +} + +static int s390_pv_cmd_vcpu(CPUState *cs, uint32_t cmd, void *data) +{ + int rc; + struct kvm_pv_cmd pv_cmd = { + .cmd = cmd, + .data = (uint64_t)data, + }; + + rc = kvm_vcpu_ioctl(cs, KVM_S390_PV_COMMAND_VCPU, &pv_cmd); + if (rc) { + error_report("KVM PV VCPU command failed cmd: %d rc: %d", cmd, rc); + exit(1); + } + return rc; +} + +int s390_pv_vm_create(void) +{ + return s390_pv_cmd(KVM_PV_VM_CREATE, NULL); +} + +int s390_pv_vm_destroy(void) +{ + return s390_pv_cmd(KVM_PV_VM_DESTROY, NULL); +} + +int s390_pv_vcpu_create(CPUState *cs) +{ + return s390_pv_cmd_vcpu(cs, KVM_PV_VCPU_CREATE, NULL); +} + +int s390_pv_vcpu_destroy(CPUState *cs) +{ + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + int rc; + + rc = s390_pv_cmd_vcpu(cs, KVM_PV_VCPU_DESTROY, NULL); + if (!rc) { + env->pv = false; + } + return rc; +} + +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) +{ + struct kvm_s390_pv_sec_parm args = { + .origin = origin, + .length = length, + }; + + return s390_pv_cmd(KVM_PV_VM_SET_SEC_PARMS, &args); +} + +/* + * Called for each component in the SE type IPL parameter block 0. + */ +int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) +{ + struct kvm_s390_pv_unp args = { + .addr = addr, + .size = size, + .tweak = tweak, + }; + + return s390_pv_cmd(KVM_PV_VM_UNPACK, &args); +} + +int s390_pv_perf_clear_reset(void) +{ + return s390_pv_cmd(KVM_PV_VM_PERF_CLEAR_RESET, NULL); +} + +int s390_pv_verify(void) +{ + return s390_pv_cmd(KVM_PV_VM_VERIFY, NULL); +} + +int s390_pv_unshare(void) +{ + return s390_pv_cmd(KVM_PV_VM_UNSHARE, NULL); +} diff --git a/hw/s390x/pv.h b/hw/s390x/pv.h new file mode 100644 index 0000000000..eb074e4bc9 --- /dev/null +++ b/hw/s390x/pv.h @@ -0,0 +1,26 @@ +/* + * Protected Virtualization header + * + * Copyright IBM Corp. 2019 + * Author(s): + * Janosch Frank + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390_PV_H +#define HW_S390_PV_H + +int s390_pv_vm_create(void); +int s390_pv_vm_destroy(void); +int s390_pv_vcpu_destroy(CPUState *cs); +int s390_pv_vcpu_create(CPUState *cs); +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length); +int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak); +int s390_pv_perf_clear_reset(void); +int s390_pv_verify(void); +int s390_pv_unshare(void); + +#endif /* HW_S390_PV_H */ diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index c1d1440272..f9481ccace 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -41,6 +41,7 @@ #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" #include "sysemu/sysemu.h" +#include "hw/s390x/pv.h" S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { @@ -322,6 +323,7 @@ static void s390_machine_reset(MachineState *machine) { enum s390_reset reset_type; CPUState *cs, *t; + S390CPU *cpu; /* get the reset parameters, reset them once done */ s390_ipl_get_reset_request(&cs, &reset_type); @@ -329,6 +331,8 @@ static void s390_machine_reset(MachineState *machine) /* all CPUs are paused and synchronized at this point */ s390_cmma_reset(); + cpu = S390_CPU(cs); + switch (reset_type) { case S390_RESET_EXTERNAL: case S390_RESET_REIPL: @@ -357,6 +361,28 @@ static void s390_machine_reset(MachineState *machine) run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL); run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); break; + case S390_RESET_PV: /* Subcode 10 */ + subsystem_reset(); + s390_crypto_reset(); + + CPU_FOREACH(t) { + run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); + } + + /* Create SE VM */ + s390_pv_vm_create(); + CPU_FOREACH(t) { + s390_pv_vcpu_create(t); + } + + /* Set SE header and unpack */ + s390_ipl_prepare_pv_header(); + /* Decrypt image */ + s390_ipl_pv_unpack(); + /* Verify integrity */ + s390_pv_verify(); + s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); + break; default: g_assert_not_reached(); } diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h index 31dff0d84e..60db28351d 100644 --- a/target/s390x/cpu_features_def.inc.h +++ b/target/s390x/cpu_features_def.inc.h @@ -107,6 +107,7 @@ DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility ( DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility") DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)") DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility") +DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility") /* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */ DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")