From nobody Thu May 12 20:40:47 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 436A11AC9D64; Thu, 12 May 2022 20:40:48 +0000 (UTC) (envelope-from git@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) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4KzkFD14gWz4hc5; Thu, 12 May 2022 20:40:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652388048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/6AVdDk7Lo6oLBaazVT8HGXpzXnPiAOeM6WmhwAUqso=; b=SZJyzxlSol03lTjn7lQnqDGbTyzElyZK49PTqh9rGceROcAFVilr5ZImfnDMSJVDqjZCE9 Zr0XlnXuofI/sAswJOhGR84wfEGBdreVzB0rxjbl5szOCsrwEC1yg5ZDSkCqxR8TOCsg9Q Cu1U0UqUWfOvk9v/wYOgDilD/F1vBf6Ui5wDPtAfGX/eE3B1u5fu/Ro8nueqW8mfchvZZm xy669KQD078wtWk1WtsBelPiYIACn04UpKe59v3bDH0BMaOoOGGhJU4eaCgg7bS3xcL16w /rBcq62Vn4lwk9WrDkbR2OUA26yi6+Na75CMbL74/5vslBvAQxX87adMKdfEKA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 04DCD1554A; Thu, 12 May 2022 20:40:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 24CKel7b042864; Thu, 12 May 2022 20:40:47 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 24CKel5T042863; Thu, 12 May 2022 20:40:47 GMT (envelope-from git) Date: Thu, 12 May 2022 20:40:47 GMT Message-Id: <202205122040.24CKel5T042863@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Alan Somers Subject: git: 04f7286f44c4 - stable/13 - fusefs: correctly handle servers that report too much data written List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 04f7286f44c484b4288b3071139d451ae4a623d7 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652388048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/6AVdDk7Lo6oLBaazVT8HGXpzXnPiAOeM6WmhwAUqso=; b=VCfGOxsm/Bjd3NAqpqvuodPedYeQFMkrVBooY8klqTCvTtBUXiRCUjNOX8bWEIidI9eCNu PhhYohAzvo/b59RokIwVjYUoDHpU4bWM4L/zybmN748gAzhmlnz1QNLJGhXpNhBa8PM0/V qg4QNBjNqlOkoqYYYL+K344TMkgW5ZbT4f/qv/iqe30n5CBvmU1ZMVDhPDY2yOcPTp76k3 2AqT51wQXMHpn9tMIduYpw909lPOf2KDl3pKv7IOEK5qaKFbqj9hf8CFn67QIindLigcNL lmeTlrJzYMdHn0ioGOfmrRYqSiO1f8llxZXPtAJAleyB8BSsEq0h2abSuDpqdQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1652388048; a=rsa-sha256; cv=none; b=uGAvbaYX79FNgtWMELXR3GaSfyRN8sT7KEf4nS6zqxwKxv70TN8u5y+AuphsJKUfXyr7Fr 9Cn8MXWIxd07riw/iZhi+FbEOI8OOee2kvBvk3xNez3TZvKhhqrW6LlEPjgSVUq54eoYqT lAG+wv2iNSJMwo7yGnGUe697yi+IjI21P9eDk6Rw0uw4KP8qvyW4BBrcsn1geinPWFeJmt 4XlMjQKpRWoh7Ef2LZ9Gn3/2mW31XfmHU5Q9m3gpv33WkNhborZYlZbwDyVBT+aUz8wvRR vGsLMcm+41ZEU3Hs0Rkjs6PuP0O2OagBqWertmkNF/Oy+UVV+Hsswa/hg+XouQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=04f7286f44c484b4288b3071139d451ae4a623d7 commit 04f7286f44c484b4288b3071139d451ae4a623d7 Author: Alan Somers AuthorDate: 2022-04-18 23:03:53 +0000 Commit: Alan Somers CommitDate: 2022-05-12 20:39:47 +0000 fusefs: correctly handle servers that report too much data written During a FUSE_WRITE, the kernel requests the server to write a certain amount of data, and the server responds with the amount that it actually did write. It is obviously an error for the server to write more than it was provided, and we always treated it as such, but there were two problems: * If the server responded with a huge amount, greater than INT_MAX, it would trigger an integer overflow which would cause a panic. * When extending the file, we wrongly set the file's size before validing the amount written. PR: 263263 Reported by: Robert Morris Sponsored by: Axcient Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D34955 (cherry picked from commit 3a1b3c6a1e68063330e897a5a5c94518edae4a3b) --- sys/fs/fuse/fuse_io.c | 18 ++++++++----- tests/sys/fs/fusefs/write.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c index 8d2e79d0a073..c70eca17ec29 100644 --- a/sys/fs/fuse/fuse_io.c +++ b/sys/fs/fuse/fuse_io.c @@ -395,8 +395,19 @@ retry: fwo = ((struct fuse_write_out *)fdi.answ); + if (fwo->size > fwi->size) { + fuse_warn(data, FSESS_WARN_WROTE_LONG, + "wrote more data than we provided it."); + /* This is bonkers. Clear attr cache. */ + fvdat->flag &= ~FN_SIZECHANGE; + fuse_vnode_clear_attr_cache(vp); + err = EINVAL; + break; + } + /* Adjust the uio in the case of short writes */ diff = fwi->size - fwo->size; + as_written_offset = uio->uio_offset - diff; if (as_written_offset - diff > filesize) { @@ -406,12 +417,7 @@ retry: if (as_written_offset - diff >= filesize) fvdat->flag &= ~FN_SIZECHANGE; - if (diff < 0) { - fuse_warn(data, FSESS_WARN_WROTE_LONG, - "wrote more data than we provided it."); - err = EINVAL; - break; - } else if (diff > 0) { + if (diff > 0) { /* Short write */ if (!direct_io) { fuse_warn(data, FSESS_WARN_SHORT_WRITE, diff --git a/tests/sys/fs/fusefs/write.cc b/tests/sys/fs/fusefs/write.cc index db5bb3fe4441..d685bd13aa17 100644 --- a/tests/sys/fs/fusefs/write.cc +++ b/tests/sys/fs/fusefs/write.cc @@ -410,6 +410,67 @@ TEST_F(Write, indirect_io_short_write) leak(fd); } +/* It is an error if the daemon claims to have written more data than we sent */ +TEST_F(Write, indirect_io_long_write) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const char *CONTENTS = "abcdefghijklmnop"; + uint64_t ino = 42; + int fd; + ssize_t bufsize = strlen(CONTENTS); + ssize_t bufsize_out = 100; + off_t some_other_size = 25; + struct stat sb; + + expect_lookup(RELPATH, ino, 0); + expect_open(ino, 0, 1); + expect_write(ino, 0, bufsize, bufsize_out, CONTENTS); + expect_getattr(ino, some_other_size); + + fd = open(FULLPATH, O_WRONLY); + ASSERT_LE(0, fd) << strerror(errno); + + ASSERT_EQ(-1, write(fd, CONTENTS, bufsize)) << strerror(errno); + ASSERT_EQ(EINVAL, errno); + + /* + * Following such an error, we should requery the server for the file's + * size. + */ + fstat(fd, &sb); + ASSERT_EQ(sb.st_size, some_other_size); + + leak(fd); +} + +/* + * Don't crash if the server returns a write that can't be represented as a + * signed 32 bit number. Regression test for + * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=263263 + */ +TEST_F(Write, indirect_io_very_long_write) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const char *CONTENTS = "abcdefghijklmnop"; + uint64_t ino = 42; + int fd; + ssize_t bufsize = strlen(CONTENTS); + ssize_t bufsize_out = 3 << 30; + + expect_lookup(RELPATH, ino, 0); + expect_open(ino, 0, 1); + expect_write(ino, 0, bufsize, bufsize_out, CONTENTS); + + fd = open(FULLPATH, O_WRONLY); + ASSERT_LE(0, fd) << strerror(errno); + + ASSERT_EQ(-1, write(fd, CONTENTS, bufsize)) << strerror(errno); + ASSERT_EQ(EINVAL, errno); + leak(fd); +} + /* * When the direct_io option is used, filesystems are allowed to write less * data than requested. We should return the short write to userland.