From owner-svn-src-projects@freebsd.org Wed May 22 23:30:52 2019 Return-Path: Delivered-To: svn-src-projects@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 B3AF315914CF for ; Wed, 22 May 2019 23:30:52 +0000 (UTC) (envelope-from asomers@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 5337A7099B; Wed, 22 May 2019 23:30:52 +0000 (UTC) (envelope-from asomers@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 1422E247C2; Wed, 22 May 2019 23:30:52 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x4MNUprq062532; Wed, 22 May 2019 23:30:51 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x4MNUp7u062531; Wed, 22 May 2019 23:30:51 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201905222330.x4MNUp7u062531@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Wed, 22 May 2019 23:30:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r348132 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 348132 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 5337A7099B X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.96)[-0.960,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 May 2019 23:30:53 -0000 Author: asomers Date: Wed May 22 23:30:51 2019 New Revision: 348132 URL: https://svnweb.freebsd.org/changeset/base/348132 Log: fusefs: fix "recursing on non recursive lockmgr" panic When mounted with -o default_permissions and when vfs.fusefs.data_cache_mode=2, fuse_io_strategy would try to clear the suid bit after a successful write by a non-owner. When combined with a not-yet-committed attribute-caching patch I'm working on, and if the FUSE_SETATTR response indicates an unexpected filesize (legal, if the file system has other clients), this would end up calling vtruncbuf. That would panic, because the buffer lock was already held by bufwrite or bufstrategy or something else upstack from fuse_vnop_strategy. Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_io.c projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Modified: projects/fuse2/sys/fs/fuse/fuse_io.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_io.c Wed May 22 23:23:16 2019 (r348131) +++ projects/fuse2/sys/fs/fuse/fuse_io.c Wed May 22 23:30:51 2019 (r348132) @@ -883,9 +883,6 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp) bp->b_ioflags |= BIO_ERROR; bp->b_flags |= B_INVAL; bp->b_error = error; - } else { - fuse_io_clear_suid_on_write(vp, cred, - uio.uio_td); } bp->b_dirtyoff = bp->b_dirtyend = 0; } Modified: projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Wed May 22 23:23:16 2019 (r348131) +++ projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Wed May 22 23:30:51 2019 (r348132) @@ -68,7 +68,7 @@ virtual void SetUp() { } public: -void expect_chmod(uint64_t ino, mode_t mode) +void expect_chmod(uint64_t ino, mode_t mode, uint64_t size = 0) { EXPECT_CALL(*m_mock, process( ResultOf([=](auto in) { @@ -82,6 +82,7 @@ void expect_chmod(uint64_t ino, mode_t mode) SET_OUT_HEADER_LEN(out, attr); out->body.attr.attr.ino = ino; // Must match nodeid out->body.attr.attr.mode = S_IFREG | mode; + out->body.attr.attr.size = size; out->body.attr.attr_valid = UINT64_MAX; }))); } @@ -1229,7 +1230,7 @@ TEST_F(Write, clear_suid) expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); expect_open(ino, 0, 1); expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); - expect_chmod(ino, newmode); + expect_chmod(ino, newmode, sizeof(wbuf)); fd = open(FULLPATH, O_WRONLY); ASSERT_LE(0, fd) << strerror(errno); @@ -1255,7 +1256,7 @@ TEST_F(Write, clear_sgid) expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); expect_open(ino, 0, 1); expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); - expect_chmod(ino, newmode); + expect_chmod(ino, newmode, sizeof(wbuf)); fd = open(FULLPATH, O_WRONLY); ASSERT_LE(0, fd) << strerror(errno); @@ -1264,3 +1265,34 @@ TEST_F(Write, clear_sgid) EXPECT_EQ(S_IFREG | newmode, sb.st_mode); /* Deliberately leak fd. close(2) will be tested in release.cc */ } + +/* Regression test for a specific recurse-of-nonrecursive-lock panic + * + * With writeback caching, we can't call vtruncbuf from fuse_io_strategy, or it + * may panic. That happens if the FUSE_SETATTR response indicates that the + * file's size has changed since the write. + */ +TEST_F(Write, recursion_panic_while_clearing_suid) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + uint64_t ino = 42; + mode_t oldmode = 04777; + mode_t newmode = 0777; + char wbuf[1] = {'x'}; + int fd; + + expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1); + expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX); + expect_open(ino, 0, 1); + expect_write(ino, 0, sizeof(wbuf), sizeof(wbuf), 0, wbuf); + /* XXX Return a smaller file size than what we just wrote! */ + expect_chmod(ino, newmode, 0); + + fd = open(FULLPATH, O_WRONLY); + ASSERT_LE(0, fd) << strerror(errno); + ASSERT_EQ(1, write(fd, wbuf, sizeof(wbuf))) << strerror(errno); + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +