git: b1aea70753bc - stable/15 - cuse: Fix hang on readv(2) and writev(2) with multiple iovecs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 07 Oct 2026 06:24:32 UTC
The branch stable/15 has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=b1aea70753bca974af6b8e4814aecd1aaff29e2a
commit b1aea70753bca974af6b8e4814aecd1aaff29e2a
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-09-30 09:49:35 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-10-07 06:23:31 +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
(cherry picked from commit 872c36cb6f2de17278c559a300c2163d8b39b3c6)
---
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,