From owner-svn-src-stable@freebsd.org Fri Dec 14 14:44:39 2018 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id AE5741335D84; Fri, 14 Dec 2018 14:44:39 +0000 (UTC) (envelope-from mav@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 50D07779AB; Fri, 14 Dec 2018 14:44:39 +0000 (UTC) (envelope-from mav@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 46DB9BFD; Fri, 14 Dec 2018 14:44:39 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wBEEidTP000971; Fri, 14 Dec 2018 14:44:39 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wBEEicw3000968; Fri, 14 Dec 2018 14:44:38 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201812141444.wBEEicw3000968@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Fri, 14 Dec 2018 14:44:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r342080 - stable/12/usr.sbin/bhyve X-SVN-Group: stable-12 X-SVN-Commit-Author: mav X-SVN-Commit-Paths: stable/12/usr.sbin/bhyve X-SVN-Commit-Revision: 342080 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 50D07779AB X-Spamd-Bar: - Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-1.19 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-0.86)[-0.864,0]; NEURAL_HAM_SHORT(-0.32)[-0.321,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Dec 2018 14:44:39 -0000 Author: mav Date: Fri Dec 14 14:44:38 2018 New Revision: 342080 URL: https://svnweb.freebsd.org/changeset/base/342080 Log: MFC r341705: Fix several iov handling bugs in bhyve virtio-scsi backend. - buf_to_iov() does not use buflen parameter, allowing out of bound read. - buf_to_iov() leaks memory if seek argument > 0. - iov_to_buf() doesn't need to reallocate buffer for every segment. - there is no point to use size_t for iov counts, int is more then enough. - some iov function arguments can be constified. - pci_vtscsi_request_handle() used truncate_iov() incorrectly, allowing getting out of buffer and possibly corrupting data. - pci_vtscsi_controlq_notify() written returned status at wrong offset. - pci_vtscsi_controlq_notify() leaked one buffer per event. Modified: stable/12/usr.sbin/bhyve/iov.c stable/12/usr.sbin/bhyve/iov.h stable/12/usr.sbin/bhyve/pci_virtio_scsi.c Directory Properties: stable/12/ (props changed) Modified: stable/12/usr.sbin/bhyve/iov.c ============================================================================== --- stable/12/usr.sbin/bhyve/iov.c Fri Dec 14 10:49:48 2018 (r342079) +++ stable/12/usr.sbin/bhyve/iov.c Fri Dec 14 14:44:38 2018 (r342080) @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2016 Jakub Klama . + * Copyright (c) 2018 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,12 +40,12 @@ __FBSDID("$FreeBSD$"); #include "iov.h" void -seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2, size_t *niov2, +seek_iov(const struct iovec *iov1, int niov1, struct iovec *iov2, int *niov2, size_t seek) { size_t remainder = 0; size_t left = seek; - size_t i, j; + int i, j; for (i = 0; i < niov1; i++) { size_t toseek = MIN(left, iov1[i].iov_len); @@ -69,9 +70,10 @@ seek_iov(struct iovec *iov1, size_t niov1, struct iove } size_t -count_iov(struct iovec *iov, size_t niov) +count_iov(const struct iovec *iov, int niov) { - size_t i, total = 0; + size_t total = 0; + int i; for (i = 0; i < niov; i++) total += iov[i].iov_len; @@ -79,35 +81,36 @@ count_iov(struct iovec *iov, size_t niov) return (total); } -size_t -truncate_iov(struct iovec *iov, size_t niov, size_t length) +void +truncate_iov(struct iovec *iov, int *niov, size_t length) { - size_t i, done = 0; + size_t done = 0; + int i; - for (i = 0; i < niov; i++) { + for (i = 0; i < *niov; i++) { size_t toseek = MIN(length - done, iov[i].iov_len); done += toseek; - if (toseek < iov[i].iov_len) { + if (toseek <= iov[i].iov_len) { iov[i].iov_len = toseek; - return (i + 1); + *niov = i + 1; + return; } } - - return (niov); } ssize_t -iov_to_buf(struct iovec *iov, size_t niov, void **buf) +iov_to_buf(const struct iovec *iov, int niov, void **buf) { - size_t i, ptr = 0, total = 0; + size_t ptr, total; + int i; - for (i = 0; i < niov; i++) { - total += iov[i].iov_len; - *buf = realloc(*buf, total); - if (*buf == NULL) - return (-1); + total = count_iov(iov, niov); + *buf = realloc(*buf, total); + if (*buf == NULL) + return (-1); + for (i = 0, ptr = 0; i < niov; i++) { memcpy(*buf + ptr, iov[i].iov_base, iov[i].iov_len); ptr += iov[i].iov_len; } @@ -116,12 +119,12 @@ iov_to_buf(struct iovec *iov, size_t niov, void **buf) } ssize_t -buf_to_iov(void *buf, size_t buflen, struct iovec *iov, size_t niov, +buf_to_iov(const void *buf, size_t buflen, struct iovec *iov, int niov, size_t seek) { struct iovec *diov; - size_t ndiov, i; - uintptr_t off = 0; + int ndiov, i; + size_t off = 0, len; if (seek > 0) { diov = malloc(sizeof(struct iovec) * niov); @@ -131,10 +134,14 @@ buf_to_iov(void *buf, size_t buflen, struct iovec *iov ndiov = niov; } - for (i = 0; i < ndiov; i++) { - memcpy(diov[i].iov_base, buf + off, diov[i].iov_len); - off += diov[i].iov_len; + for (i = 0; i < ndiov && off < buflen; i++) { + len = MIN(diov[i].iov_len, buflen - off); + memcpy(diov[i].iov_base, buf + off, len); + off += len; } + + if (seek > 0) + free(diov); return ((ssize_t)off); } Modified: stable/12/usr.sbin/bhyve/iov.h ============================================================================== --- stable/12/usr.sbin/bhyve/iov.h Fri Dec 14 10:49:48 2018 (r342079) +++ stable/12/usr.sbin/bhyve/iov.h Fri Dec 14 14:44:38 2018 (r342080) @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2016 Jakub Klama . + * Copyright (c) 2018 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,12 +33,12 @@ #ifndef _IOV_H_ #define _IOV_H_ -void seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2, - size_t *niov2, size_t seek); -size_t truncate_iov(struct iovec *iov, size_t niov, size_t length); -size_t count_iov(struct iovec *iov, size_t niov); -ssize_t iov_to_buf(struct iovec *iov, size_t niov, void **buf); -ssize_t buf_to_iov(void *buf, size_t buflen, struct iovec *iov, size_t niov, +void seek_iov(const struct iovec *iov1, int niov1, struct iovec *iov2, + int *niov2, size_t seek); +void truncate_iov(struct iovec *iov, int *niov, size_t length); +size_t count_iov(const struct iovec *iov, int niov); +ssize_t iov_to_buf(const struct iovec *iov, int niov, void **buf); +ssize_t buf_to_iov(const void *buf, size_t buflen, struct iovec *iov, int niov, size_t seek); #endif /* _IOV_H_ */ Modified: stable/12/usr.sbin/bhyve/pci_virtio_scsi.c ============================================================================== --- stable/12/usr.sbin/bhyve/pci_virtio_scsi.c Fri Dec 14 10:49:48 2018 (r342079) +++ stable/12/usr.sbin/bhyve/pci_virtio_scsi.c Fri Dec 14 14:44:38 2018 (r342080) @@ -462,7 +462,7 @@ pci_vtscsi_request_handle(struct pci_vtscsi_queue *q, struct pci_vtscsi_req_cmd_wr *cmd_wr; struct iovec data_iov_in[VTSCSI_MAXSEG], data_iov_out[VTSCSI_MAXSEG]; union ctl_io *io; - size_t data_niov_in, data_niov_out; + int data_niov_in, data_niov_out; void *ext_data_ptr = NULL; uint32_t ext_data_len = 0, ext_sg_entries = 0; int err; @@ -472,8 +472,8 @@ pci_vtscsi_request_handle(struct pci_vtscsi_queue *q, seek_iov(iov_out, niov_out, data_iov_out, &data_niov_out, VTSCSI_OUT_HEADER_LEN(sc)); - truncate_iov(iov_in, niov_in, VTSCSI_IN_HEADER_LEN(sc)); - truncate_iov(iov_out, niov_out, VTSCSI_OUT_HEADER_LEN(sc)); + truncate_iov(iov_in, &niov_in, VTSCSI_IN_HEADER_LEN(sc)); + truncate_iov(iov_out, &niov_out, VTSCSI_OUT_HEADER_LEN(sc)); iov_to_buf(iov_in, niov_in, (void **)&cmd_rd); cmd_wr = malloc(VTSCSI_OUT_HEADER_LEN(sc)); @@ -552,7 +552,8 @@ pci_vtscsi_controlq_notify(void *vsc, struct vqueue_in n = vq_getchain(vq, &idx, iov, VTSCSI_MAXSEG, NULL); bufsize = iov_to_buf(iov, n, &buf); iolen = pci_vtscsi_control_handle(sc, buf, bufsize); - buf_to_iov(buf + bufsize - iolen, iolen, iov, n, iolen); + buf_to_iov(buf + bufsize - iolen, iolen, iov, n, + bufsize - iolen); /* * Release this chain and handle more @@ -560,6 +561,7 @@ pci_vtscsi_controlq_notify(void *vsc, struct vqueue_in vq_relchain(vq, idx, iolen); } vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ + free(buf); } static void