From patchwork Wed Jan 13 05:39:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 8022161 Return-Path: X-Original-To: patchwork-linux-nvdimm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7E8A6BEEE5 for ; Wed, 13 Jan 2016 05:40:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5F2372040F for ; Wed, 13 Jan 2016 05:40:03 +0000 (UTC) Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5E17F203DF for ; Wed, 13 Jan 2016 05:40:02 +0000 (UTC) Received: from ml01.vlan14.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 414A11A1EF0; Tue, 12 Jan 2016 21:40:02 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by ml01.01.org (Postfix) with ESMTP id E315C1A1EF0 for ; Tue, 12 Jan 2016 21:40:00 -0800 (PST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga101.jf.intel.com with ESMTP; 12 Jan 2016 21:40:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,287,1449561600"; d="scan'208";a="892098591" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.136]) by fmsmga002.fm.intel.com with ESMTP; 12 Jan 2016 21:40:00 -0800 Subject: [RFC PATCH 3/6] acpi/nfit, libnvdimm: fail unsupported dsm function numbers via call_dsm From: Dan Williams To: linux-nvdimm@lists.01.org Date: Tue, 12 Jan 2016 21:39:34 -0800 Message-ID: <20160113053934.6293.5029.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <20160113052327.6293.32858.stgit@dwillia2-desk3.amr.corp.intel.com> References: <20160113052327.6293.32858.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.17.1-9-g687f MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Prevent invalid commands from being sent to ACPICA, check the requested dsm function number against the support dsm mask. Besides protecting against known invalid commands this also enables the kernel to guarantee it has exclusive access to manipulate namespace labels (for buses that implement get_config and set_config commands). A side effect of this change is that the kernel must know the uuid of the device in advance so that it can populate a correct dsm_mask. The top-level bus device has a known uuid, but the per-dimm device are format interface code specific. Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 39 ++++++++++++++++++++++----------------- drivers/nvdimm/bus.c | 35 ++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 9ba5a9a4b943..00aa20adde7c 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -76,8 +76,9 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, unsigned int buf_len) { struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); - const struct nd_cmd_desc *desc = NULL; union acpi_object in_obj, in_buf, *out_obj; + struct nd_cmd_dsmcall_pkg *call_dsm = NULL; + const struct nd_cmd_desc *desc = NULL; struct device *dev = acpi_desc->dev; const char *cmd_name, *dimm_name; unsigned long dsm_mask; @@ -87,8 +88,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, int rc, i; __u64 rev = 1, func = cmd; - struct nd_cmd_dsmcall_pkg *pkg = buf; - int dsm_call = (cmd == ND_CMD_CALL_DSM); + if (cmd == ND_CMD_CALL_DSM) { + call_dsm = buf; + func = call_dsm->dsm_fun_idx; + } if (nvdimm) { struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); @@ -112,13 +115,11 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, handle = adev->handle; dimm_name = "bus"; } - if (dsm_call) - dsm_mask = ~0UL; if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) return -ENOTTY; - if (!test_bit(cmd, &dsm_mask)) + if (!test_bit(func, &dsm_mask)) return -ENOTTY; in_obj.type = ACPI_TYPE_PACKAGE; @@ -133,14 +134,16 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, in_buf.buffer.length += nd_cmd_in_size(nvdimm, cmd, desc, i, buf); - if (dsm_call) { + if (call_dsm) { /* must skip over package wrapper */ - in_buf.buffer.pointer = (void *) &pkg->dsm_buf; - in_buf.buffer.length = pkg->dsm_in; - /* for pass thru must use value sent in from user space. */ - uuid = pkg->dsm_uuid; - rev = pkg->dsm_rev; - func = pkg->dsm_fun_idx; + in_buf.buffer.pointer = (void *) &call_dsm->dsm_buf; + in_buf.buffer.length = call_dsm->dsm_in; + if (memcmp(call_dsm->dsm_uuid, uuid, 16) != 0) { + dev_dbg(dev, "%s:%s unsupported uuid\n", dimm_name, + cmd_name); + return -EINVAL; + } + rev = call_dsm->dsm_rev; } if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) { @@ -173,10 +176,12 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, min_t(u32, 256, out_obj->buffer.length), true); } - if (dsm_call) { - pkg->dsm_size = out_obj->buffer.length; - memcpy(pkg->dsm_buf + pkg->dsm_in, out_obj->buffer.pointer, - min(pkg->dsm_size, pkg->dsm_out)); + if (call_dsm) { + call_dsm->dsm_size = out_obj->buffer.length; + memcpy(call_dsm->dsm_buf + call_dsm->dsm_in, + out_obj->buffer.pointer, + min(call_dsm->dsm_size, call_dsm->dsm_out)); + ACPI_FREE(out_obj); return 0; } diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 6e9787ad1fe1..b86d5eda78ed 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -512,35 +512,38 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, unsigned int cmd = _IOC_NR(ioctl_cmd); void __user *p = (void __user *) arg; struct device *dev = &nvdimm_bus->dev; + struct nd_cmd_dsmcall_pkg call_dsm; const char *cmd_name, *dimm_name; - unsigned long dsm_mask = ~0UL; + unsigned int func = cmd; + unsigned long dsm_mask; void *buf; int rc, i; - struct nd_cmd_dsmcall_pkg *pkg; - int dsm_call = (cmd == ND_CMD_CALL_DSM); - if (nvdimm) { desc = nd_cmd_dimm_desc(cmd); cmd_name = nvdimm_cmd_name(cmd); - if (!dsm_call) - dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0; + dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0; dimm_name = dev_name(&nvdimm->dev); } else { desc = nd_cmd_bus_desc(cmd); cmd_name = nvdimm_bus_cmd_name(cmd); - if (!dsm_call) - dsm_mask = nd_desc->dsm_mask; + dsm_mask = nd_desc->dsm_mask; dimm_name = "bus"; } + if (cmd == ND_CMD_CALL_DSM) { + if (copy_from_user(&call_dsm, p, sizeof(cmd))) + return -EFAULT; + func = call_dsm.dsm_fun_idx; + } + if (!desc || (desc->out_num + desc->in_num == 0) || - !test_bit(cmd, &dsm_mask)) + !test_bit(func, &dsm_mask)) return -ENOTTY; /* fail write commands (when read-only) */ if (read_only) - switch (cmd) { + switch (func) { case ND_CMD_VENDOR: case ND_CMD_SET_CONFIG_DATA: case ND_CMD_ARS_START: @@ -572,15 +575,13 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, in_len += in_size; } - if (dsm_call) { - pkg = (struct nd_cmd_dsmcall_pkg *) in_env; - + if (cmd == ND_CMD_CALL_DSM) { dev_dbg(dev, "%s:%s rev: %llu, idx: %llu, in: %zu, out: %zu, len %zu\n", - __func__, dimm_name, pkg->dsm_rev, - pkg->dsm_fun_idx, in_len, out_len, buf_len); + __func__, dimm_name, call_dsm.dsm_rev, + call_dsm.dsm_fun_idx, in_len, out_len, buf_len); - for (i = 0; i < ARRAY_SIZE(pkg->reserved2); i++) - if (pkg->reserved2[i]) + for (i = 0; i < ARRAY_SIZE(call_dsm.reserved2); i++) + if (call_dsm.reserved2[i]) return -EINVAL; }