mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Allow open(O_TRUNC) and (f)truncate for proc files.
This allows writable proc and devices files to be opened with O_CREAT|O_TRUNC. This is encountered most frequently when interacting with proc or devices files via the command line. e.g. $ echo 8192 1048576 4194304 > /proc/sys/net/ipv4/tcp_rmem Also adds a test to test the behavior of open(O_TRUNC), truncate, and ftruncate on named pipes. Fixes #1116 PiperOrigin-RevId: 282677425
This commit is contained in:
@@ -64,7 +64,7 @@ var _ fs.InodeOperations = (*tcpMemInode)(nil)
|
||||
|
||||
func newTCPMemInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack, dir tcpMemDir) *fs.Inode {
|
||||
tm := &tcpMemInode{
|
||||
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC),
|
||||
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0644), linux.PROC_SUPER_MAGIC),
|
||||
s: s,
|
||||
dir: dir,
|
||||
}
|
||||
@@ -77,6 +77,11 @@ func newTCPMemInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack, dir
|
||||
return fs.NewInode(ctx, tm, msrc, sattr)
|
||||
}
|
||||
|
||||
// Truncate implements fs.InodeOperations.Truncate.
|
||||
func (tcpMemInode) Truncate(context.Context, *fs.Inode, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
func (m *tcpMemInode) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
flags.Pread = true
|
||||
@@ -168,14 +173,15 @@ func writeSize(dirType tcpMemDir, s inet.Stack, size inet.TCPBufferSize) error {
|
||||
|
||||
// +stateify savable
|
||||
type tcpSack struct {
|
||||
fsutil.SimpleFileInode
|
||||
|
||||
stack inet.Stack `state:"wait"`
|
||||
enabled *bool
|
||||
fsutil.SimpleFileInode
|
||||
}
|
||||
|
||||
func newTCPSackInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack) *fs.Inode {
|
||||
ts := &tcpSack{
|
||||
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC),
|
||||
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0644), linux.PROC_SUPER_MAGIC),
|
||||
stack: s,
|
||||
}
|
||||
sattr := fs.StableAttr{
|
||||
@@ -187,6 +193,11 @@ func newTCPSackInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack) *f
|
||||
return fs.NewInode(ctx, ts, msrc, sattr)
|
||||
}
|
||||
|
||||
// Truncate implements fs.InodeOperations.Truncate.
|
||||
func (tcpSack) Truncate(context.Context, *fs.Inode, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
func (s *tcpSack) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
flags.Pread = true
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
// +stateify savable
|
||||
type masterInodeOperations struct {
|
||||
fsutil.SimpleFileInode
|
||||
fsutil.InodeNoopTruncate
|
||||
|
||||
// d is the containing dir.
|
||||
d *dirInodeOperations
|
||||
@@ -77,6 +76,11 @@ func newMasterInode(ctx context.Context, d *dirInodeOperations, owner fs.FileOwn
|
||||
func (mi *masterInodeOperations) Release(ctx context.Context) {
|
||||
}
|
||||
|
||||
// Truncate implements fs.InodeOperations.Truncate.
|
||||
func (masterInodeOperations) Truncate(context.Context, *fs.Inode, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
//
|
||||
// It allocates a new terminal.
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
// +stateify savable
|
||||
type slaveInodeOperations struct {
|
||||
fsutil.SimpleFileInode
|
||||
fsutil.InodeNoopTruncate
|
||||
|
||||
// d is the containing dir.
|
||||
d *dirInodeOperations
|
||||
@@ -73,6 +72,11 @@ func (si *slaveInodeOperations) Release(ctx context.Context) {
|
||||
si.t.DecRef()
|
||||
}
|
||||
|
||||
// Truncate implements fs.InodeOperations.Truncate.
|
||||
func (slaveInodeOperations) Truncate(context.Context, *fs.Inode, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
//
|
||||
// This may race with destruction of the terminal. If the terminal is gone, it
|
||||
|
||||
@@ -171,6 +171,9 @@ func openAt(t *kernel.Task, dirFD int32, addr usermem.Addr, flags uint) (fd uint
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate is called when O_TRUNC is specified for any kind of
|
||||
// existing Dirent. Behavior is delegated to the entry's Truncate
|
||||
// implementation.
|
||||
if flags&linux.O_TRUNC != 0 {
|
||||
if err := d.Inode.Truncate(t, d, 0); err != nil {
|
||||
return err
|
||||
@@ -397,7 +400,9 @@ func createAt(t *kernel.Task, dirFD int32, addr usermem.Addr, flags uint, mode l
|
||||
return err
|
||||
}
|
||||
|
||||
// Should we truncate the file?
|
||||
// Truncate is called when O_TRUNC is specified for any kind of
|
||||
// existing Dirent. Behavior is delegated to the entry's Truncate
|
||||
// implementation.
|
||||
if flags&linux.O_TRUNC != 0 {
|
||||
if err := found.Inode.Truncate(t, found, 0); err != nil {
|
||||
return err
|
||||
@@ -1484,6 +1489,8 @@ func Truncate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
|
||||
if fs.IsDir(d.Inode.StableAttr) {
|
||||
return syserror.EISDIR
|
||||
}
|
||||
// In contrast to open(O_TRUNC), truncate(2) is only valid for file
|
||||
// types.
|
||||
if !fs.IsFile(d.Inode.StableAttr) {
|
||||
return syserror.EINVAL
|
||||
}
|
||||
@@ -1522,7 +1529,8 @@ func Ftruncate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
|
||||
// Note that this is different from truncate(2) above, where a
|
||||
// In contrast to open(O_TRUNC), truncate(2) is only valid for file
|
||||
// types. Note that this is different from truncate(2) above, where a
|
||||
// directory returns EISDIR.
|
||||
if !fs.IsFile(file.Dirent.Inode.StableAttr) {
|
||||
return 0, nil, syserror.EINVAL
|
||||
|
||||
@@ -212,6 +212,20 @@ TEST(Pipe2Test, BadOptions) {
|
||||
EXPECT_THAT(pipe2(fds, 0xDEAD), SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
// Tests that opening named pipes with O_TRUNC shouldn't cause an error, but
|
||||
// calls to (f)truncate should.
|
||||
TEST(NamedPipeTest, Truncate) {
|
||||
const std::string tmp_path = NewTempAbsPath();
|
||||
SKIP_IF(mkfifo(tmp_path.c_str(), 0644) != 0);
|
||||
|
||||
ASSERT_THAT(open(tmp_path.c_str(), O_NONBLOCK | O_RDONLY), SyscallSucceeds());
|
||||
FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Open(tmp_path.c_str(), O_RDWR | O_NONBLOCK | O_TRUNC));
|
||||
|
||||
ASSERT_THAT(truncate(tmp_path.c_str(), 0), SyscallFailsWithErrno(EINVAL));
|
||||
ASSERT_THAT(ftruncate(fd.get(), 0), SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST_P(PipeTest, Seek) {
|
||||
SKIP_IF(!CreateBlocking());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user