git: 872c36cb6f2d - main - cuse: Fix hang on readv(2) and writev(2) with multiple iovecs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 30 Sep 2026 09:51:22 UTC
The branch main has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=872c36cb6f2de17278c559a300c2163d8b39b3c6
commit 872c36cb6f2de17278c559a300c2163d8b39b3c6
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-09-30 09:49:35 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-09-30 09:49:35 +0000
cuse: Fix hang on readv(2) and writev(2) with multiple iovecs
uiomove() leaves an iovec it has just emptied as the current one, so
cuse_client_read() and cuse_client_write() picked it up again on the
next iteration, sent the server a zero-length command, and got zero
bytes back. That left the residual count unchanged, so the loop never
terminated and the call never returned.
Step past empty iovecs at the start of every iteration. This also covers
caller-supplied zero-length iovecs, which hung in the same way
PR: 293489
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Reviewed by: kib, markj
Differential Revision: https://reviews.freebsd.org/D59822
---
sys/fs/cuse/cuse.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c
index ef786d125c15..c6107b977dac 100644
--- a/sys/fs/cuse/cuse.c
+++ b/sys/fs/cuse/cuse.c
@@ -1666,11 +1666,21 @@ cuse_client_read(struct cdev *dev, struct uio *uio, int ioflag)
cuse_cmd_lock(pccmd);
while (uio->uio_resid != 0) {
- if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) {
+ len = uio->uio_iov->iov_len;
+ /*
+ * The uiomove() below does not step past an iovec it has
+ * just emptied, so do it here, to avoid an infinite loop
+ * where we are requesting zero-byte transfers.
+ */
+ if (len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
+ }
+ if (len > CUSE_LENGTH_MAX) {
error = ENOMEM;
break;
}
- len = uio->uio_iov->iov_len;
cuse_server_lock(pcs);
if (len <= CUSE_COPY_BUFFER_MAX) {
@@ -1754,11 +1764,21 @@ cuse_client_write(struct cdev *dev, struct uio *uio, int ioflag)
cuse_cmd_lock(pccmd);
while (uio->uio_resid != 0) {
- if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) {
+ len = uio->uio_iov->iov_len;
+ /*
+ * The uiomove() below does not step past an iovec it has
+ * just emptied, so do it here, to avoid an infinite loop
+ * where we are requesting zero-byte transfers.
+ */
+ if (len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ continue;
+ }
+ if (len > CUSE_LENGTH_MAX) {
error = ENOMEM;
break;
}
- len = uio->uio_iov->iov_len;
if (len <= CUSE_COPY_BUFFER_MAX) {
error = copyin(uio->uio_iov->iov_base,