From patchwork Wed Dec 12 20:17:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 153590 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp6490ljp; Wed, 12 Dec 2018 12:17:57 -0800 (PST) X-Google-Smtp-Source: AFSGD/XJYbu142/NjjUj13sb/OT/TkiJejomRBWhp72fjm1JQgy6jaNgKSSi+8+taGnMdI+eSdFm X-Received: by 2002:a62:435a:: with SMTP id q87mr21137304pfa.109.1544645877518; Wed, 12 Dec 2018 12:17:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544645877; cv=none; d=google.com; s=arc-20160816; b=QVDNypDbgwwGDORAG59eaZ+RnVxLp1PtpxoIdMyiWzxetMx/YuEGyogv5+6wpYWSll 2/ZCG7BHqV08PXC4Kqaa9hj5YvqZOBPT6nDzB88IjLwZa1y2HkeimzpqLXW93ed9S3id hajeZLq34lW6yDMuT6L+c30qlnRG1CzdaYxHh8TJcg1Qw68xPJYdGzrSwq2r51c/dRQu nNEA4Dd0FrdDvTRWzaVCrhK2YQkcwBx3m4fFcAKOOZfIGHKN4L/bReDDgOc3PREtV1ep KPCnnQjlM3qQz34L6V3XSX6LD7XBCgcS3PFJqoXtfV+rQ7f2nflO9IIWUKiz4MHxZUUC royg== 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; bh=6we9yJecNqoIQsSUJPYY1E4yMYsuNZFODwOaJpYIhy8=; b=pJP321IFmnRTn4CCo+/efWzn9XjaN91+XT8BEZHLYUAKgdhN6vYS1vgNWq81RQgB+g 6aDHF8Bq+7lDayk4wvftOzhjIY2dbD4z5QSinr8kGxrBBPotHIYxqJq1RDGfLIorMz5Q sAYkh3wP3A2W2AYKfc6z5Fu852O+GmPKLMr1EjkGK6E+BQMeFDNEwstgsZ+CODNwOFMp rVQBfE5P0lDeK85SWmDhW7fF/94Cy6SJk3elJ7LmFD7wkR5FLt1y4y6gyomiFhdNHVQl VtvmOov3lY0idD/EqE8JLEJy6o2RYFG9J5vfL1IxWFfNszIJblO9qLp5VlNqgMO0NC3L 8bXg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c10si15378865pll.271.2018.12.12.12.17.57; Wed, 12 Dec 2018 12:17:57 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of stable-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 stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726294AbeLLUR4 (ORCPT + 15 others); Wed, 12 Dec 2018 15:17:56 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:48394 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727088AbeLLUR4 (ORCPT ); Wed, 12 Dec 2018 15:17:56 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 5855FA78; Wed, 12 Dec 2018 12:17:56 -0800 (PST) Received: from e103592.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 486A83F59C; Wed, 12 Dec 2018 12:17:55 -0800 (PST) From: Dave Martin To: kvmarm@lists.cs.columbia.edu Cc: Marc Zyngier , Christoffer Dall , Peter Maydell , linux-arm-kernel@lists.infradead.org, stable@vger.kernel.org Subject: [PATCH v2 1/2] KVM: arm64: Filter out invalid core register IDs in KVM_GET_REG_LIST Date: Wed, 12 Dec 2018 20:17:03 +0000 Message-Id: <1544645824-16461-2-git-send-email-Dave.Martin@arm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1544645824-16461-1-git-send-email-Dave.Martin@arm.com> References: <1544645824-16461-1-git-send-email-Dave.Martin@arm.com> Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org Since commit d26c25a9d19b ("arm64: KVM: Tighten guest core register access from userspace"), KVM_{GET,SET}_ONE_REG rejects register IDs that do not correspond to a single underlying architectural register. KVM_GET_REG_LIST was not changed to match however: instead, it simply yields a list of 32-bit register IDs that together cover the whole kvm_regs struct. This means that if userspace tries to use the resulting list of IDs directly to drive calls to KVM_*_ONE_REG, some of those calls will now fail. This was not the intention. Instead, iterating KVM_*_ONE_REG over the list of IDs returned by KVM_GET_REG_LIST should be guaranteed to work. This patch fixes the problem by splitting validate_core_reg_id() into a backend core_reg_size_from_offset() which does all of the work except for checking that the size field in the register ID matches, and kvm_arm_copy_reg_indices() and num_core_regs() are converted to use this to enumerate the valid offsets. kvm_arm_copy_reg_indices() now also sets the register ID size field appropriately based on the value returned, so the register ID supplied to userspace is fully qualified for use with the register access ioctls. Cc: stable@vger.kernel.org Fixes: d26c25a9d19b ("arm64: KVM: Tighten guest core register access from userspace") Signed-off-by: Dave Martin --- arch/arm64/kvm/guest.c | 61 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) -- 2.1.4 diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index dd436a5..cbe423b 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -57,9 +57,8 @@ static u64 core_reg_offset_from_id(u64 id) return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); } -static int validate_core_offset(const struct kvm_one_reg *reg) +static int core_reg_size_from_offset(u64 off) { - u64 off = core_reg_offset_from_id(reg->id); int size; switch (off) { @@ -89,8 +88,21 @@ static int validate_core_offset(const struct kvm_one_reg *reg) return -EINVAL; } - if (KVM_REG_SIZE(reg->id) == size && - IS_ALIGNED(off, size / sizeof(__u32))) + if (IS_ALIGNED(off, size / sizeof(__u32))) + return size; + + return -EINVAL; +} + +static int validate_core_offset(const struct kvm_one_reg *reg) +{ + u64 off = core_reg_offset_from_id(reg->id); + int size = core_reg_size_from_offset(off); + + if (size < 0) + return -EINVAL; + + if (KVM_REG_SIZE(reg->id) == size) return 0; return -EINVAL; @@ -195,7 +207,19 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) static unsigned long num_core_regs(void) { - return sizeof(struct kvm_regs) / sizeof(__u32); + unsigned int i; + int n = 0; + + for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) { + int size = core_reg_size_from_offset(i); + + if (size < 0) + continue; + + n++; + } + + return n; } /** @@ -270,11 +294,34 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) { unsigned int i; - const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE; int ret; for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) { - if (put_user(core_reg | i, uindices)) + u64 reg = KVM_REG_ARM64 | KVM_REG_ARM_CORE | i; + int size = core_reg_size_from_offset(i); + + if (size < 0) + continue; + + switch (size) { + case sizeof(__u32): + reg |= KVM_REG_SIZE_U32; + break; + + case sizeof(__u64): + reg |= KVM_REG_SIZE_U64; + break; + + case sizeof(__uint128_t): + reg |= KVM_REG_SIZE_U128; + break; + + default: + WARN_ON(1); + continue; + } + + if (put_user(reg, uindices)) return -EFAULT; uindices++; }