From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrew Jones Subject: Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering Date: Wed, 3 Apr 2019 21:17:03 +0200 Message-ID: <20190403191703.lakl5wf4yqspure4@kamzik.brq.redhat.com> References: <1553864452-15080-1-git-send-email-Dave.Martin@arm.com> <1553864452-15080-12-git-send-email-Dave.Martin@arm.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Content-Disposition: inline In-Reply-To: <1553864452-15080-12-git-send-email-Dave.Martin@arm.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Dave Martin Cc: Okamoto Takayuki , Christoffer Dall , Ard Biesheuvel , Marc Zyngier , Catalin Marinas , Will Deacon , Zhang Lei , Julien Grall , kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org List-Id: kvmarm@lists.cs.columbia.edu On Fri, Mar 29, 2019 at 01:00:36PM +0000, Dave Martin wrote: > Some optional features of the Arm architecture add new system > registers that are not present in the base architecture. > > Where these features are optional for the guest, the visibility of > these registers may need to depend on some runtime configuration, > such as a flag passed to KVM_ARM_VCPU_INIT. > > For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE > is not enabled for the guest, even though these registers may be > present in the hardware and visible to the host at EL2. > > Adding special-case checks all over the place for individual > registers is going to get messy as the number of conditionally- > visible registers grows. > > In order to help solve this problem, this patch adds a new sysreg > method visibility() that can be used to hook in any needed runtime > visibility checks. This method can currently return > REG_HIDDEN_USER to inhibit enumeration and ioctl access to the > register for userspace, and REG_HIDDEN_GUEST to inhibit runtime > access by the guest using MSR/MRS. Wrappers are added to allow > these flags to be conveniently queried. > > This approach allows a conditionally modified view of individual > system registers such as the CPU ID registers, in addition to > completely hiding register where appropriate. > > Signed-off-by: Dave Martin > Tested-by: zhang.lei > > --- > > Changes since v5: > > * Rename the visibility override flags, add some comments, and rename/ > introduce helpers to make the purpose of this code clearer. > --- > arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++--- > arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++ > 2 files changed, 46 insertions(+), 3 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index a5d14b5..c86a7b0 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu, > { > trace_kvm_sys_access(*vcpu_pc(vcpu), params, r); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_guest(vcpu, r)) { > + kvm_inject_undefined(vcpu); > + return; > + } > + > /* > * Not having an accessor means that we have configured a trap > * that we don't know how to handle. This certainly qualifies > @@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (!r) > return get_invariant_sys_reg(reg->id, uaddr); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_user(vcpu, r)) > + return -ENOENT; > + > if (r->get_user) > return (r->get_user)(vcpu, r, reg, uaddr); > > @@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (!r) > return set_invariant_sys_reg(reg->id, uaddr); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_user(vcpu, r)) > + return -ENOENT; > + > if (r->set_user) > return (r->set_user)(vcpu, r, reg, uaddr); > > @@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind) > return true; > } > > -static int walk_one_sys_reg(const struct sys_reg_desc *rd, > +static int walk_one_sys_reg(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > u64 __user **uind, > unsigned int *total) > { > @@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd, > if (!(rd->reg || rd->get_user)) > return 0; > > + if (sysreg_hidden_from_user(vcpu, rd)) > + return 0; > + > if (!copy_reg_to_user(rd, uind)) > return -EFAULT; > > @@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) > int cmp = cmp_sys_reg(i1, i2); > /* target-specific overrides generic entry. */ > if (cmp <= 0) > - err = walk_one_sys_reg(i1, &uind, &total); > + err = walk_one_sys_reg(vcpu, i1, &uind, &total); > else > - err = walk_one_sys_reg(i2, &uind, &total); > + err = walk_one_sys_reg(vcpu, i2, &uind, &total); > > if (err) > return err; > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h > index 3b1bc7f..2be9950 100644 > --- a/arch/arm64/kvm/sys_regs.h > +++ b/arch/arm64/kvm/sys_regs.h > @@ -64,8 +64,15 @@ struct sys_reg_desc { > const struct kvm_one_reg *reg, void __user *uaddr); > int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > const struct kvm_one_reg *reg, void __user *uaddr); > + > + /* Return mask of REG_* runtime visibility overrides */ > + unsigned int (*visibility)(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd); > }; > > +#define REG_HIDDEN_USER (1 << 0) /* hidden from userspace ioctls */ > +#define REG_HIDDEN_GUEST (1 << 1) /* hidden from guest */ > + > static inline void print_sys_reg_instr(const struct sys_reg_params *p) > { > /* Look, we even formatted it for you to paste into the table! */ > @@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r > __vcpu_sys_reg(vcpu, r->reg) = r->val; > } > > +static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *r) > +{ > + if (likely(!r->visibility)) > + return false; > + > + return r->visibility(vcpu, r) & REG_HIDDEN_GUEST; > +} > + > +static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *r) > +{ > + if (likely(!r->visibility)) > + return false; > + > + return r->visibility(vcpu, r) & REG_HIDDEN_USER; > +} > + > static inline int cmp_sys_reg(const struct sys_reg_desc *i1, > const struct sys_reg_desc *i2) > { > -- > 2.1.4 > Reviewed-by: Andrew Jones From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.0 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_NEOMUTT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 26D7DC4360F for ; Wed, 3 Apr 2019 19:17:18 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 DDB1420882 for ; Wed, 3 Apr 2019 19:17:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="WCpEWIjS" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DDB1420882 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References: Message-ID:Subject:To:From:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Ea/K8SLS3Fcn04t+xpycmLynB+RaYPynxJUUZRsHN6M=; b=WCpEWIjSJaQOS5 UuzMndA0lvLrAduFcJkhz1xFsp0BSgevgEkSNysnaUNE4C+GObuGlf2RnPctqAKXLxdQYRmNcmF2Q 77IEpEV1/yZdKD8ck5zd/vSeqmslJIc7+3dUtMe0ucOwX6LAUYtp15RY3XfZs3+i8wxSpf53QetpD V5ZuxPAsxs6g3xo6Z4uwI4ytn7IUGtNK0cPiyaiYg4LuKH5sS4hZFD6jktPjwCU1oFoI/LHnRQ5yM K7QFhWH7Et5+oPD3GiDJ8I3SczVbHziP4K3QJ4QBZ98Mkj8zFKzUt/aSLsYl+PlRtXPAyirDkloGZ czECariGYD5LWgdfWqtQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hBlNo-00061d-2Z; Wed, 03 Apr 2019 19:17:12 +0000 Received: from mx1.redhat.com ([209.132.183.28]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hBlNk-00061J-Fk for linux-arm-kernel@lists.infradead.org; Wed, 03 Apr 2019 19:17:10 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 092B92C9724; Wed, 3 Apr 2019 19:17:08 +0000 (UTC) Received: from kamzik.brq.redhat.com (unknown [10.43.2.160]) by smtp.corp.redhat.com (Postfix) with ESMTPS id AA0CA62A14; Wed, 3 Apr 2019 19:17:05 +0000 (UTC) Date: Wed, 3 Apr 2019 21:17:03 +0200 From: Andrew Jones To: Dave Martin Subject: Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering Message-ID: <20190403191703.lakl5wf4yqspure4@kamzik.brq.redhat.com> References: <1553864452-15080-1-git-send-email-Dave.Martin@arm.com> <1553864452-15080-12-git-send-email-Dave.Martin@arm.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1553864452-15080-12-git-send-email-Dave.Martin@arm.com> User-Agent: NeoMutt/20180716 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Wed, 03 Apr 2019 19:17:08 +0000 (UTC) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190403_121708_568344_4AC2A690 X-CRM114-Status: GOOD ( 31.40 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Okamoto Takayuki , Christoffer Dall , Ard Biesheuvel , Marc Zyngier , Catalin Marinas , Will Deacon , Zhang Lei , Julien Grall , kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Fri, Mar 29, 2019 at 01:00:36PM +0000, Dave Martin wrote: > Some optional features of the Arm architecture add new system > registers that are not present in the base architecture. > > Where these features are optional for the guest, the visibility of > these registers may need to depend on some runtime configuration, > such as a flag passed to KVM_ARM_VCPU_INIT. > > For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE > is not enabled for the guest, even though these registers may be > present in the hardware and visible to the host at EL2. > > Adding special-case checks all over the place for individual > registers is going to get messy as the number of conditionally- > visible registers grows. > > In order to help solve this problem, this patch adds a new sysreg > method visibility() that can be used to hook in any needed runtime > visibility checks. This method can currently return > REG_HIDDEN_USER to inhibit enumeration and ioctl access to the > register for userspace, and REG_HIDDEN_GUEST to inhibit runtime > access by the guest using MSR/MRS. Wrappers are added to allow > these flags to be conveniently queried. > > This approach allows a conditionally modified view of individual > system registers such as the CPU ID registers, in addition to > completely hiding register where appropriate. > > Signed-off-by: Dave Martin > Tested-by: zhang.lei > > --- > > Changes since v5: > > * Rename the visibility override flags, add some comments, and rename/ > introduce helpers to make the purpose of this code clearer. > --- > arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++--- > arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++ > 2 files changed, 46 insertions(+), 3 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index a5d14b5..c86a7b0 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu, > { > trace_kvm_sys_access(*vcpu_pc(vcpu), params, r); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_guest(vcpu, r)) { > + kvm_inject_undefined(vcpu); > + return; > + } > + > /* > * Not having an accessor means that we have configured a trap > * that we don't know how to handle. This certainly qualifies > @@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (!r) > return get_invariant_sys_reg(reg->id, uaddr); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_user(vcpu, r)) > + return -ENOENT; > + > if (r->get_user) > return (r->get_user)(vcpu, r, reg, uaddr); > > @@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (!r) > return set_invariant_sys_reg(reg->id, uaddr); > > + /* Check for regs disabled by runtime config */ > + if (sysreg_hidden_from_user(vcpu, r)) > + return -ENOENT; > + > if (r->set_user) > return (r->set_user)(vcpu, r, reg, uaddr); > > @@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind) > return true; > } > > -static int walk_one_sys_reg(const struct sys_reg_desc *rd, > +static int walk_one_sys_reg(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > u64 __user **uind, > unsigned int *total) > { > @@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd, > if (!(rd->reg || rd->get_user)) > return 0; > > + if (sysreg_hidden_from_user(vcpu, rd)) > + return 0; > + > if (!copy_reg_to_user(rd, uind)) > return -EFAULT; > > @@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) > int cmp = cmp_sys_reg(i1, i2); > /* target-specific overrides generic entry. */ > if (cmp <= 0) > - err = walk_one_sys_reg(i1, &uind, &total); > + err = walk_one_sys_reg(vcpu, i1, &uind, &total); > else > - err = walk_one_sys_reg(i2, &uind, &total); > + err = walk_one_sys_reg(vcpu, i2, &uind, &total); > > if (err) > return err; > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h > index 3b1bc7f..2be9950 100644 > --- a/arch/arm64/kvm/sys_regs.h > +++ b/arch/arm64/kvm/sys_regs.h > @@ -64,8 +64,15 @@ struct sys_reg_desc { > const struct kvm_one_reg *reg, void __user *uaddr); > int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > const struct kvm_one_reg *reg, void __user *uaddr); > + > + /* Return mask of REG_* runtime visibility overrides */ > + unsigned int (*visibility)(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd); > }; > > +#define REG_HIDDEN_USER (1 << 0) /* hidden from userspace ioctls */ > +#define REG_HIDDEN_GUEST (1 << 1) /* hidden from guest */ > + > static inline void print_sys_reg_instr(const struct sys_reg_params *p) > { > /* Look, we even formatted it for you to paste into the table! */ > @@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r > __vcpu_sys_reg(vcpu, r->reg) = r->val; > } > > +static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *r) > +{ > + if (likely(!r->visibility)) > + return false; > + > + return r->visibility(vcpu, r) & REG_HIDDEN_GUEST; > +} > + > +static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *r) > +{ > + if (likely(!r->visibility)) > + return false; > + > + return r->visibility(vcpu, r) & REG_HIDDEN_USER; > +} > + > static inline int cmp_sys_reg(const struct sys_reg_desc *i1, > const struct sys_reg_desc *i2) > { > -- > 2.1.4 > Reviewed-by: Andrew Jones _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel