diff options
author | Ian Gudger <igudger@google.com> | 2018-06-21 10:52:33 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-06-21 10:53:21 -0700 |
commit | d571a4359cebbcf8a9b201bb125f1cdc9fb126e4 (patch) | |
tree | 53d993db5ab045897c4ad50bb73670e3f018ffea /pkg/sentry/syscalls | |
parent | f2a687001ded18a4343c1aa3bfba18b08c6a816a (diff) |
Implement ioctl(FIOASYNC)
FIOASYNC and friends are used to send signals when a file is ready for IO.
This may or may not be needed by Nginx. While Nginx does use it, it is unclear
if the code that uses it has any effect.
PiperOrigin-RevId: 201550828
Change-Id: I7ba05a7db4eb2dfffde11e9bd9a35b65b98d7f50
Diffstat (limited to 'pkg/sentry/syscalls')
-rw-r--r-- | pkg/sentry/syscalls/linux/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/flags.go | 5 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_file.go | 78 |
3 files changed, 78 insertions, 6 deletions
diff --git a/pkg/sentry/syscalls/linux/BUILD b/pkg/sentry/syscalls/linux/BUILD index 7cfd37fb1..d3f3cc459 100644 --- a/pkg/sentry/syscalls/linux/BUILD +++ b/pkg/sentry/syscalls/linux/BUILD @@ -82,6 +82,7 @@ go_library( "//pkg/sentry/kernel/auth", "//pkg/sentry/kernel/epoll", "//pkg/sentry/kernel/eventfd", + "//pkg/sentry/kernel/fasync", "//pkg/sentry/kernel/kdefs", "//pkg/sentry/kernel/pipe", "//pkg/sentry/kernel/sched", diff --git a/pkg/sentry/syscalls/linux/flags.go b/pkg/sentry/syscalls/linux/flags.go index 82bfd7c2a..3d39a20f4 100644 --- a/pkg/sentry/syscalls/linux/flags.go +++ b/pkg/sentry/syscalls/linux/flags.go @@ -61,6 +61,9 @@ func flagsToLinux(flags fs.FileFlags) (mask uint) { if flags.Directory { mask |= syscall.O_DIRECTORY } + if flags.Async { + mask |= syscall.O_ASYNC + } switch { case flags.Read && flags.Write: mask |= syscall.O_RDWR @@ -82,6 +85,7 @@ func linuxToFlags(mask uint) (flags fs.FileFlags) { Write: (mask & syscall.O_ACCMODE) != syscall.O_RDONLY, Append: mask&syscall.O_APPEND != 0, Directory: mask&syscall.O_DIRECTORY != 0, + Async: mask&syscall.O_ASYNC != 0, } } @@ -91,5 +95,6 @@ func linuxToSettableFlags(mask uint) fs.SettableFileFlags { Direct: mask&syscall.O_DIRECT != 0, NonBlocking: mask&syscall.O_NONBLOCK != 0, Append: mask&syscall.O_APPEND != 0, + Async: mask&syscall.O_ASYNC != 0, } } diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index e2980842f..490649f87 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -25,6 +25,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/fs/lock" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/fasync" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time" "gvisor.googlesource.com/gvisor/pkg/sentry/limits" @@ -528,6 +529,33 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall file.SetFlags(flags.Settable()) return 0, nil, nil + case linux.FIOASYNC: + var set int32 + if _, err := t.CopyIn(args[2].Pointer(), &set); err != nil { + return 0, nil, err + } + flags := file.Flags() + if set != 0 { + flags.Async = true + } else { + flags.Async = false + } + file.SetFlags(flags.Settable()) + return 0, nil, nil + + case linux.FIOSETOWN, linux.SIOCSPGRP: + var set int32 + if _, err := t.CopyIn(args[2].Pointer(), &set); err != nil { + return 0, nil, err + } + fSetOwn(t, file, set) + return 0, nil, nil + + case linux.FIOGETOWN, linux.SIOCGPGRP: + who := fGetOwn(t, file) + _, err := t.CopyOut(args[2].Pointer(), &who) + return 0, nil, err + default: ret, err := file.FileOperations.Ioctl(t, t.MemoryManager(), args) if err != nil { @@ -725,6 +753,39 @@ func Dup3(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC return uintptr(newfd), nil, nil } +func fGetOwn(t *kernel.Task, file *fs.File) int32 { + ma := file.Async(nil) + if ma == nil { + return 0 + } + a := ma.(*fasync.FileAsync) + ot, otg, opg := a.Owner() + switch { + case ot != nil: + return int32(t.PIDNamespace().IDOfTask(ot)) + case otg != nil: + return int32(t.PIDNamespace().IDOfThreadGroup(otg)) + case opg != nil: + return int32(-t.PIDNamespace().IDOfProcessGroup(opg)) + default: + return 0 + } +} + +// fSetOwn sets the file's owner with the semantics of F_SETOWN in Linux. +// +// If who is positive, it represents a PID. If negative, it represents a PGID. +// If the PID or PGID is invalid, the owner is silently unset. +func fSetOwn(t *kernel.Task, file *fs.File, who int32) { + a := file.Async(fasync.New).(*fasync.FileAsync) + if who < 0 { + pg := t.PIDNamespace().ProcessGroupWithID(kernel.ProcessGroupID(-who)) + a.SetOwnerProcessGroup(t, pg) + } + tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(who)) + a.SetOwnerThreadGroup(t, tg) +} + // Fcntl implements linux syscall fcntl(2). func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { fd := kdefs.FD(args[0].Int()) @@ -737,7 +798,7 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall defer file.DecRef() switch cmd { - case syscall.F_DUPFD, syscall.F_DUPFD_CLOEXEC: + case linux.F_DUPFD, linux.F_DUPFD_CLOEXEC: from := kdefs.FD(args[2].Int()) fdFlags := kernel.FDFlags{CloseOnExec: cmd == syscall.F_DUPFD_CLOEXEC} fd, err := t.FDMap().NewFDFrom(from, file, fdFlags, t.ThreadGroup().Limits()) @@ -745,19 +806,19 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall return 0, nil, err } return uintptr(fd), nil, nil - case syscall.F_GETFD: + case linux.F_GETFD: return uintptr(fdFlagsToLinux(flags)), nil, nil - case syscall.F_SETFD: + case linux.F_SETFD: flags := args[2].Uint() t.FDMap().SetFlags(fd, kernel.FDFlags{ CloseOnExec: flags&syscall.FD_CLOEXEC != 0, }) - case syscall.F_GETFL: + case linux.F_GETFL: return uintptr(flagsToLinux(file.Flags())), nil, nil - case syscall.F_SETFL: + case linux.F_SETFL: flags := uint(args[2].Uint()) file.SetFlags(linuxToSettableFlags(flags)) - case syscall.F_SETLK, syscall.F_SETLKW: + case linux.F_SETLK, linux.F_SETLKW: // In Linux the file system can choose to provide lock operations for an inode. // Normally pipe and socket types lack lock operations. We diverge and use a heavy // hammer by only allowing locks on files and directories. @@ -854,6 +915,11 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall default: return 0, nil, syserror.EINVAL } + case linux.F_GETOWN: + return uintptr(fGetOwn(t, file)), nil, nil + case linux.F_SETOWN: + fSetOwn(t, file, args[2].Int()) + return 0, nil, nil default: // Everything else is not yet supported. return 0, nil, syserror.EINVAL |