Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Dec 2018 14:44:38 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
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
Message-ID:  <201812141444.wBEEicw3000968@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <jceel@FreeBSD.org>.
+ * Copyright (c) 2018 Alexander Motin <mav@FreeBSD.org>
  * 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 <jceel@FreeBSD.org>.
+ * Copyright (c) 2018 Alexander Motin <mav@FreeBSD.org>
  * 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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812141444.wBEEicw3000968>