svn commit: r347128 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Alan Somers
asomers at FreeBSD.org
Sat May 4 16:28:00 UTC 2019
Author: asomers
Date: Sat May 4 16:27:58 2019
New Revision: 347128
URL: https://svnweb.freebsd.org/changeset/base/347128
Log:
fusefs: only root may set the sticky bit on a non-directory
PR: 216391
Reported by: pjdfstest
Sponsored by: The FreeBSD Foundation
Added:
projects/fuse2/tests/sys/fs/fusefs/default_permissions_privileged.cc (contents, props changed)
Modified:
projects/fuse2/sys/fs/fuse/fuse_vnops.c
projects/fuse2/tests/sys/fs/fusefs/Makefile
projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc
Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c Sat May 4 16:24:43 2019 (r347127)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Sat May 4 16:27:58 2019 (r347128)
@@ -1603,6 +1603,15 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
*/
}
if (vap->va_mode != (mode_t)VNOVAL) {
+ /* Only root may set the sticky bit on non-directories */
+ if (dataflags & FSESS_DEFAULT_PERMISSIONS &&
+ vp->v_type != VDIR && (vap->va_mode & S_ISTXT))
+ {
+ if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) {
+ err = EFTYPE;
+ goto out;
+ }
+ }
fsai->mode = vap->va_mode & ALLPERMS;
fsai->valid |= FATTR_MODE;
accmode |= VADMIN;
Modified: projects/fuse2/tests/sys/fs/fusefs/Makefile
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/Makefile Sat May 4 16:24:43 2019 (r347127)
+++ projects/fuse2/tests/sys/fs/fusefs/Makefile Sat May 4 16:27:58 2019 (r347128)
@@ -11,6 +11,7 @@ GTESTS+= access
GTESTS+= allow_other
GTESTS+= create
GTESTS+= default_permissions
+GTESTS+= default_permissions_privileged
GTESTS+= destroy
GTESTS+= fifo
GTESTS+= flush
@@ -47,6 +48,7 @@ SRCS.$p+= utils.cc
.endfor
TEST_METADATA.default_permissions+= required_user="unprivileged"
+TEST_METADATA.default_permissions_privileged+= required_user="root"
TEST_METADATA.mknod+= required_user="root"
# TODO: drastically increase timeout after test development is mostly complete
Modified: projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Sat May 4 16:24:43 2019 (r347127)
+++ projects/fuse2/tests/sys/fs/fusefs/default_permissions.cc Sat May 4 16:27:58 2019 (r347128)
@@ -771,6 +771,28 @@ TEST_F(Setattr, eacces)
EXPECT_EQ(EPERM, errno);
}
+/* Only the superuser may set the sticky bit on a non-directory */
+TEST_F(Setattr, sticky_regular_file)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const uint64_t ino = 42;
+ const mode_t oldmode = 0644;
+ const mode_t newmode = 01644;
+
+ expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1);
+ expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX, geteuid());
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([](auto in) {
+ return (in->header.opcode == FUSE_SETATTR);
+ }, Eq(true)),
+ _)
+ ).Times(0);
+
+ EXPECT_NE(0, chmod(FULLPATH, newmode));
+ EXPECT_EQ(EFTYPE, errno);
+}
+
TEST_F(Setextattr, ok)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
Added: projects/fuse2/tests/sys/fs/fusefs/default_permissions_privileged.cc
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/fuse2/tests/sys/fs/fusefs/default_permissions_privileged.cc Sat May 4 16:27:58 2019 (r347128)
@@ -0,0 +1,124 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 The FreeBSD Foundation
+ *
+ * This software was developed by BFF Storage Systems, LLC under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Tests for the "default_permissions" mount option that require a privileged
+ * user.
+ */
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/extattr.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+}
+
+#include "mockfs.hh"
+#include "utils.hh"
+
+using namespace testing;
+
+class DefaultPermissionsPrivileged: public FuseTest {
+virtual void SetUp() {
+ m_default_permissions = true;
+ FuseTest::SetUp();
+ if (HasFatalFailure() || IsSkipped())
+ return;
+
+ if (geteuid() != 0) {
+ GTEST_SKIP() << "This test requires a privileged user";
+ }
+
+ /* With -o default_permissions, FUSE_ACCESS should never be called */
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in->header.opcode == FUSE_ACCESS);
+ }, Eq(true)),
+ _)
+ ).Times(0);
+}
+
+public:
+void expect_getattr(uint64_t ino, mode_t mode, uint64_t attr_valid, int times,
+ uid_t uid = 0, gid_t gid = 0)
+{
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in->header.opcode == FUSE_GETATTR &&
+ in->header.nodeid == ino);
+ }, Eq(true)),
+ _)
+ ).Times(times)
+ .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, attr);
+ out->body.attr.attr.ino = ino; // Must match nodeid
+ out->body.attr.attr.mode = mode;
+ out->body.attr.attr.size = 0;
+ out->body.attr.attr.uid = uid;
+ out->body.attr.attr.uid = gid;
+ out->body.attr.attr_valid = attr_valid;
+ })));
+}
+
+void expect_lookup(const char *relpath, uint64_t ino, mode_t mode,
+ uint64_t attr_valid, uid_t uid = 0, gid_t gid = 0)
+{
+ FuseTest::expect_lookup(relpath, ino, mode, 0, 1, attr_valid, uid, gid);
+}
+
+};
+
+class Setattr: public DefaultPermissionsPrivileged {};
+
+TEST_F(Setattr, sticky_regular_file_eftype)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const uint64_t ino = 42;
+ const mode_t oldmode = 0644;
+ const mode_t newmode = 01644;
+
+ expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1);
+ expect_lookup(RELPATH, ino, S_IFREG | oldmode, UINT64_MAX, geteuid());
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([](auto in) {
+ return (in->header.opcode == FUSE_SETATTR);
+ }, Eq(true)),
+ _)
+ ).WillOnce(Invoke(ReturnImmediate([](auto in __unused, auto out) {
+ SET_OUT_HEADER_LEN(out, attr);
+ out->body.attr.attr.mode = S_IFREG | newmode;
+ })));
+
+ EXPECT_EQ(0, chmod(FULLPATH, newmode)) << strerror(errno);
+}
+
+
More information about the svn-src-projects
mailing list