// Copyright 2023 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include #include #include #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "test/util/file_descriptor.h" #include "test/util/fs_util.h" #include "test/util/linux_capability_util.h" #include "test/util/mount_util.h" #include "test/util/posix_error.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" using ::testing::Ge; namespace gvisor { namespace testing { namespace { TEST(FuseTest, RejectBadInit) { SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/fuse", O_RDWR, 0)); auto mount_point = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); auto mount_opts = absl::StrFormat("fd=%d,user_id=0,group_id=0,rootmode=40000", fd.get()); auto mount = ASSERT_NO_ERRNO_AND_VALUE( Mount("fuse", mount_point.path(), "fuse", MS_NODEV | MS_NOSUID, mount_opts, 0 /* umountflags */)); // Read the init request so that we have the correct unique ID. alignas(fuse_in_header) char req_buf[FUSE_MIN_READ_BUFFER]; ASSERT_THAT(read(fd.get(), req_buf, sizeof(req_buf)), SyscallSucceedsWithValue(Ge(sizeof(fuse_in_header)))); fuse_out_header resp; resp.len = sizeof(resp) - 1; resp.error = 0; resp.unique = reinterpret_cast(req_buf)->unique; ASSERT_THAT(write(fd.get(), reinterpret_cast(&resp), sizeof(resp)), SyscallFailsWithErrno(EINVAL)); } TEST(FuseTest, LookupUpdatesInode) { SKIP_IF(absl::NullSafeStringView(getenv("GVISOR_FUSE_TEST")) != "TRUE"); const std::string kFileData = "May thy knife chip and shatter.\n"; TempPath path = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( GetAbsoluteTestTmpdir(), kFileData, TempPath::kDefaultFileMode)); FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path.path(), O_RDONLY)); std::vector buf(kFileData.size()); ASSERT_THAT(ReadFd(fd.get(), buf.data(), kFileData.size()), SyscallSucceedsWithValue(kFileData.size())); ASSERT_THAT(unlink(JoinPath("/fuse", Basename(path.path())).c_str()), SyscallSucceeds()); EXPECT_THAT(access(path.path().c_str(), O_RDONLY), SyscallFailsWithErrno(ENOENT)); } } // namespace } // namespace testing } // namespace gvisor