From owner-svn-src-head@freebsd.org Tue Sep 3 14:06:23 2019 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id EF1B5DC6C3; Tue, 3 Sep 2019 14:06:17 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [96.47.72.132]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46N7zF1plYz4PNc; Tue, 3 Sep 2019 14:06:17 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 1452) id EBAD41A40E; Tue, 3 Sep 2019 14:06:03 +0000 (UTC) X-Original-To: yuripv@localmail.freebsd.org Delivered-To: yuripv@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 6B991F248; Fri, 5 Apr 2019 16:54:32 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 96D2B6B2BF; Fri, 5 Apr 2019 16:54:30 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 538) id 111F1F223; Fri, 5 Apr 2019 16:54:29 +0000 (UTC) Delivered-To: src-committers@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 8E448F1CB for ; Fri, 5 Apr 2019 16:54:26 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id E622E6B1C6; Fri, 5 Apr 2019 16:54:21 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 564FFFF51; Fri, 5 Apr 2019 16:54:21 +0000 (UTC) (envelope-from chuck@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x35GsLtU006387; Fri, 5 Apr 2019 16:54:21 GMT (envelope-from chuck@FreeBSD.org) Received: (from chuck@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x35GsLcO006386; Fri, 5 Apr 2019 16:54:21 GMT (envelope-from chuck@FreeBSD.org) Message-Id: <201904051654.x35GsLcO006386@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: chuck set sender to chuck@FreeBSD.org using -f From: Chuck Tuffli To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r345957 - head/usr.sbin/bhyve X-SVN-Group: head X-SVN-Commit-Author: chuck X-SVN-Commit-Paths: head/usr.sbin/bhyve X-SVN-Commit-Revision: 345957 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk X-Loop: FreeBSD.org Sender: owner-src-committers@freebsd.org X-Rspamd-Queue-Id: 96D2B6B2BF X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[freebsd.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.998,0]; NEURAL_HAM_SHORT(-0.96)[-0.963,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] Status: O X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Tue, 03 Sep 2019 14:06:23 -0000 X-Original-Date: Fri, 5 Apr 2019 16:54:21 +0000 (UTC) X-List-Received-Date: Tue, 03 Sep 2019 14:06:23 -0000 Author: chuck Date: Fri Apr 5 16:54:20 2019 New Revision: 345957 URL: https://svnweb.freebsd.org/changeset/base/345957 Log: bhyve: Fix NVMe data structure copy to guest bhyve's NVMe emulation was transferring Identify data back to the guest incorrectly causing memory corruptions. These corruptions resulted in core dumps and other system level errors in the guest. In their simplest form, NVMe Physical Region Page (PRP) values in commands indicate which physical pages to use for data transfer. The first PRP value is not required to be page aligned but does not cross a page boundary. The second PRP value must be page aligned, does not cross a page boundary, and need not be contiguous with PRP1. The code was copying Identify data past the end of PRP1. This happens to work if PRP1 and PRP2 are physically contiguous but will corrupt guest memory in unpredictable ways if they are not. Fix is to copy the Identify data back to the guest piecewise (i.e. for each PRP entry). Also fix a similarly wrong problem when copying back Log page data. Reviewed by: imp (mentor), araujo, jhb, rgrimes, bhyve Approved by: imp (mentor), bhyve (jhb) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D19695 Modified: head/usr.sbin/bhyve/pci_nvme.c Modified: head/usr.sbin/bhyve/pci_nvme.c ============================================================================== --- head/usr.sbin/bhyve/pci_nvme.c Fri Apr 5 16:54:16 2019 (r345956) +++ head/usr.sbin/bhyve/pci_nvme.c Fri Apr 5 16:54:20 2019 (r345957) @@ -202,6 +202,9 @@ struct pci_nvme_softc { struct nvme_namespace_data nsdata; struct nvme_controller_data ctrldata; + struct nvme_error_information_entry err_log; + struct nvme_health_information_page health_log; + struct nvme_firmware_page fw_log; struct pci_nvme_blockstore nvstore; @@ -369,6 +372,15 @@ pci_nvme_init_nsdata(struct pci_nvme_softc *sc) } static void +pci_nvme_init_logpages(struct pci_nvme_softc *sc) +{ + + memset(&sc->err_log, 0, sizeof(sc->err_log)); + memset(&sc->health_log, 0, sizeof(sc->health_log)); + memset(&sc->fw_log, 0, sizeof(sc->fw_log)); +} + +static void pci_nvme_reset_locked(struct pci_nvme_softc *sc) { DPRINTF(("%s\r\n", __func__)); @@ -458,6 +470,47 @@ pci_nvme_init_controller(struct vmctx *ctx, struct pci } static int +nvme_prp_memcpy(struct vmctx *ctx, uint64_t prp1, uint64_t prp2, uint8_t *src, + size_t len) +{ + uint8_t *dst; + size_t bytes; + + if (len > (8 * 1024)) { + return (-1); + } + + /* Copy from the start of prp1 to the end of the physical page */ + bytes = PAGE_SIZE - (prp1 & PAGE_MASK); + bytes = MIN(bytes, len); + + dst = vm_map_gpa(ctx, prp1, bytes); + if (dst == NULL) { + return (-1); + } + + memcpy(dst, src, bytes); + + src += bytes; + + len -= bytes; + if (len == 0) { + return (0); + } + + len = MIN(len, PAGE_SIZE); + + dst = vm_map_gpa(ctx, prp2, len); + if (dst == NULL) { + return (-1); + } + + memcpy(dst, src, len); + + return (0); +} + +static int nvme_opc_delete_io_sq(struct pci_nvme_softc* sc, struct nvme_command* command, struct nvme_completion* compl) { @@ -590,26 +643,24 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struc { uint32_t logsize = (1 + ((command->cdw10 >> 16) & 0xFFF)) * 2; uint8_t logpage = command->cdw10 & 0xFF; - void *data; DPRINTF(("%s log page %u len %u\r\n", __func__, logpage, logsize)); - if (logpage >= 1 && logpage <= 3) - data = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, - PAGE_SIZE); - pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS); switch (logpage) { - case 0x01: /* Error information */ - memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize); + case NVME_LOG_ERROR: + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->err_log, logsize); break; - case 0x02: /* SMART/Health information */ + case NVME_LOG_HEALTH_INFORMATION: /* TODO: present some smart info */ - memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize); + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->health_log, logsize); break; - case 0x03: /* Firmware slot information */ - memset(data, 0, logsize > PAGE_SIZE ? PAGE_SIZE : logsize); + case NVME_LOG_FIRMWARE_SLOT: + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->fw_log, logsize); break; default: WPRINTF(("%s get log page %x command not supported\r\n", @@ -633,14 +684,13 @@ nvme_opc_identify(struct pci_nvme_softc* sc, struct nv switch (command->cdw10 & 0xFF) { case 0x00: /* return Identify Namespace data structure */ - dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, - sizeof(sc->nsdata)); - memcpy(dest, &sc->nsdata, sizeof(sc->nsdata)); + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->nsdata, sizeof(sc->nsdata)); break; case 0x01: /* return Identify Controller data structure */ - dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, - sizeof(sc->ctrldata)); - memcpy(dest, &sc->ctrldata, sizeof(sc->ctrldata)); + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->ctrldata, + sizeof(sc->ctrldata)); break; case 0x02: /* list of 1024 active NSIDs > CDW1.NSID */ dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, @@ -1881,6 +1931,7 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *p pci_nvme_reset(sc); pci_nvme_init_ctrldata(sc); pci_nvme_init_nsdata(sc); + pci_nvme_init_logpages(sc); pci_lintr_request(pi);