mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Check that a file is a regular file with open(O_TRUNC).
It was possible to panic the sentry by opening a cache revalidating folder with O_TRUNC|O_CREAT. Avoids breaking php tests. PiperOrigin-RevId: 280533213
This commit is contained in:
committed by
gVisor bot
parent
1e1f5ce082
commit
339536de5e
@@ -344,6 +344,10 @@ func (i *Inode) SetTimestamps(ctx context.Context, d *Dirent, ts TimeSpec) error
|
||||
|
||||
// Truncate calls i.InodeOperations.Truncate with i as the Inode.
|
||||
func (i *Inode) Truncate(ctx context.Context, d *Dirent, size int64) error {
|
||||
if IsDir(i.StableAttr) {
|
||||
return syserror.EISDIR
|
||||
}
|
||||
|
||||
if i.overlay != nil {
|
||||
return overlayTruncate(ctx, i.overlay, d, size)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
// +stateify savable
|
||||
type masterInodeOperations struct {
|
||||
fsutil.SimpleFileInode
|
||||
fsutil.InodeNoopTruncate
|
||||
|
||||
// d is the containing dir.
|
||||
d *dirInodeOperations
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
// +stateify savable
|
||||
type slaveInodeOperations struct {
|
||||
fsutil.SimpleFileInode
|
||||
fsutil.InodeNoopTruncate
|
||||
|
||||
// d is the containing dir.
|
||||
d *dirInodeOperations
|
||||
|
||||
@@ -169,10 +169,11 @@ func openAt(t *kernel.Task, dirFD int32, addr usermem.Addr, flags uint) (fd uint
|
||||
if dirPath {
|
||||
return syserror.ENOTDIR
|
||||
}
|
||||
if flags&linux.O_TRUNC != 0 {
|
||||
if err := d.Inode.Truncate(t, d, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if flags&linux.O_TRUNC != 0 {
|
||||
if err := d.Inode.Truncate(t, d, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,28 @@ class OpenTest : public FileTest {
|
||||
const std::string test_data_ = "hello world\n";
|
||||
};
|
||||
|
||||
TEST_F(OpenTest, OTrunc) {
|
||||
auto dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncd");
|
||||
ASSERT_THAT(mkdir(dirpath.c_str(), 0777), SyscallSucceeds());
|
||||
ASSERT_THAT(open(dirpath.c_str(), O_TRUNC, 0666),
|
||||
SyscallFailsWithErrno(EISDIR));
|
||||
}
|
||||
|
||||
TEST_F(OpenTest, OTruncAndReadOnlyDir) {
|
||||
auto dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncd");
|
||||
ASSERT_THAT(mkdir(dirpath.c_str(), 0777), SyscallSucceeds());
|
||||
ASSERT_THAT(open(dirpath.c_str(), O_TRUNC | O_RDONLY, 0666),
|
||||
SyscallFailsWithErrno(EISDIR));
|
||||
}
|
||||
|
||||
TEST_F(OpenTest, OTruncAndReadOnlyFile) {
|
||||
auto dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncfile");
|
||||
const FileDescriptor existing =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Open(dirpath.c_str(), O_RDWR | O_CREAT, 0666));
|
||||
const FileDescriptor otrunc = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Open(dirpath.c_str(), O_TRUNC | O_RDONLY, 0666));
|
||||
}
|
||||
|
||||
TEST_F(OpenTest, ReadOnly) {
|
||||
char buf;
|
||||
const FileDescriptor ro_file =
|
||||
|
||||
@@ -88,6 +88,30 @@ TEST(CreateTest, CreateExclusively) {
|
||||
SyscallFailsWithErrno(EEXIST));
|
||||
}
|
||||
|
||||
TEST(CreateTeast, CreatWithOTrunc) {
|
||||
std::string dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncd");
|
||||
ASSERT_THAT(mkdir(dirpath.c_str(), 0777), SyscallSucceeds());
|
||||
ASSERT_THAT(open(dirpath.c_str(), O_CREAT | O_TRUNC, 0666),
|
||||
SyscallFailsWithErrno(EISDIR));
|
||||
}
|
||||
|
||||
TEST(CreateTeast, CreatDirWithOTruncAndReadOnly) {
|
||||
std::string dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncd");
|
||||
ASSERT_THAT(mkdir(dirpath.c_str(), 0777), SyscallSucceeds());
|
||||
ASSERT_THAT(open(dirpath.c_str(), O_CREAT | O_TRUNC | O_RDONLY, 0666),
|
||||
SyscallFailsWithErrno(EISDIR));
|
||||
}
|
||||
|
||||
TEST(CreateTeast, CreatFileWithOTruncAndReadOnly) {
|
||||
std::string dirpath = JoinPath(GetAbsoluteTestTmpdir(), "truncfile");
|
||||
int dirfd;
|
||||
ASSERT_THAT(dirfd = open(dirpath.c_str(), O_RDWR | O_CREAT, 0666),
|
||||
SyscallSucceeds());
|
||||
ASSERT_THAT(open(dirpath.c_str(), O_CREAT | O_TRUNC | O_RDONLY, 0666),
|
||||
SyscallSucceeds());
|
||||
ASSERT_THAT(close(dirfd), SyscallSucceeds());
|
||||
}
|
||||
|
||||
TEST(CreateTest, CreateFailsOnUnpermittedDir) {
|
||||
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
|
||||
// always override directory permissions.
|
||||
|
||||
@@ -70,6 +70,8 @@ constexpr absl::Duration kTimeout = absl::Seconds(20);
|
||||
// The maximum line size in bytes returned per read from a pty file.
|
||||
constexpr int kMaxLineSize = 4096;
|
||||
|
||||
constexpr char kMasterPath[] = "/dev/ptmx";
|
||||
|
||||
// glibc defines its own, different, version of struct termios. We care about
|
||||
// what the kernel does, not glibc.
|
||||
#define KERNEL_NCCS 19
|
||||
@@ -376,9 +378,25 @@ PosixErrorOr<size_t> PollAndReadFd(int fd, void* buf, size_t count,
|
||||
return PosixError(ETIMEDOUT, "Poll timed out");
|
||||
}
|
||||
|
||||
TEST(PtyTrunc, Truncate) {
|
||||
// Opening PTYs with O_TRUNC shouldn't cause an error, but calls to
|
||||
// (f)truncate should.
|
||||
FileDescriptor master =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Open(kMasterPath, O_RDWR | O_TRUNC));
|
||||
int n = ASSERT_NO_ERRNO_AND_VALUE(SlaveID(master));
|
||||
std::string spath = absl::StrCat("/dev/pts/", n);
|
||||
FileDescriptor slave =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Open(spath, O_RDWR | O_NONBLOCK | O_TRUNC));
|
||||
|
||||
EXPECT_THAT(truncate(kMasterPath, 0), SyscallFailsWithErrno(EINVAL));
|
||||
EXPECT_THAT(truncate(spath.c_str(), 0), SyscallFailsWithErrno(EINVAL));
|
||||
EXPECT_THAT(ftruncate(master.get(), 0), SyscallFailsWithErrno(EINVAL));
|
||||
EXPECT_THAT(ftruncate(slave.get(), 0), SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST(BasicPtyTest, StatUnopenedMaster) {
|
||||
struct stat s;
|
||||
ASSERT_THAT(stat("/dev/ptmx", &s), SyscallSucceeds());
|
||||
ASSERT_THAT(stat(kMasterPath, &s), SyscallSucceeds());
|
||||
|
||||
EXPECT_EQ(s.st_rdev, makedev(TTYAUX_MAJOR, kPtmxMinor));
|
||||
EXPECT_EQ(s.st_size, 0);
|
||||
|
||||
@@ -24,6 +24,14 @@ namespace gvisor {
|
||||
namespace testing {
|
||||
|
||||
PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master) {
|
||||
PosixErrorOr<int> n = SlaveID(master);
|
||||
if (!n.ok()) {
|
||||
return PosixErrorOr<FileDescriptor>(n.error());
|
||||
}
|
||||
return Open(absl::StrCat("/dev/pts/", n.ValueOrDie()), O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
PosixErrorOr<int> SlaveID(const FileDescriptor& master) {
|
||||
// Get pty index.
|
||||
int n;
|
||||
int ret = ioctl(master.get(), TIOCGPTN, &n);
|
||||
@@ -38,7 +46,7 @@ PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master) {
|
||||
return PosixError(errno, "ioctl(TIOSPTLCK) failed");
|
||||
}
|
||||
|
||||
return Open(absl::StrCat("/dev/pts/", n), O_RDWR | O_NONBLOCK);
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace testing {
|
||||
// Opens the slave end of the passed master as R/W and nonblocking.
|
||||
PosixErrorOr<FileDescriptor> OpenSlave(const FileDescriptor& master);
|
||||
|
||||
// Get the number of the slave end of the master.
|
||||
PosixErrorOr<int> SlaveID(const FileDescriptor& master);
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
|
||||
Reference in New Issue
Block a user