Skip to content

Commit 1f42bcd

Browse files
fvoznikagvisor-bot
authored andcommitted
Complete pipe support on overlayfs
Get/Set pipe size and ioctl support were missing from overlayfs. It required moving the pipe.Sizer interface to fs so that overlay could get access. Fixes #318 PiperOrigin-RevId: 255000716
1 parent 03ae91c commit 1f42bcd

File tree

19 files changed

+87
-44
lines changed

19 files changed

+87
-44
lines changed

pkg/sentry/fs/ashmem/area.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func (a *Area) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MM
139139
}
140140

141141
// Ioctl implements fs.FileOperations.Ioctl.
142-
func (a *Area) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
142+
func (a *Area) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
143143
// Switch on ioctl request.
144144
switch args[1].Uint() {
145145
case linux.AshmemSetNameIoctl:

pkg/sentry/fs/binder/binder.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (bp *Proc) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.M
162162
// Ioctl implements fs.FileOperations.Ioctl.
163163
//
164164
// TODO(b/30946773): Implement.
165-
func (bp *Proc) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
165+
func (bp *Proc) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
166166
// Switch on ioctl request.
167167
switch uint32(args[1].Int()) {
168168
case linux.BinderVersionIoctl:

pkg/sentry/fs/file_operations.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -155,5 +155,16 @@ type FileOperations interface {
155155
// refer.
156156
//
157157
// Preconditions: The AddressSpace (if any) that io refers to is activated.
158-
Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error)
158+
Ioctl(ctx context.Context, file *File, io usermem.IO, args arch.SyscallArguments) (uintptr, error)
159+
}
160+
161+
// FifoSizer is an interface for setting and getting the size of a pipe.
162+
type FifoSizer interface {
163+
// FifoSize returns the pipe capacity in bytes.
164+
FifoSize(ctx context.Context, file *File) (int64, error)
165+
166+
// SetFifoSize sets the new pipe capacity in bytes.
167+
//
168+
// The new size is returned (which may be capped).
169+
SetFifoSize(ctx context.Context, file *File, size int64) (int64, error)
159170
}

pkg/sentry/fs/file_overlay.go

+45-3
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,51 @@ func (f *overlayFileOperations) UnstableAttr(ctx context.Context, file *File) (U
388388
return f.lower.UnstableAttr(ctx)
389389
}
390390

391-
// Ioctl implements fs.FileOperations.Ioctl and always returns ENOTTY.
392-
func (*overlayFileOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
393-
return 0, syserror.ENOTTY
391+
// Ioctl implements fs.FileOperations.Ioctl.
392+
func (f *overlayFileOperations) Ioctl(ctx context.Context, file *File, io usermem.IO, args arch.SyscallArguments) (rv uintptr, err error) {
393+
err = f.onTop(ctx, file, func(file *File, ops FileOperations) error {
394+
if f.upper != nil {
395+
rv, err = f.upper.FileOperations.Ioctl(ctx, file, io, args)
396+
return err
397+
}
398+
rv, err = f.lower.FileOperations.Ioctl(ctx, file, io, args)
399+
return err
400+
})
401+
return
402+
}
403+
404+
// FifoSize implements FifoSizer.FifoSize.
405+
func (f *overlayFileOperations) FifoSize(ctx context.Context, file *File) (rv int64, err error) {
406+
err = f.onTop(ctx, file, func(file *File, ops FileOperations) error {
407+
layer := f.upper
408+
if layer == nil {
409+
layer = f.lower
410+
}
411+
sz, ok := layer.FileOperations.(FifoSizer)
412+
if !ok {
413+
return syserror.EINVAL
414+
}
415+
rv, err = sz.FifoSize(ctx, file)
416+
return err
417+
})
418+
return
419+
}
420+
421+
// SetFifoSize implements FifoSizer.SetFifoSize.
422+
func (f *overlayFileOperations) SetFifoSize(ctx context.Context, file *File, size int64) (rv int64, err error) {
423+
err = f.onTop(ctx, file, func(file *File, ops FileOperations) error {
424+
layer := f.upper
425+
if layer == nil {
426+
layer = f.lower
427+
}
428+
sz, ok := layer.FileOperations.(FifoSizer)
429+
if !ok {
430+
return syserror.EINVAL
431+
}
432+
rv, err = sz.SetFifoSize(ctx, file, size)
433+
return err
434+
})
435+
return
394436
}
395437

396438
// readdirEntries returns a sorted map of directory entries from the

pkg/sentry/fs/fsutil/file.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func GenericConfigureMMap(file *fs.File, m memmap.Mappable, opts *memmap.MMapOpt
219219
type FileNoIoctl struct{}
220220

221221
// Ioctl implements fs.FileOperations.Ioctl.
222-
func (FileNoIoctl) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
222+
func (FileNoIoctl) Ioctl(context.Context, *fs.File, usermem.IO, arch.SyscallArguments) (uintptr, error) {
223223
return 0, syserror.ENOTTY
224224
}
225225

pkg/sentry/fs/host/tty.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (t *TTYFileOperations) Release() {
114114
}
115115

116116
// Ioctl implements fs.FileOperations.Ioctl.
117-
func (t *TTYFileOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
117+
func (t *TTYFileOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
118118
// Ignore arg[0]. This is the real FD:
119119
fd := t.fileOperations.iops.fileState.FD()
120120
ioctl := args[1].Uint64()

pkg/sentry/fs/inotify.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (i *Inotify) UnstableAttr(ctx context.Context, file *File) (UnstableAttr, e
202202
}
203203

204204
// Ioctl implements fs.FileOperations.Ioctl.
205-
func (i *Inotify) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
205+
func (i *Inotify) Ioctl(ctx context.Context, _ *File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
206206
switch args[1].Int() {
207207
case linux.FIONREAD:
208208
i.evMu.Lock()

pkg/sentry/fs/tty/master.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func (mf *masterFileOperations) Write(ctx context.Context, _ *fs.File, src userm
144144
}
145145

146146
// Ioctl implements fs.FileOperations.Ioctl.
147-
func (mf *masterFileOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
147+
func (mf *masterFileOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
148148
switch cmd := args[1].Uint(); cmd {
149149
case linux.FIONREAD: // linux.FIONREAD == linux.TIOCINQ
150150
// Get the number of bytes in the output queue read buffer.

pkg/sentry/fs/tty/slave.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (sf *slaveFileOperations) Write(ctx context.Context, _ *fs.File, src userme
128128
}
129129

130130
// Ioctl implements fs.FileOperations.Ioctl.
131-
func (sf *slaveFileOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
131+
func (sf *slaveFileOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
132132
switch cmd := args[1].Uint(); cmd {
133133
case linux.FIONREAD: // linux.FIONREAD == linux.TIOCINQ
134134
// Get the number of bytes in the input queue read buffer.

pkg/sentry/kernel/pipe/pipe.go

+5-18
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,6 @@ const (
3939
MaximumPipeSize = 8 << 20
4040
)
4141

42-
// Sizer is an interface for setting and getting the size of a pipe.
43-
//
44-
// It is implemented by Pipe and, through embedding, all other types.
45-
type Sizer interface {
46-
// PipeSize returns the pipe capacity in bytes.
47-
PipeSize() int64
48-
49-
// SetPipeSize sets the new pipe capacity in bytes.
50-
//
51-
// The new size is returned (which may be capped).
52-
SetPipeSize(int64) (int64, error)
53-
}
54-
5542
// Pipe is an encapsulation of a platform-independent pipe.
5643
// It manages a buffered byte queue shared between a reader/writer
5744
// pair.
@@ -399,15 +386,15 @@ func (p *Pipe) queued() int64 {
399386
return p.size
400387
}
401388

402-
// PipeSize implements PipeSizer.PipeSize.
403-
func (p *Pipe) PipeSize() int64 {
389+
// FifoSize implements fs.FifoSizer.FifoSize.
390+
func (p *Pipe) FifoSize(context.Context, *fs.File) (int64, error) {
404391
p.mu.Lock()
405392
defer p.mu.Unlock()
406-
return p.max
393+
return p.max, nil
407394
}
408395

409-
// SetPipeSize implements PipeSize.SetPipeSize.
410-
func (p *Pipe) SetPipeSize(size int64) (int64, error) {
396+
// SetFifoSize implements fs.FifoSizer.SetFifoSize.
397+
func (p *Pipe) SetFifoSize(_ context.Context, _ *fs.File, size int64) (int64, error) {
411398
if size < 0 {
412399
return 0, syserror.EINVAL
413400
}

pkg/sentry/kernel/pipe/reader_writer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (rw *ReaderWriter) Readiness(mask waiter.EventMask) waiter.EventMask {
7777
}
7878

7979
// Ioctl implements fs.FileOperations.Ioctl.
80-
func (rw *ReaderWriter) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
80+
func (rw *ReaderWriter) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
8181
// Switch on ioctl request.
8282
switch int(args[1].Int()) {
8383
case linux.FIONREAD:

pkg/sentry/socket/epsocket/epsocket.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,7 @@ func (s *SocketOperations) SendMsg(t *kernel.Task, src usermem.IOSequence, to []
19931993
}
19941994

19951995
// Ioctl implements fs.FileOperations.Ioctl.
1996-
func (s *SocketOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
1996+
func (s *SocketOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
19971997
// SIOCGSTAMP is implemented by epsocket rather than all commonEndpoint
19981998
// sockets.
19991999
// TODO(b/78348848): Add a commonEndpoint method to support SIOCGSTAMP.

pkg/sentry/socket/hostinet/socket_unsafe.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"gvisor.dev/gvisor/pkg/sentry/arch"
2222
"gvisor.dev/gvisor/pkg/sentry/context"
23+
"gvisor.dev/gvisor/pkg/sentry/fs"
2324
"gvisor.dev/gvisor/pkg/sentry/kernel"
2425
"gvisor.dev/gvisor/pkg/sentry/usermem"
2526
"gvisor.dev/gvisor/pkg/syserr"
@@ -52,7 +53,7 @@ func writev(fd int, srcs []syscall.Iovec) (uint64, error) {
5253
}
5354

5455
// Ioctl implements fs.FileOperations.Ioctl.
55-
func (s *socketOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
56+
func (s *socketOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
5657
switch cmd := uintptr(args[1].Int()); cmd {
5758
case syscall.TIOCINQ, syscall.TIOCOUTQ:
5859
var val int32

pkg/sentry/socket/netlink/socket.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (s *Socket) EventUnregister(e *waiter.Entry) {
173173
}
174174

175175
// Ioctl implements fs.FileOperations.Ioctl.
176-
func (s *Socket) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
176+
func (*Socket) Ioctl(context.Context, *fs.File, usermem.IO, arch.SyscallArguments) (uintptr, error) {
177177
// TODO(b/68878065): no ioctls supported.
178178
return 0, syserror.ENOTTY
179179
}

pkg/sentry/socket/rpcinet/socket.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ func ifconfIoctlFromStack(ctx context.Context, io usermem.IO, ifc *linux.IFConf)
564564
}
565565

566566
// Ioctl implements fs.FileOperations.Ioctl.
567-
func (s *socketOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
567+
func (s *socketOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
568568
t := ctx.(*kernel.Task)
569569

570570
cmd := uint32(args[1].Int())

pkg/sentry/socket/unix/unix.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (s *SocketOperations) GetSockName(t *kernel.Task) (interface{}, uint32, *sy
152152
}
153153

154154
// Ioctl implements fs.FileOperations.Ioctl.
155-
func (s *SocketOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
155+
func (s *SocketOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
156156
return epsocket.Ioctl(ctx, s.ep, io, args)
157157
}
158158

pkg/sentry/syscalls/linux/sys_file.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
2828
"gvisor.dev/gvisor/pkg/sentry/kernel/fasync"
2929
"gvisor.dev/gvisor/pkg/sentry/kernel/kdefs"
30-
"gvisor.dev/gvisor/pkg/sentry/kernel/pipe"
3130
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
3231
"gvisor.dev/gvisor/pkg/sentry/limits"
3332
"gvisor.dev/gvisor/pkg/sentry/usermem"
@@ -571,7 +570,7 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
571570
return 0, nil, err
572571

573572
default:
574-
ret, err := file.FileOperations.Ioctl(t, t.MemoryManager(), args)
573+
ret, err := file.FileOperations.Ioctl(t, file, t.MemoryManager(), args)
575574
if err != nil {
576575
return 0, nil, err
577576
}
@@ -944,17 +943,18 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
944943
err := tmpfs.AddSeals(file.Dirent.Inode, args[2].Uint())
945944
return 0, nil, err
946945
case linux.F_GETPIPE_SZ:
947-
sz, ok := file.FileOperations.(pipe.Sizer)
946+
sz, ok := file.FileOperations.(fs.FifoSizer)
948947
if !ok {
949948
return 0, nil, syserror.EINVAL
950949
}
951-
return uintptr(sz.PipeSize()), nil, nil
950+
size, err := sz.FifoSize(t, file)
951+
return uintptr(size), nil, err
952952
case linux.F_SETPIPE_SZ:
953-
sz, ok := file.FileOperations.(pipe.Sizer)
953+
sz, ok := file.FileOperations.(fs.FifoSizer)
954954
if !ok {
955955
return 0, nil, syserror.EINVAL
956956
}
957-
n, err := sz.SetPipeSize(int64(args[2].Int()))
957+
n, err := sz.SetFifoSize(t, file, int64(args[2].Int()))
958958
return uintptr(n), nil, err
959959
default:
960960
// Everything else is not yet supported.

test/syscalls/BUILD

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ syscall_test(test = "//test/syscalls/linux:pause_test")
255255

256256
syscall_test(
257257
size = "large",
258-
add_overlay = False, # TODO(gvisor.dev/issue/318): enable when fixed.
258+
add_overlay = True,
259259
shard_count = 5,
260260
test = "//test/syscalls/linux:pipe_test",
261261
)

test/syscalls/linux/pipe.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,13 @@ TEST_P(PipeTest, BlockPartialWriteClosed) {
339339
SKIP_IF(!CreateBlocking());
340340

341341
ScopedThread t([this]() {
342-
std::vector<char> buf(2 * Size());
342+
const int pipe_size = Size();
343+
std::vector<char> buf(2 * pipe_size);
344+
343345
// Write more than fits in the buffer. Blocks then returns partial write
344346
// when the other end is closed. The next call returns EPIPE.
345347
ASSERT_THAT(write(wfd_.get(), buf.data(), buf.size()),
346-
SyscallSucceedsWithValue(Size()));
348+
SyscallSucceedsWithValue(pipe_size));
347349
EXPECT_THAT(write(wfd_.get(), buf.data(), buf.size()),
348350
SyscallFailsWithErrno(EPIPE));
349351
});

0 commit comments

Comments
 (0)