Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp282205ybb; Fri, 27 Mar 2020 22:12:09 -0700 (PDT) X-Google-Smtp-Source: ADFU+vt4ByGqk363lfBYb3ul2IZacjPtBhAsi43uWWKoXFxMmQVPF9l7aTO43Ae04MaK7kk4kwN7 X-Received: by 2002:a4a:d30c:: with SMTP id g12mr2238019oos.16.1585372329213; Fri, 27 Mar 2020 22:12:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1585372329; cv=none; d=google.com; s=arc-20160816; b=Mv9NdQY2f0bJtm/w0o3TqmLAGewDyQKdsNwlo0MiEvg/LZiBT48Iw85FjgnYWtZGM2 CLIXbsdR/NyHVB+0jNjYnd0d7Jgql2OZofqDN3T6921EmT2JDFlgoaV/a/gsdV3gQM/r N/tYPy/S+MSHRg3gj4LyiSVorI7PT0p8FplZoAE83wDtSdqQgu8glEagLCoBqpkVgvFo JtNnnSeewvcuUd8N3QK+XXTpHTJ4rrWMEhCyZc2Z4bSXqqeENJmON34bPQDN7hfGR9Dz KqnNaUSHG4KliMOjwcz76pzjvrSbs3P7IpYLVjyzyFjZzYfdlLTdyaIWSG/P/DQqpjv/ h9vg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=73oD+30y6Wu3MRHFh2CUTnbCEgbi2YqK1GNQew4wDgA=; b=XawqMMTlx9iGoXE+8clnab9PO57Z/gVgJmPe9LIz7gT7zHeSQUAsnsvCjGgf+XOeff CnyzjZUIGbMDiFJE34Gaa9OZuDiDpRxrm3Q2NesHfpWZA+AJ2/6xOjZPWFyQ7X9/1JOS eKTEG1W0vL5Gy24mgj2RBtHvgfh4bExI0oZk9S4gXQJaFmuB+ZSzh4/C9Ev8+tL9d0nK Y42216ar1JHBMvJdVHanaJ+0+kDleD5FSru/eeUIfmEGLED0iLL5RdfFWONVmV25zajT Ooqw11/tDKKPkZPGvxLH+s3h5E1mPEx6ZNojwaVPTsOATmP3ZOKTA9ooFs1roxFgANms 0ipA== 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r67si1437378oib.237.2020.03.27.22.11.56; Fri, 27 Mar 2020 22:12:09 -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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726199AbgC1FKf (ORCPT + 99 others); Sat, 28 Mar 2020 01:10:35 -0400 Received: from mta01.start.ca ([162.250.196.97]:44074 "EHLO mta01.start.ca" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725372AbgC1FKf (ORCPT ); Sat, 28 Mar 2020 01:10:35 -0400 Received: from mta01.start.ca (localhost [127.0.0.1]) by mta01.start.ca (Postfix) with ESMTP id A946E4292B; Sat, 28 Mar 2020 01:10:33 -0400 (EDT) Received: from localhost (dhcp-24-53-240-163.cable.user.start.ca [24.53.240.163]) by mta01.start.ca (Postfix) with ESMTPS id ADCD142928; Sat, 28 Mar 2020 01:10:31 -0400 (EDT) From: Nick Bowler To: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org Cc: Sagi Grimberg , Christoph Hellwig , Keith Busch Subject: [PATCH v2 2/2] nvme: Fix compat address handling in several ioctls Date: Sat, 28 Mar 2020 01:09:09 -0400 Message-Id: <20200328050909.30639-3-nbowler@draconx.ca> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200328050909.30639-1-nbowler@draconx.ca> References: <20200328050909.30639-1-nbowler@draconx.ca> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Virus-Scanned: ClamAV using ClamSMTP Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On a 32-bit kernel, the upper bits of userspace addresses passed via various ioctls are silently ignored by the nvme driver. However on a 64-bit kernel running a compat task, these upper bits are not ignored and are in fact required to be zero for the ioctls to work. Unfortunately, this difference matters. 32-bit smartctl submits the NVME_IOCTL_ADMIN_CMD ioctl with garbage in these upper bits because it seems the pointer value it puts into the nvme_passthru_cmd structure is sign extended. This works fine on 32-bit kernels but fails on a 64-bit one because (at least on my setup) the addresses smartctl uses are consistently above 2G. For example: # smartctl -x /dev/nvme0n1 smartctl 7.1 2019-12-30 r5022 [x86_64-linux-5.5.11] (local build) Copyright (C) 2002-19, Bruce Allen, Christian Franke, www.smartmontools.org Read NVMe Identify Controller failed: NVME_IOCTL_ADMIN_CMD: Bad address Since changing 32-bit kernels to actually check all of the submitted address bits now would break existing userspace, this patch fixes the compat problem by explicitly zeroing the upper bits in the compat case. This enables 32-bit smartctl to work on a 64-bit kernel. Signed-off-by: Nick Bowler --- drivers/nvme/host/core.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 9eccf56494de..f265ccd69dd7 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -1248,6 +1249,19 @@ static void nvme_enable_aen(struct nvme_ctrl *ctrl) queue_work(nvme_wq, &ctrl->async_event_work); } +/* + * Convert integer values from ioctl structures to user pointers, silently + * ignoring the upper bits in the compat case to match behaviour of 32-bit + * kernels. + */ +static void __user *nvme_to_user_ptr(uintptr_t ptrval) +{ + if (in_compat_syscall()) + ptrval = (compat_uptr_t)ptrval; + + return (void __user *)ptrval; +} + static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio, size_t uio_size) { @@ -1276,7 +1290,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio, length = (io.nblocks + 1) << ns->lba_shift; meta_len = (io.nblocks + 1) * ns->ms; - metadata = (void __user *)(uintptr_t)io.metadata; + metadata = nvme_to_user_ptr(io.metadata); if (ns->ext) { length += meta_len; @@ -1299,7 +1313,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio, c.rw.appmask = cpu_to_le16(io.appmask); return nvme_submit_user_cmd(ns->queue, &c, - (void __user *)(uintptr_t)io.addr, length, + nvme_to_user_ptr(io.addr), length, metadata, meta_len, lower_32_bits(io.slba), NULL, 0); } @@ -1419,9 +1433,9 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, effects = nvme_passthru_start(ctrl, ns, cmd.opcode); status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, - (void __user *)(uintptr_t)cmd.addr, cmd.data_len, - (void __user *)(uintptr_t)cmd.metadata, - cmd.metadata_len, 0, &result, timeout); + nvme_to_user_ptr(cmd.addr), cmd.data_len, + nvme_to_user_ptr(cmd.metadata), cmd.metadata_len, + 0, &result, timeout); nvme_passthru_end(ctrl, effects); if (status >= 0) { @@ -1466,8 +1480,8 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, effects = nvme_passthru_start(ctrl, ns, cmd.opcode); status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, - (void __user *)(uintptr_t)cmd.addr, cmd.data_len, - (void __user *)(uintptr_t)cmd.metadata, cmd.metadata_len, + nvme_to_user_ptr(cmd.addr), cmd.data_len, + nvme_to_user_ptr(cmd.metadata), cmd.metadata_len, 0, &cmd.result, timeout); nvme_passthru_end(ctrl, effects); -- 2.24.1