Delete VFS1 syscall handlers.

Directly use VFS2 syscall handlers. No need to override VFS2 handlers.
Updates #1624

PiperOrigin-RevId: 488448348
This commit is contained in:
Ayush Ranjan
2022-11-14 13:11:22 -08:00
committed by gVisor bot
parent cf13339a6e
commit ed35016d99
65 changed files with 3044 additions and 11490 deletions
-4
View File
@@ -5,7 +5,6 @@ package(licenses = ["notice"])
go_library(
name = "syscalls",
srcs = [
"epoll.go",
"syscalls.go",
],
visibility = ["//:sandbox"],
@@ -14,8 +13,5 @@ go_library(
"//pkg/errors/linuxerr",
"//pkg/sentry/arch",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/epoll",
"//pkg/sentry/kernel/time",
"//pkg/waiter",
],
)
-173
View File
@@ -1,173 +0,0 @@
// Copyright 2018 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.
package syscalls
import (
"time"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/epoll"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/waiter"
)
// CreateEpoll implements the epoll_create(2) linux syscall.
func CreateEpoll(t *kernel.Task, closeOnExec bool) (int32, error) {
file := epoll.NewEventPoll(t)
defer file.DecRef(t)
fd, err := t.NewFDFrom(0, file, kernel.FDFlags{
CloseOnExec: closeOnExec,
})
if err != nil {
return 0, err
}
return fd, nil
}
// AddEpoll implements the epoll_ctl(2) linux syscall when op is EPOLL_CTL_ADD.
func AddEpoll(t *kernel.Task, epfd int32, fd int32, flags epoll.EntryFlags, mask waiter.EventMask, userData [2]int32) error {
// Get epoll from the file descriptor.
epollfile := t.GetFile(epfd)
if epollfile == nil {
return linuxerr.EBADF
}
defer epollfile.DecRef(t)
// Get the target file id.
file := t.GetFile(fd)
if file == nil {
return linuxerr.EBADF
}
defer file.DecRef(t)
// Extract the epollPoll operations.
e, ok := epollfile.FileOperations.(*epoll.EventPoll)
if !ok {
return linuxerr.EBADF
}
// Try to add the entry.
return e.AddEntry(epoll.FileIdentifier{file, fd}, flags, mask, userData)
}
// UpdateEpoll implements the epoll_ctl(2) linux syscall when op is EPOLL_CTL_MOD.
func UpdateEpoll(t *kernel.Task, epfd int32, fd int32, flags epoll.EntryFlags, mask waiter.EventMask, userData [2]int32) error {
// Get epoll from the file descriptor.
epollfile := t.GetFile(epfd)
if epollfile == nil {
return linuxerr.EBADF
}
defer epollfile.DecRef(t)
// Get the target file id.
file := t.GetFile(fd)
if file == nil {
return linuxerr.EBADF
}
defer file.DecRef(t)
// Extract the epollPoll operations.
e, ok := epollfile.FileOperations.(*epoll.EventPoll)
if !ok {
return linuxerr.EBADF
}
// Try to update the entry.
return e.UpdateEntry(epoll.FileIdentifier{file, fd}, flags, mask, userData)
}
// RemoveEpoll implements the epoll_ctl(2) linux syscall when op is EPOLL_CTL_DEL.
func RemoveEpoll(t *kernel.Task, epfd int32, fd int32) error {
// Get epoll from the file descriptor.
epollfile := t.GetFile(epfd)
if epollfile == nil {
return linuxerr.EBADF
}
defer epollfile.DecRef(t)
// Get the target file id.
file := t.GetFile(fd)
if file == nil {
return linuxerr.EBADF
}
defer file.DecRef(t)
// Extract the epollPoll operations.
e, ok := epollfile.FileOperations.(*epoll.EventPoll)
if !ok {
return linuxerr.EBADF
}
// Try to remove the entry.
return e.RemoveEntry(t, epoll.FileIdentifier{file, fd})
}
// WaitEpoll implements the epoll_wait(2) linux syscall.
func WaitEpoll(t *kernel.Task, fd int32, max int, timeoutInNanos int64) ([]linux.EpollEvent, error) {
// Get epoll from the file descriptor.
epollfile := t.GetFile(fd)
if epollfile == nil {
return nil, linuxerr.EBADF
}
defer epollfile.DecRef(t)
// Extract the epollPoll operations.
e, ok := epollfile.FileOperations.(*epoll.EventPoll)
if !ok {
return nil, linuxerr.EBADF
}
// Try to read events and return right away if we got them or if the
// caller requested a non-blocking "wait".
r := e.ReadEvents(max)
if len(r) != 0 || timeoutInNanos == 0 {
return r, nil
}
// We'll have to wait. Set up the timer if a timeout was specified and
// and register with the epoll object for readability events.
var haveDeadline bool
var deadline ktime.Time
if timeoutInNanos > 0 {
timeoutDur := time.Duration(timeoutInNanos) * time.Nanosecond
deadline = t.Kernel().MonotonicClock().Now().Add(timeoutDur)
haveDeadline = true
}
w, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
e.EventRegister(&w)
defer e.EventUnregister(&w)
// Try to read the events again until we succeed, timeout or get
// interrupted.
for {
r = e.ReadEvents(max)
if len(r) != 0 {
return r, nil
}
if err := t.BlockWithDeadline(ch, haveDeadline, deadline); err != nil {
if linuxerr.Equals(linuxerr.ETIMEDOUT, err) {
return nil, nil
}
return nil, err
}
}
}
+16 -11
View File
@@ -6,8 +6,8 @@ go_library(
name = "linux",
srcs = [
"error.go",
"flags.go",
"linux64.go",
"path.go",
"points.go",
"sigset.go",
"sys_aio.go",
@@ -21,17 +21,19 @@ go_library(
"sys_getdents.go",
"sys_identity.go",
"sys_inotify.go",
"sys_lseek.go",
"sys_iouring.go",
"sys_membarrier.go",
"sys_mempolicy.go",
"sys_mmap.go",
"sys_mount.go",
"sys_mq.go",
"sys_msgqueue.go",
"sys_pipe.go",
"sys_poll.go",
"sys_prctl.go",
"sys_process_vm.go",
"sys_random.go",
"sys_read.go",
"sys_read_write.go",
"sys_rlimit.go",
"sys_rseq.go",
"sys_rusage.go",
@@ -55,7 +57,6 @@ go_library(
"sys_tls_amd64.go",
"sys_tls_arm64.go",
"sys_utsname.go",
"sys_write.go",
"sys_xattr.go",
"timespec.go",
],
@@ -64,9 +65,12 @@ go_library(
deps = [
"//pkg/abi",
"//pkg/abi/linux",
"//pkg/bits",
"//pkg/bpf",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fspath",
"//pkg/gohacks",
"//pkg/hostarch",
"//pkg/log",
"//pkg/marshal",
@@ -75,23 +79,24 @@ go_library(
"//pkg/rand",
"//pkg/safemem",
"//pkg/sentry/arch",
"//pkg/sentry/fs",
"//pkg/sentry/fs/anon",
"//pkg/sentry/fs/lock",
"//pkg/sentry/fs/timerfd",
"//pkg/sentry/fs/tmpfs",
"//pkg/sentry/fsbridge",
"//pkg/sentry/fsimpl/eventfd",
"//pkg/sentry/fsimpl/host",
"//pkg/sentry/fsimpl/iouringfs",
"//pkg/sentry/fsimpl/pipefs",
"//pkg/sentry/fsimpl/signalfd",
"//pkg/sentry/fsimpl/timerfd",
"//pkg/sentry/fsimpl/tmpfs",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/epoll",
"//pkg/sentry/kernel/eventfd",
"//pkg/sentry/kernel/fasync",
"//pkg/sentry/kernel/ipc",
"//pkg/sentry/kernel/mq",
"//pkg/sentry/kernel/msgqueue",
"//pkg/sentry/kernel/pipe",
"//pkg/sentry/kernel/sched",
"//pkg/sentry/kernel/shm",
"//pkg/sentry/kernel/signalfd",
"//pkg/sentry/kernel/time",
"//pkg/sentry/limits",
"//pkg/sentry/loader",
+2 -21
View File
@@ -22,7 +22,6 @@ import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/metric"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/sync"
@@ -40,11 +39,11 @@ func incrementPartialResultMetric() {
metric.WeirdnessMetric.Increment("partial_result")
}
// HandleIOErrorVFS2 handles special error cases for partial results. For some
// HandleIOError handles special error cases for partial results. For some
// errors, we may consume the error and return only the partial read/write.
//
// op and f are used only for panics.
func HandleIOErrorVFS2(ctx context.Context, partialResult bool, ioerr, intr error, op string, f *vfs.FileDescription) error {
func HandleIOError(ctx context.Context, partialResult bool, ioerr, intr error, op string, f *vfs.FileDescription) error {
known, err := handleIOErrorImpl(ctx, partialResult, ioerr, intr, op)
if err != nil {
return err
@@ -60,24 +59,6 @@ func HandleIOErrorVFS2(ctx context.Context, partialResult bool, ioerr, intr erro
return nil
}
// handleIOError handles special error cases for partial results. For some
// errors, we may consume the error and return only the partial read/write.
//
// op and f are used only for panics.
func handleIOError(ctx context.Context, partialResult bool, ioerr, intr error, op string, f *fs.File) error {
known, err := handleIOErrorImpl(ctx, partialResult, ioerr, intr, op)
if err != nil {
return err
}
if !known {
// An unknown error is encountered with a partial read/write.
name, _ := f.Dirent.FullName(nil /* ignore chroot */)
log.Traceback("Invalid request partialResult %v and err (type %T) %v for %s operation on %q, %T", partialResult, ioerr, ioerr, op, name, f.FileOperations)
partialResultOnce.Do(incrementPartialResultMetric)
}
return nil
}
// handleIOError handles special error cases for partial results. For some
// errors, we may consume the error and return only the partial read/write.
//
-55
View File
@@ -1,55 +0,0 @@
// Copyright 2018 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.
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/fs"
)
// flagsToPermissions returns a Permissions object from Linux flags.
// This includes truncate permission if O_TRUNC is set in the mask.
func flagsToPermissions(mask uint) (p fs.PermMask) {
if mask&linux.O_TRUNC != 0 {
p.Write = true
}
switch mask & linux.O_ACCMODE {
case linux.O_WRONLY:
p.Write = true
case linux.O_RDWR:
p.Write = true
p.Read = true
case linux.O_RDONLY:
p.Read = true
}
return
}
// linuxToFlags converts Linux file flags to a FileFlags object.
func linuxToFlags(mask uint) fs.FileFlags {
return fs.FileFlags{
Direct: mask&linux.O_DIRECT != 0,
DSync: mask&(linux.O_DSYNC|linux.O_SYNC) != 0,
Sync: mask&linux.O_SYNC != 0,
NonBlocking: mask&linux.O_NONBLOCK != 0,
Read: (mask & linux.O_ACCMODE) != linux.O_WRONLY,
Write: (mask & linux.O_ACCMODE) != linux.O_RDONLY,
Append: mask&linux.O_APPEND != 0,
Directory: mask&linux.O_DIRECTORY != 0,
Async: mask&linux.O_ASYNC != 0,
LargeFile: mask&linux.O_LARGEFILE != 0,
Truncate: mask&linux.O_TRUNC != 0,
}
}
+105 -103
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package linux provides syscall tables for amd64 Linux.
// Package linux provides syscall tables for amd64 and arm64 Linux.
package linux
import (
@@ -54,21 +54,21 @@ var AMD64 = &kernel.SyscallTable{
Table: map[uintptr]kernel.Syscall{
0: syscalls.SupportedPoint("read", Read, PointRead),
1: syscalls.Supported("write", Write),
2: syscalls.PartiallySupportedPoint("open", Open, PointOpen, "Options O_DIRECT, O_NOATIME, O_PATH, O_TMPFILE, O_SYNC are not supported.", nil),
3: syscalls.Supported("close", Close),
2: syscalls.SupportedPoint("open", Open, PointOpen),
3: syscalls.SupportedPoint("close", Close, PointClose),
4: syscalls.Supported("stat", Stat),
5: syscalls.Supported("fstat", Fstat),
6: syscalls.Supported("lstat", Lstat),
7: syscalls.Supported("poll", Poll),
8: syscalls.Supported("lseek", Lseek),
9: syscalls.PartiallySupported("mmap", Mmap, "Generally supported with exceptions. Options MAP_FIXED_NOREPLACE, MAP_SHARED_VALIDATE, MAP_SYNC MAP_GROWSDOWN, MAP_HUGETLB are not supported.", nil),
9: syscalls.Supported("mmap", Mmap),
10: syscalls.Supported("mprotect", Mprotect),
11: syscalls.Supported("munmap", Munmap),
12: syscalls.Supported("brk", Brk),
13: syscalls.Supported("rt_sigaction", RtSigaction),
14: syscalls.Supported("rt_sigprocmask", RtSigprocmask),
15: syscalls.Supported("rt_sigreturn", RtSigreturn),
16: syscalls.PartiallySupported("ioctl", Ioctl, "Only a few ioctls are implemented for backing devices and file systems.", nil),
16: syscalls.Supported("ioctl", Ioctl),
17: syscalls.Supported("pread64", Pread64),
18: syscalls.Supported("pwrite64", Pwrite64),
19: syscalls.Supported("readv", Readv),
@@ -93,21 +93,21 @@ var AMD64 = &kernel.SyscallTable{
38: syscalls.Supported("setitimer", Setitimer),
39: syscalls.Supported("getpid", Getpid),
40: syscalls.Supported("sendfile", Sendfile),
41: syscalls.PartiallySupported("socket", Socket, "Limited support for AF_NETLINK, NETLINK_ROUTE sockets. Limited support for SOCK_RAW.", nil),
41: syscalls.SupportedPoint("socket", Socket, PointSocket),
42: syscalls.SupportedPoint("connect", Connect, PointConnect),
43: syscalls.SupportedPoint("accept", Accept, PointAccept),
44: syscalls.Supported("sendto", SendTo),
45: syscalls.Supported("recvfrom", RecvFrom),
46: syscalls.Supported("sendmsg", SendMsg),
47: syscalls.PartiallySupported("recvmsg", RecvMsg, "Not all flags and control messages are supported.", nil),
48: syscalls.PartiallySupported("shutdown", Shutdown, "Not all flags and control messages are supported.", nil),
49: syscalls.PartiallySupportedPoint("bind", Bind, PointBind, "Autobind for abstract Unix sockets is not supported.", nil),
47: syscalls.Supported("recvmsg", RecvMsg),
48: syscalls.Supported("shutdown", Shutdown),
49: syscalls.SupportedPoint("bind", Bind, PointBind),
50: syscalls.Supported("listen", Listen),
51: syscalls.Supported("getsockname", GetSockName),
52: syscalls.Supported("getpeername", GetPeerName),
53: syscalls.SupportedPoint("socketpair", SocketPair, PointSocketpair),
54: syscalls.PartiallySupported("setsockopt", SetSockOpt, "Not all socket options are supported.", nil),
55: syscalls.PartiallySupported("getsockopt", GetSockOpt, "Not all socket options are supported.", nil),
54: syscalls.Supported("setsockopt", SetSockOpt),
55: syscalls.Supported("getsockopt", GetSockOpt),
56: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil),
57: syscalls.SupportedPoint("fork", Fork, PointFork),
58: syscalls.SupportedPoint("vfork", Vfork, PointVfork),
@@ -124,10 +124,10 @@ var AMD64 = &kernel.SyscallTable{
69: syscalls.Supported("msgsnd", Msgsnd),
70: syscalls.Supported("msgrcv", Msgrcv),
71: syscalls.Supported("msgctl", Msgctl),
72: syscalls.PartiallySupportedPoint("fcntl", Fcntl, PointFcntl, "Not all options are supported.", nil),
73: syscalls.PartiallySupported("flock", Flock, "Locks are held within the sandbox only.", nil),
74: syscalls.PartiallySupported("fsync", Fsync, "Full data flush is not guaranteed at this time.", nil),
75: syscalls.PartiallySupported("fdatasync", Fdatasync, "Full data flush is not guaranteed at this time.", nil),
72: syscalls.SupportedPoint("fcntl", Fcntl, PointFcntl),
73: syscalls.Supported("flock", Flock),
74: syscalls.Supported("fsync", Fsync),
75: syscalls.Supported("fdatasync", Fdatasync),
76: syscalls.Supported("truncate", Truncate),
77: syscalls.Supported("ftruncate", Ftruncate),
78: syscalls.Supported("getdents", Getdents),
@@ -137,13 +137,13 @@ var AMD64 = &kernel.SyscallTable{
82: syscalls.Supported("rename", Rename),
83: syscalls.Supported("mkdir", Mkdir),
84: syscalls.Supported("rmdir", Rmdir),
85: syscalls.Supported("creat", Creat),
86: syscalls.PartiallySupported("link", Link, "Limited support with Gofer. Link count and linked files may get out of sync because gVisor is not aware of external hardlinks.", nil),
85: syscalls.SupportedPoint("creat", Creat, PointCreat),
86: syscalls.Supported("link", Link),
87: syscalls.Supported("unlink", Unlink),
88: syscalls.Supported("symlink", Symlink),
89: syscalls.Supported("readlink", Readlink),
90: syscalls.Supported("chmod", Chmod),
91: syscalls.PartiallySupported("fchmod", Fchmod, "Options S_ISUID and S_ISGID not supported.", nil),
91: syscalls.Supported("fchmod", Fchmod),
92: syscalls.Supported("chown", Chown),
93: syscalls.Supported("fchown", Fchown),
94: syscalls.Supported("lchown", Lchown),
@@ -185,12 +185,12 @@ var AMD64 = &kernel.SyscallTable{
130: syscalls.Supported("rt_sigsuspend", RtSigsuspend),
131: syscalls.Supported("sigaltstack", Sigaltstack),
132: syscalls.Supported("utime", Utime),
133: syscalls.PartiallySupported("mknod", Mknod, "Device creation is not generally supported. Only regular file and FIFO creation are supported.", nil),
133: syscalls.Supported("mknod", Mknod),
134: syscalls.Error("uselib", linuxerr.ENOSYS, "Obsolete", nil),
135: syscalls.ErrorWithEvent("personality", linuxerr.EINVAL, "Unable to change personality.", nil),
136: syscalls.ErrorWithEvent("ustat", linuxerr.ENOSYS, "Needs filesystem support.", nil),
137: syscalls.PartiallySupported("statfs", Statfs, "Depends on the backing file system implementation.", nil),
138: syscalls.PartiallySupported("fstatfs", Fstatfs, "Depends on the backing file system implementation.", nil),
137: syscalls.Supported("statfs", Statfs),
138: syscalls.Supported("fstatfs", Fstatfs),
139: syscalls.ErrorWithEvent("sysfs", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/165"}),
140: syscalls.PartiallySupported("getpriority", Getpriority, "Stub implementation.", nil),
141: syscalls.PartiallySupported("setpriority", Setpriority, "Stub implementation.", nil),
@@ -207,18 +207,18 @@ var AMD64 = &kernel.SyscallTable{
152: syscalls.PartiallySupported("munlockall", Munlockall, "Stub implementation. The sandbox lacks appropriate permissions.", nil),
153: syscalls.CapError("vhangup", linux.CAP_SYS_TTY_CONFIG, "", nil),
154: syscalls.Error("modify_ldt", linuxerr.EPERM, "", nil),
155: syscalls.Error("pivot_root", linuxerr.EPERM, "", nil),
155: syscalls.Supported("pivot_root", PivotRoot),
156: syscalls.Error("sysctl", linuxerr.EPERM, "Deprecated. Use /proc/sys instead.", nil),
157: syscalls.PartiallySupported("prctl", Prctl, "Not all options are supported.", nil),
158: syscalls.PartiallySupported("arch_prctl", ArchPrctl, "Options ARCH_GET_GS, ARCH_SET_GS not supported.", nil),
159: syscalls.CapError("adjtimex", linux.CAP_SYS_TIME, "", nil),
160: syscalls.PartiallySupported("setrlimit", Setrlimit, "Not all rlimits are enforced.", nil),
161: syscalls.SupportedPoint("chroot", Chroot, PointChroot),
162: syscalls.PartiallySupported("sync", Sync, "Full data flush is not guaranteed at this time.", nil),
162: syscalls.Supported("sync", Sync),
163: syscalls.CapError("acct", linux.CAP_SYS_PACCT, "", nil),
164: syscalls.CapError("settimeofday", linux.CAP_SYS_TIME, "", nil),
165: syscalls.PartiallySupported("mount", Mount, "Not all options or file systems are supported.", nil),
166: syscalls.PartiallySupported("umount2", Umount2, "Not all options or file systems are supported.", nil),
165: syscalls.Supported("mount", Mount),
166: syscalls.Supported("umount2", Umount2),
167: syscalls.CapError("swapon", linux.CAP_SYS_ADMIN, "", nil),
168: syscalls.CapError("swapoff", linux.CAP_SYS_ADMIN, "", nil),
169: syscalls.CapError("reboot", linux.CAP_SYS_BOOT, "", nil),
@@ -240,18 +240,18 @@ var AMD64 = &kernel.SyscallTable{
185: syscalls.Error("security", linuxerr.ENOSYS, "Not implemented in Linux.", nil),
186: syscalls.Supported("gettid", Gettid),
187: syscalls.Supported("readahead", Readahead),
188: syscalls.PartiallySupported("setxattr", SetXattr, "Only supported for tmpfs.", nil),
189: syscalls.PartiallySupported("lsetxattr", LSetXattr, "Only supported for tmpfs.", nil),
190: syscalls.PartiallySupported("fsetxattr", FSetXattr, "Only supported for tmpfs.", nil),
191: syscalls.PartiallySupported("getxattr", GetXattr, "Only supported for tmpfs.", nil),
192: syscalls.PartiallySupported("lgetxattr", LGetXattr, "Only supported for tmpfs.", nil),
193: syscalls.PartiallySupported("fgetxattr", FGetXattr, "Only supported for tmpfs.", nil),
194: syscalls.PartiallySupported("listxattr", ListXattr, "Only supported for tmpfs", nil),
195: syscalls.PartiallySupported("llistxattr", LListXattr, "Only supported for tmpfs", nil),
196: syscalls.PartiallySupported("flistxattr", FListXattr, "Only supported for tmpfs", nil),
197: syscalls.PartiallySupported("removexattr", RemoveXattr, "Only supported for tmpfs", nil),
198: syscalls.PartiallySupported("lremovexattr", LRemoveXattr, "Only supported for tmpfs", nil),
199: syscalls.PartiallySupported("fremovexattr", FRemoveXattr, "Only supported for tmpfs", nil),
188: syscalls.Supported("setxattr", SetXattr),
189: syscalls.Supported("lsetxattr", Lsetxattr),
190: syscalls.Supported("fsetxattr", Fsetxattr),
191: syscalls.Supported("getxattr", GetXattr),
192: syscalls.Supported("lgetxattr", Lgetxattr),
193: syscalls.Supported("fgetxattr", Fgetxattr),
194: syscalls.Supported("listxattr", ListXattr),
195: syscalls.Supported("llistxattr", Llistxattr),
196: syscalls.Supported("flistxattr", Flistxattr),
197: syscalls.Supported("removexattr", RemoveXattr),
198: syscalls.Supported("lremovexattr", Lremovexattr),
199: syscalls.Supported("fremovexattr", Fremovexattr),
200: syscalls.Supported("tkill", Tkill),
201: syscalls.Supported("time", Time),
202: syscalls.PartiallySupported("futex", Futex, "Robust futexes not supported.", nil),
@@ -273,7 +273,7 @@ var AMD64 = &kernel.SyscallTable{
218: syscalls.Supported("set_tid_address", SetTidAddress),
219: syscalls.Supported("restart_syscall", RestartSyscall),
220: syscalls.Supported("semtimedop", Semtimedop),
221: syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil),
221: syscalls.PartiallySupported("fadvise64", Fadvise64, "The syscall is 'supported', but ignores all provided advice.", nil),
222: syscalls.Supported("timer_create", TimerCreate),
223: syscalls.Supported("timer_settime", TimerSettime),
224: syscalls.Supported("timer_gettime", TimerGettime),
@@ -292,8 +292,8 @@ var AMD64 = &kernel.SyscallTable{
237: syscalls.PartiallySupported("mbind", Mbind, "Stub implementation. Only a single NUMA node is advertised, and mempolicy is ignored accordingly, but mbind() will succeed and has effects reflected by get_mempolicy.", []string{"gvisor.dev/issue/262"}),
238: syscalls.PartiallySupported("set_mempolicy", SetMempolicy, "Stub implementation.", nil),
239: syscalls.PartiallySupported("get_mempolicy", GetMempolicy, "Stub implementation.", nil),
240: syscalls.ErrorWithEvent("mq_open", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
241: syscalls.ErrorWithEvent("mq_unlink", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
240: syscalls.Supported("mq_open", MqOpen),
241: syscalls.Supported("mq_unlink", MqUnlink),
242: syscalls.ErrorWithEvent("mq_timedsend", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
243: syscalls.ErrorWithEvent("mq_timedreceive", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
244: syscalls.ErrorWithEvent("mq_notify", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
@@ -305,19 +305,19 @@ var AMD64 = &kernel.SyscallTable{
250: syscalls.Error("keyctl", linuxerr.EACCES, "Not available to user.", nil),
251: syscalls.CapError("ioprio_set", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_nice or cap_sys_admin (depending)
252: syscalls.CapError("ioprio_get", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_nice or cap_sys_admin (depending)
253: syscalls.PartiallySupportedPoint("inotify_init", InotifyInit, PointInotifyInit, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
254: syscalls.PartiallySupportedPoint("inotify_add_watch", InotifyAddWatch, PointInotifyAddWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
255: syscalls.PartiallySupportedPoint("inotify_rm_watch", InotifyRmWatch, PointInotifyRmWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
253: syscalls.PartiallySupportedPoint("inotify_init", InotifyInit, PointInotifyInit, "inotify events are only available inside the sandbox.", nil),
254: syscalls.PartiallySupportedPoint("inotify_add_watch", InotifyAddWatch, PointInotifyAddWatch, "inotify events are only available inside the sandbox.", nil),
255: syscalls.PartiallySupportedPoint("inotify_rm_watch", InotifyRmWatch, PointInotifyRmWatch, "inotify events are only available inside the sandbox.", nil),
256: syscalls.CapError("migrate_pages", linux.CAP_SYS_NICE, "", nil),
257: syscalls.SupportedPoint("openat", Openat, PointOpenat),
258: syscalls.Supported("mkdirat", Mkdirat),
259: syscalls.Supported("mknodat", Mknodat),
260: syscalls.Supported("fchownat", Fchownat),
261: syscalls.Supported("futimesat", Futimesat),
262: syscalls.Supported("fstatat", Fstatat),
262: syscalls.Supported("newfstatat", Newfstatat),
263: syscalls.Supported("unlinkat", Unlinkat),
264: syscalls.Supported("renameat", Renameat),
265: syscalls.PartiallySupported("linkat", Linkat, "See link(2).", nil),
265: syscalls.Supported("linkat", Linkat),
266: syscalls.Supported("symlinkat", Symlinkat),
267: syscalls.Supported("readlinkat", Readlinkat),
268: syscalls.Supported("fchmodat", Fchmodat),
@@ -329,37 +329,37 @@ var AMD64 = &kernel.SyscallTable{
274: syscalls.Supported("get_robust_list", GetRobustList),
275: syscalls.Supported("splice", Splice),
276: syscalls.Supported("tee", Tee),
277: syscalls.PartiallySupported("sync_file_range", SyncFileRange, "Full data flush is not guaranteed at this time.", nil),
277: syscalls.Supported("sync_file_range", SyncFileRange),
278: syscalls.ErrorWithEvent("vmsplice", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/138"}), // TODO(b/29354098)
279: syscalls.CapError("move_pages", linux.CAP_SYS_NICE, "", nil), // requires cap_sys_nice (mostly)
280: syscalls.Supported("utimensat", Utimensat),
281: syscalls.Supported("epoll_pwait", EpollPwait),
282: syscalls.PartiallySupportedPoint("signalfd", Signalfd, PointSignalfd, "Semantics are slightly different.", []string{"gvisor.dev/issue/139"}),
282: syscalls.SupportedPoint("signalfd", Signalfd, PointSignalfd),
283: syscalls.SupportedPoint("timerfd_create", TimerfdCreate, PointTimerfdCreate),
284: syscalls.SupportedPoint("eventfd", Eventfd, PointEventfd),
285: syscalls.PartiallySupported("fallocate", Fallocate, "Not all options are supported.", nil),
286: syscalls.SupportedPoint("timerfd_settime", TimerfdSettime, PointTimerfdSettime),
287: syscalls.SupportedPoint("timerfd_gettime", TimerfdGettime, PointTimerfdGettime),
288: syscalls.SupportedPoint("accept4", Accept4, PointAccept4),
289: syscalls.PartiallySupportedPoint("signalfd4", Signalfd4, PointSignalfd4, "Semantics are slightly different.", []string{"gvisor.dev/issue/139"}),
289: syscalls.SupportedPoint("signalfd4", Signalfd4, PointSignalfd4),
290: syscalls.SupportedPoint("eventfd2", Eventfd2, PointEventfd2),
291: syscalls.Supported("epoll_create1", EpollCreate1),
292: syscalls.SupportedPoint("dup3", Dup3, PointDup3),
293: syscalls.SupportedPoint("pipe2", Pipe2, PointPipe2),
294: syscalls.PartiallySupportedPoint("inotify_init1", InotifyInit1, PointInotifyInit1, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
294: syscalls.PartiallySupportedPoint("inotify_init1", InotifyInit1, PointInotifyInit1, "inotify events are only available inside the sandbox.", nil),
295: syscalls.Supported("preadv", Preadv),
296: syscalls.Supported("pwritev", Pwritev),
297: syscalls.Supported("rt_tgsigqueueinfo", RtTgsigqueueinfo),
298: syscalls.ErrorWithEvent("perf_event_open", linuxerr.ENODEV, "No support for perf counters", nil),
299: syscalls.PartiallySupported("recvmmsg", RecvMMsg, "Not all flags and control messages are supported.", nil),
299: syscalls.Supported("recvmmsg", RecvMMsg),
300: syscalls.ErrorWithEvent("fanotify_init", linuxerr.ENOSYS, "Needs CONFIG_FANOTIFY", nil),
301: syscalls.ErrorWithEvent("fanotify_mark", linuxerr.ENOSYS, "Needs CONFIG_FANOTIFY", nil),
302: syscalls.SupportedPoint("prlimit64", Prlimit64, PointPrlimit64),
303: syscalls.Error("name_to_handle_at", linuxerr.EOPNOTSUPP, "Not supported by gVisor filesystems", nil),
304: syscalls.Error("open_by_handle_at", linuxerr.EOPNOTSUPP, "Not supported by gVisor filesystems", nil),
305: syscalls.CapError("clock_adjtime", linux.CAP_SYS_TIME, "", nil),
306: syscalls.PartiallySupported("syncfs", Syncfs, "Depends on backing file system.", nil),
307: syscalls.PartiallySupported("sendmmsg", SendMMsg, "Not all flags and control messages are supported.", nil),
306: syscalls.Supported("syncfs", Syncfs),
307: syscalls.Supported("sendmmsg", SendMMsg),
308: syscalls.ErrorWithEvent("setns", linuxerr.EOPNOTSUPP, "Needs filesystem support", []string{"gvisor.dev/issue/140"}), // TODO(b/29354995)
309: syscalls.Supported("getcpu", Getcpu),
310: syscalls.ErrorWithEvent("process_vm_readv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}),
@@ -368,7 +368,7 @@ var AMD64 = &kernel.SyscallTable{
313: syscalls.CapError("finit_module", linux.CAP_SYS_MODULE, "", nil),
314: syscalls.ErrorWithEvent("sched_setattr", linuxerr.ENOSYS, "gVisor does not implement a scheduler.", []string{"gvisor.dev/issue/264"}), // TODO(b/118902272)
315: syscalls.ErrorWithEvent("sched_getattr", linuxerr.ENOSYS, "gVisor does not implement a scheduler.", []string{"gvisor.dev/issue/264"}), // TODO(b/118902272)
316: syscalls.ErrorWithEvent("renameat2", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/263"}), // TODO(b/118902772)
316: syscalls.Supported("renameat2", Renameat2),
317: syscalls.Supported("seccomp", Seccomp),
318: syscalls.Supported("getrandom", GetRandom),
319: syscalls.Supported("memfd_create", MemfdCreate),
@@ -383,7 +383,7 @@ var AMD64 = &kernel.SyscallTable{
// of Linux after 4.4.
326: syscalls.ErrorWithEvent("copy_file_range", linuxerr.ENOSYS, "", nil),
327: syscalls.Supported("preadv2", Preadv2),
328: syscalls.PartiallySupported("pwritev2", Pwritev2, "Flag RWF_HIPRI is not supported.", nil),
328: syscalls.Supported("pwritev2", Pwritev2),
329: syscalls.ErrorWithEvent("pkey_mprotect", linuxerr.ENOSYS, "", nil),
330: syscalls.ErrorWithEvent("pkey_alloc", linuxerr.ENOSYS, "", nil),
331: syscalls.ErrorWithEvent("pkey_free", linuxerr.ENOSYS, "", nil),
@@ -393,8 +393,8 @@ var AMD64 = &kernel.SyscallTable{
// Linux skips ahead to syscall 424 to sync numbers between arches.
424: syscalls.ErrorWithEvent("pidfd_send_signal", linuxerr.ENOSYS, "", nil),
425: syscalls.ErrorWithEvent("io_uring_setup", linuxerr.ENOSYS, "", nil),
426: syscalls.ErrorWithEvent("io_uring_enter", linuxerr.ENOSYS, "", nil),
425: syscalls.PartiallySupported("io_uring_setup", IOUringSetup, "Not all flags and functionality supported.", nil),
426: syscalls.PartiallySupported("io_uring_enter", IOUringEnter, "Not all flags and functionality supported.", nil),
427: syscalls.ErrorWithEvent("io_uring_register", linuxerr.ENOSYS, "", nil),
428: syscalls.ErrorWithEvent("open_tree", linuxerr.ENOSYS, "", nil),
429: syscalls.ErrorWithEvent("move_mount", linuxerr.ENOSYS, "", nil),
@@ -405,6 +405,7 @@ var AMD64 = &kernel.SyscallTable{
434: syscalls.ErrorWithEvent("pidfd_open", linuxerr.ENOSYS, "", nil),
435: syscalls.ErrorWithEvent("clone3", linuxerr.ENOSYS, "", nil),
436: syscalls.Supported("close_range", CloseRange),
439: syscalls.Supported("faccessat2", Faccessat2),
441: syscalls.Supported("epoll_pwait2", EpollPwait2),
},
Emulate: map[hostarch.Addr]uintptr{
@@ -435,18 +436,18 @@ var ARM64 = &kernel.SyscallTable{
2: syscalls.PartiallySupported("io_submit", IoSubmit, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
3: syscalls.PartiallySupported("io_cancel", IoCancel, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
4: syscalls.PartiallySupported("io_getevents", IoGetevents, "Generally supported with exceptions. User ring optimizations are not implemented.", []string{"gvisor.dev/issue/204"}),
5: syscalls.PartiallySupported("setxattr", SetXattr, "Only supported for tmpfs.", nil),
6: syscalls.PartiallySupported("lsetxattr", LSetXattr, "Only supported for tmpfs.", nil),
7: syscalls.PartiallySupported("fsetxattr", FSetXattr, "Only supported for tmpfs.", nil),
8: syscalls.PartiallySupported("getxattr", GetXattr, "Only supported for tmpfs.", nil),
9: syscalls.PartiallySupported("lgetxattr", LGetXattr, "Only supported for tmpfs.", nil),
10: syscalls.PartiallySupported("fgetxattr", FGetXattr, "Only supported for tmpfs.", nil),
11: syscalls.PartiallySupported("listxattr", ListXattr, "Only supported for tmpfs", nil),
12: syscalls.PartiallySupported("llistxattr", LListXattr, "Only supported for tmpfs", nil),
13: syscalls.PartiallySupported("flistxattr", FListXattr, "Only supported for tmpfs", nil),
14: syscalls.PartiallySupported("removexattr", RemoveXattr, "Only supported for tmpfs", nil),
15: syscalls.PartiallySupported("lremovexattr", LRemoveXattr, "Only supported for tmpfs", nil),
16: syscalls.PartiallySupported("fremovexattr", FRemoveXattr, "Only supported for tmpfs", nil),
5: syscalls.Supported("setxattr", SetXattr),
6: syscalls.Supported("lsetxattr", Lsetxattr),
7: syscalls.Supported("fsetxattr", Fsetxattr),
8: syscalls.Supported("getxattr", GetXattr),
9: syscalls.Supported("lgetxattr", Lgetxattr),
10: syscalls.Supported("fgetxattr", Fgetxattr),
11: syscalls.Supported("listxattr", ListXattr),
12: syscalls.Supported("llistxattr", Llistxattr),
13: syscalls.Supported("flistxattr", Flistxattr),
14: syscalls.Supported("removexattr", RemoveXattr),
15: syscalls.Supported("lremovexattr", Lremovexattr),
16: syscalls.Supported("fremovexattr", Fremovexattr),
17: syscalls.Supported("getcwd", Getcwd),
18: syscalls.CapError("lookup_dcookie", linux.CAP_SYS_ADMIN, "", nil),
19: syscalls.SupportedPoint("eventfd2", Eventfd2, PointEventfd2),
@@ -455,26 +456,26 @@ var ARM64 = &kernel.SyscallTable{
22: syscalls.Supported("epoll_pwait", EpollPwait),
23: syscalls.SupportedPoint("dup", Dup, PointDup),
24: syscalls.SupportedPoint("dup3", Dup3, PointDup3),
25: syscalls.PartiallySupportedPoint("fcntl", Fcntl, PointFcntl, "Not all options are supported.", nil),
26: syscalls.PartiallySupportedPoint("inotify_init1", InotifyInit1, PointInotifyInit1, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
27: syscalls.PartiallySupportedPoint("inotify_add_watch", InotifyAddWatch, PointInotifyAddWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
28: syscalls.PartiallySupportedPoint("inotify_rm_watch", InotifyRmWatch, PointInotifyRmWatch, "Inotify events are only available inside the sandbox. Hard links are treated as different watch targets in gofer fs.", nil),
29: syscalls.PartiallySupported("ioctl", Ioctl, "Only a few ioctls are implemented for backing devices and file systems.", nil),
25: syscalls.SupportedPoint("fcntl", Fcntl, PointFcntl),
26: syscalls.PartiallySupportedPoint("inotify_init1", InotifyInit1, PointInotifyInit1, "inotify events are only available inside the sandbox.", nil),
27: syscalls.PartiallySupportedPoint("inotify_add_watch", InotifyAddWatch, PointInotifyAddWatch, "inotify events are only available inside the sandbox.", nil),
28: syscalls.PartiallySupportedPoint("inotify_rm_watch", InotifyRmWatch, PointInotifyRmWatch, "inotify events are only available inside the sandbox.", nil),
29: syscalls.Supported("ioctl", Ioctl),
30: syscalls.CapError("ioprio_set", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_nice or cap_sys_admin (depending)
31: syscalls.CapError("ioprio_get", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_nice or cap_sys_admin (depending)
32: syscalls.PartiallySupported("flock", Flock, "Locks are held within the sandbox only.", nil),
32: syscalls.Supported("flock", Flock),
33: syscalls.Supported("mknodat", Mknodat),
34: syscalls.Supported("mkdirat", Mkdirat),
35: syscalls.Supported("unlinkat", Unlinkat),
36: syscalls.Supported("symlinkat", Symlinkat),
37: syscalls.Supported("linkat", Linkat),
38: syscalls.Supported("renameat", Renameat),
39: syscalls.PartiallySupported("umount2", Umount2, "Not all options or file systems are supported.", nil),
40: syscalls.PartiallySupported("mount", Mount, "Not all options or file systems are supported.", nil),
41: syscalls.Error("pivot_root", linuxerr.EPERM, "", nil),
39: syscalls.Supported("umount2", Umount2),
40: syscalls.Supported("mount", Mount),
41: syscalls.Supported("pivot_root", PivotRoot),
42: syscalls.Error("nfsservctl", linuxerr.ENOSYS, "Removed after Linux 3.1.", nil),
43: syscalls.PartiallySupported("statfs", Statfs, "Depends on the backing file system implementation.", nil),
44: syscalls.PartiallySupported("fstatfs", Fstatfs, "Depends on the backing file system implementation.", nil),
43: syscalls.Supported("statfs", Statfs),
44: syscalls.Supported("fstatfs", Fstatfs),
45: syscalls.Supported("truncate", Truncate),
46: syscalls.Supported("ftruncate", Ftruncate),
47: syscalls.PartiallySupported("fallocate", Fallocate, "Not all options are supported.", nil),
@@ -482,12 +483,12 @@ var ARM64 = &kernel.SyscallTable{
49: syscalls.SupportedPoint("chdir", Chdir, PointChdir),
50: syscalls.SupportedPoint("fchdir", Fchdir, PointFchdir),
51: syscalls.SupportedPoint("chroot", Chroot, PointChroot),
52: syscalls.PartiallySupported("fchmod", Fchmod, "Options S_ISUID and S_ISGID not supported.", nil),
52: syscalls.Supported("fchmod", Fchmod),
53: syscalls.Supported("fchmodat", Fchmodat),
54: syscalls.Supported("fchownat", Fchownat),
55: syscalls.Supported("fchown", Fchown),
56: syscalls.SupportedPoint("openat", Openat, PointOpenat),
57: syscalls.Supported("close", Close),
57: syscalls.SupportedPoint("close", Close, PointClose),
58: syscalls.CapError("vhangup", linux.CAP_SYS_TTY_CONFIG, "", nil),
59: syscalls.SupportedPoint("pipe2", Pipe2, PointPipe2),
60: syscalls.CapError("quotactl", linux.CAP_SYS_ADMIN, "", nil), // requires cap_sys_admin for most operations
@@ -504,17 +505,17 @@ var ARM64 = &kernel.SyscallTable{
71: syscalls.Supported("sendfile", Sendfile),
72: syscalls.Supported("pselect", Pselect),
73: syscalls.Supported("ppoll", Ppoll),
74: syscalls.PartiallySupportedPoint("signalfd4", Signalfd4, PointSignalfd4, "Semantics are slightly different.", []string{"gvisor.dev/issue/139"}),
74: syscalls.SupportedPoint("signalfd4", Signalfd4, PointSignalfd4),
75: syscalls.ErrorWithEvent("vmsplice", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/138"}), // TODO(b/29354098)
76: syscalls.Supported("splice", Splice),
77: syscalls.Supported("tee", Tee),
78: syscalls.Supported("readlinkat", Readlinkat),
79: syscalls.Supported("fstatat", Fstatat),
79: syscalls.Supported("newfstatat", Newfstatat),
80: syscalls.Supported("fstat", Fstat),
81: syscalls.PartiallySupported("sync", Sync, "Full data flush is not guaranteed at this time.", nil),
82: syscalls.PartiallySupported("fsync", Fsync, "Full data flush is not guaranteed at this time.", nil),
83: syscalls.PartiallySupported("fdatasync", Fdatasync, "Full data flush is not guaranteed at this time.", nil),
84: syscalls.PartiallySupported("sync_file_range", SyncFileRange, "Full data flush is not guaranteed at this time.", nil),
81: syscalls.Supported("sync", Sync),
82: syscalls.Supported("fsync", Fsync),
83: syscalls.Supported("fdatasync", Fdatasync),
84: syscalls.Supported("sync_file_range", SyncFileRange),
85: syscalls.SupportedPoint("timerfd_create", TimerfdCreate, PointTimerfdCreate),
86: syscalls.SupportedPoint("timerfd_settime", TimerfdSettime, PointTimerfdSettime),
87: syscalls.SupportedPoint("timerfd_gettime", TimerfdGettime, PointTimerfdGettime),
@@ -610,8 +611,8 @@ var ARM64 = &kernel.SyscallTable{
177: syscalls.Supported("getegid", Getegid),
178: syscalls.Supported("gettid", Gettid),
179: syscalls.PartiallySupported("sysinfo", Sysinfo, "Fields loads, sharedram, bufferram, totalswap, freeswap, totalhigh, freehigh not supported.", nil),
180: syscalls.ErrorWithEvent("mq_open", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
181: syscalls.ErrorWithEvent("mq_unlink", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
180: syscalls.Supported("mq_open", MqOpen),
181: syscalls.Supported("mq_unlink", MqUnlink),
182: syscalls.ErrorWithEvent("mq_timedsend", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
183: syscalls.ErrorWithEvent("mq_timedreceive", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
184: syscalls.ErrorWithEvent("mq_notify", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/136"}), // TODO(b/29354921)
@@ -628,9 +629,9 @@ var ARM64 = &kernel.SyscallTable{
195: syscalls.PartiallySupported("shmctl", Shmctl, "Options SHM_LOCK, SHM_UNLOCK are not supported.", nil),
196: syscalls.PartiallySupported("shmat", Shmat, "Option SHM_RND is not supported.", nil),
197: syscalls.Supported("shmdt", Shmdt),
198: syscalls.PartiallySupported("socket", Socket, "Limited support for AF_NETLINK, NETLINK_ROUTE sockets. Limited support for SOCK_RAW.", nil),
198: syscalls.SupportedPoint("socket", Socket, PointSocket),
199: syscalls.SupportedPoint("socketpair", SocketPair, PointSocketpair),
200: syscalls.PartiallySupportedPoint("bind", Bind, PointBind, "Autobind for abstract Unix sockets is not supported.", nil),
200: syscalls.SupportedPoint("bind", Bind, PointBind),
201: syscalls.Supported("listen", Listen),
202: syscalls.SupportedPoint("accept", Accept, PointAccept),
203: syscalls.SupportedPoint("connect", Connect, PointConnect),
@@ -638,11 +639,11 @@ var ARM64 = &kernel.SyscallTable{
205: syscalls.Supported("getpeername", GetPeerName),
206: syscalls.Supported("sendto", SendTo),
207: syscalls.Supported("recvfrom", RecvFrom),
208: syscalls.PartiallySupported("setsockopt", SetSockOpt, "Not all socket options are supported.", nil),
209: syscalls.PartiallySupported("getsockopt", GetSockOpt, "Not all socket options are supported.", nil),
210: syscalls.PartiallySupported("shutdown", Shutdown, "Not all flags and control messages are supported.", nil),
208: syscalls.Supported("setsockopt", SetSockOpt),
209: syscalls.Supported("getsockopt", GetSockOpt),
210: syscalls.Supported("shutdown", Shutdown),
211: syscalls.Supported("sendmsg", SendMsg),
212: syscalls.PartiallySupported("recvmsg", RecvMsg, "Not all flags and control messages are supported.", nil),
212: syscalls.Supported("recvmsg", RecvMsg),
213: syscalls.Supported("readahead", Readahead),
214: syscalls.Supported("brk", Brk),
215: syscalls.Supported("munmap", Munmap),
@@ -652,7 +653,7 @@ var ARM64 = &kernel.SyscallTable{
219: syscalls.Error("keyctl", linuxerr.EACCES, "Not available to user.", nil),
220: syscalls.PartiallySupportedPoint("clone", Clone, PointClone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil),
221: syscalls.SupportedPoint("execve", Execve, PointExecve),
222: syscalls.PartiallySupported("mmap", Mmap, "Generally supported with exceptions. Options MAP_FIXED_NOREPLACE, MAP_SHARED_VALIDATE, MAP_SYNC MAP_GROWSDOWN, MAP_HUGETLB are not supported.", nil),
222: syscalls.Supported("mmap", Mmap),
223: syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil),
224: syscalls.CapError("swapon", linux.CAP_SYS_ADMIN, "", nil),
225: syscalls.CapError("swapoff", linux.CAP_SYS_ADMIN, "", nil),
@@ -673,7 +674,7 @@ var ARM64 = &kernel.SyscallTable{
240: syscalls.Supported("rt_tgsigqueueinfo", RtTgsigqueueinfo),
241: syscalls.ErrorWithEvent("perf_event_open", linuxerr.ENODEV, "No support for perf counters", nil),
242: syscalls.SupportedPoint("accept4", Accept4, PointAccept4),
243: syscalls.PartiallySupported("recvmmsg", RecvMMsg, "Not all flags and control messages are supported.", nil),
243: syscalls.Supported("recvmmsg", RecvMMsg),
260: syscalls.Supported("wait4", Wait4),
261: syscalls.SupportedPoint("prlimit64", Prlimit64, PointPrlimit64),
262: syscalls.ErrorWithEvent("fanotify_init", linuxerr.ENOSYS, "Needs CONFIG_FANOTIFY", nil),
@@ -681,16 +682,16 @@ var ARM64 = &kernel.SyscallTable{
264: syscalls.Error("name_to_handle_at", linuxerr.EOPNOTSUPP, "Not supported by gVisor filesystems", nil),
265: syscalls.Error("open_by_handle_at", linuxerr.EOPNOTSUPP, "Not supported by gVisor filesystems", nil),
266: syscalls.CapError("clock_adjtime", linux.CAP_SYS_TIME, "", nil),
267: syscalls.PartiallySupported("syncfs", Syncfs, "Depends on backing file system.", nil),
267: syscalls.Supported("syncfs", Syncfs),
268: syscalls.ErrorWithEvent("setns", linuxerr.EOPNOTSUPP, "Needs filesystem support", []string{"gvisor.dev/issue/140"}), // TODO(b/29354995)
269: syscalls.PartiallySupported("sendmmsg", SendMMsg, "Not all flags and control messages are supported.", nil),
269: syscalls.Supported("sendmmsg", SendMMsg),
270: syscalls.ErrorWithEvent("process_vm_readv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}),
271: syscalls.ErrorWithEvent("process_vm_writev", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}),
272: syscalls.CapError("kcmp", linux.CAP_SYS_PTRACE, "", nil),
273: syscalls.CapError("finit_module", linux.CAP_SYS_MODULE, "", nil),
274: syscalls.ErrorWithEvent("sched_setattr", linuxerr.ENOSYS, "gVisor does not implement a scheduler.", []string{"gvisor.dev/issue/264"}), // TODO(b/118902272)
275: syscalls.ErrorWithEvent("sched_getattr", linuxerr.ENOSYS, "gVisor does not implement a scheduler.", []string{"gvisor.dev/issue/264"}), // TODO(b/118902272)
276: syscalls.ErrorWithEvent("renameat2", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/263"}), // TODO(b/118902772)
276: syscalls.Supported("renameat2", Renameat2),
277: syscalls.Supported("seccomp", Seccomp),
278: syscalls.Supported("getrandom", GetRandom),
279: syscalls.Supported("memfd_create", MemfdCreate),
@@ -703,7 +704,7 @@ var ARM64 = &kernel.SyscallTable{
// Syscalls after 284 are "backports" from versions of Linux after 4.4.
285: syscalls.ErrorWithEvent("copy_file_range", linuxerr.ENOSYS, "", nil),
286: syscalls.Supported("preadv2", Preadv2),
287: syscalls.PartiallySupported("pwritev2", Pwritev2, "Flag RWF_HIPRI is not supported.", nil),
287: syscalls.Supported("pwritev2", Pwritev2),
288: syscalls.ErrorWithEvent("pkey_mprotect", linuxerr.ENOSYS, "", nil),
289: syscalls.ErrorWithEvent("pkey_alloc", linuxerr.ENOSYS, "", nil),
290: syscalls.ErrorWithEvent("pkey_free", linuxerr.ENOSYS, "", nil),
@@ -713,8 +714,8 @@ var ARM64 = &kernel.SyscallTable{
// Linux skips ahead to syscall 424 to sync numbers between arches.
424: syscalls.ErrorWithEvent("pidfd_send_signal", linuxerr.ENOSYS, "", nil),
425: syscalls.ErrorWithEvent("io_uring_setup", linuxerr.ENOSYS, "", nil),
426: syscalls.ErrorWithEvent("io_uring_enter", linuxerr.ENOSYS, "", nil),
425: syscalls.PartiallySupported("io_uring_setup", IOUringSetup, "Not all flags and functionality supported.", nil),
426: syscalls.PartiallySupported("io_uring_enter", IOUringEnter, "Not all flags and functionality supported.", nil),
427: syscalls.ErrorWithEvent("io_uring_register", linuxerr.ENOSYS, "", nil),
428: syscalls.ErrorWithEvent("open_tree", linuxerr.ENOSYS, "", nil),
429: syscalls.ErrorWithEvent("move_mount", linuxerr.ENOSYS, "", nil),
@@ -725,6 +726,7 @@ var ARM64 = &kernel.SyscallTable{
434: syscalls.ErrorWithEvent("pidfd_open", linuxerr.ENOSYS, "", nil),
435: syscalls.ErrorWithEvent("clone3", linuxerr.ENOSYS, "", nil),
436: syscalls.Supported("close_range", CloseRange),
439: syscalls.Supported("faccessat2", Faccessat2),
441: syscalls.Supported("epoll_pwait2", EpollPwait2),
},
Emulate: map[hostarch.Addr]uintptr{},
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package vfs2
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
+109 -114
View File
@@ -21,11 +21,11 @@ import (
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/marshal/primitive"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/eventfd"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/eventfd"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/sentry/mm"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
)
@@ -218,116 +218,6 @@ func IoCancel(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
return 0, nil, linuxerr.ENOSYS
}
// LINT.IfChange
func getAIOCallback(t *kernel.Task, file *fs.File, cbAddr hostarch.Addr, cb *linux.IOCallback, ioseq usermem.IOSequence, actx *mm.AIOContext, eventFile *fs.File) kernel.AIOCallback {
return func(ctx context.Context) {
if actx.Dead() {
actx.CancelPendingRequest()
return
}
ev := &linux.IOEvent{
Data: cb.Data,
Obj: uint64(cbAddr),
}
var err error
switch cb.OpCode {
case linux.IOCB_CMD_PREAD, linux.IOCB_CMD_PREADV:
ev.Result, err = file.Preadv(ctx, ioseq, cb.Offset)
case linux.IOCB_CMD_PWRITE, linux.IOCB_CMD_PWRITEV:
ev.Result, err = file.Pwritev(ctx, ioseq, cb.Offset)
case linux.IOCB_CMD_FSYNC:
err = file.Fsync(ctx, 0, fs.FileMaxOffset, fs.SyncAll)
case linux.IOCB_CMD_FDSYNC:
err = file.Fsync(ctx, 0, fs.FileMaxOffset, fs.SyncData)
}
// Update the result.
if err != nil {
err = handleIOError(t, ev.Result != 0 /* partial */, err, nil /* never interrupted */, "aio", file)
ev.Result = -int64(kernel.ExtractErrno(err, 0))
}
file.DecRef(ctx)
// Queue the result for delivery.
actx.FinishRequest(ev)
// Notify the event file if one was specified. This needs to happen
// *after* queueing the result to avoid racing with the thread we may
// wake up.
if eventFile != nil {
eventFile.FileOperations.(*eventfd.EventOperations).Signal(1)
eventFile.DecRef(ctx)
}
}
}
// submitCallback processes a single callback.
func submitCallback(t *kernel.Task, id uint64, cb *linux.IOCallback, cbAddr hostarch.Addr) error {
file := t.GetFile(cb.FD)
if file == nil {
// File not found.
return linuxerr.EBADF
}
defer file.DecRef(t)
// Was there an eventFD? Extract it.
var eventFile *fs.File
if cb.Flags&linux.IOCB_FLAG_RESFD != 0 {
eventFile = t.GetFile(cb.ResFD)
if eventFile == nil {
// Bad FD.
return linuxerr.EBADF
}
defer eventFile.DecRef(t)
// Check that it is an eventfd.
if _, ok := eventFile.FileOperations.(*eventfd.EventOperations); !ok {
// Not an event FD.
return linuxerr.EINVAL
}
}
ioseq, err := memoryFor(t, cb)
if err != nil {
return err
}
// Check offset for reads/writes.
switch cb.OpCode {
case linux.IOCB_CMD_PREAD, linux.IOCB_CMD_PREADV, linux.IOCB_CMD_PWRITE, linux.IOCB_CMD_PWRITEV:
if cb.Offset < 0 {
return linuxerr.EINVAL
}
}
// Prepare the request.
ctx, ok := t.MemoryManager().LookupAIOContext(t, id)
if !ok {
return linuxerr.EINVAL
}
if err := ctx.Prepare(); err != nil {
return err
}
if eventFile != nil {
// The request is set. Make sure there's a ref on the file.
//
// This is necessary when the callback executes on completion,
// which is also what will release this reference.
eventFile.IncRef()
}
// Perform the request asynchronously.
file.IncRef()
t.QueueAIO(getAIOCallback(t, file, cbAddr, cb, ioseq, ctx, eventFile))
// All set.
return nil
}
// IoSubmit implements linux syscall io_submit(2).
func IoSubmit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
id := args[0].Uint64()
@@ -360,7 +250,6 @@ func IoSubmit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
// Copy in this callback.
var cb linux.IOCallback
if _, err := cb.CopyIn(t, cbAddr); err != nil {
if i > 0 {
// Some have been successful.
return uintptr(i), nil, nil
@@ -386,4 +275,110 @@ func IoSubmit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
return uintptr(nrEvents), nil, nil
}
// LINT.ThenChange(vfs2/aio.go)
// submitCallback processes a single callback.
func submitCallback(t *kernel.Task, id uint64, cb *linux.IOCallback, cbAddr hostarch.Addr) error {
if cb.Reserved2 != 0 {
return linuxerr.EINVAL
}
fd := t.GetFileVFS2(cb.FD)
if fd == nil {
return linuxerr.EBADF
}
defer fd.DecRef(t)
// Was there an eventFD? Extract it.
var eventFD *vfs.FileDescription
if cb.Flags&linux.IOCB_FLAG_RESFD != 0 {
eventFD = t.GetFileVFS2(cb.ResFD)
if eventFD == nil {
return linuxerr.EBADF
}
defer eventFD.DecRef(t)
// Check that it is an eventfd.
if _, ok := eventFD.Impl().(*eventfd.EventFileDescription); !ok {
return linuxerr.EINVAL
}
}
ioseq, err := memoryFor(t, cb)
if err != nil {
return err
}
// Check offset for reads/writes.
switch cb.OpCode {
case linux.IOCB_CMD_PREAD, linux.IOCB_CMD_PREADV, linux.IOCB_CMD_PWRITE, linux.IOCB_CMD_PWRITEV:
if cb.Offset < 0 {
return linuxerr.EINVAL
}
}
// Prepare the request.
aioCtx, ok := t.MemoryManager().LookupAIOContext(t, id)
if !ok {
return linuxerr.EINVAL
}
if err := aioCtx.Prepare(); err != nil {
return err
}
if eventFD != nil {
// The request is set. Make sure there's a ref on the file.
//
// This is necessary when the callback executes on completion,
// which is also what will release this reference.
eventFD.IncRef()
}
// Perform the request asynchronously.
fd.IncRef()
t.QueueAIO(getAIOCallback(t, fd, eventFD, cbAddr, cb, ioseq, aioCtx))
return nil
}
func getAIOCallback(t *kernel.Task, fd, eventFD *vfs.FileDescription, cbAddr hostarch.Addr, cb *linux.IOCallback, ioseq usermem.IOSequence, aioCtx *mm.AIOContext) kernel.AIOCallback {
return func(ctx context.Context) {
// Release references after completing the callback.
defer fd.DecRef(ctx)
if eventFD != nil {
defer eventFD.DecRef(ctx)
}
if aioCtx.Dead() {
aioCtx.CancelPendingRequest()
return
}
ev := &linux.IOEvent{
Data: cb.Data,
Obj: uint64(cbAddr),
}
var err error
switch cb.OpCode {
case linux.IOCB_CMD_PREAD, linux.IOCB_CMD_PREADV:
ev.Result, err = fd.PRead(ctx, ioseq, cb.Offset, vfs.ReadOptions{})
case linux.IOCB_CMD_PWRITE, linux.IOCB_CMD_PWRITEV:
ev.Result, err = fd.PWrite(ctx, ioseq, cb.Offset, vfs.WriteOptions{})
case linux.IOCB_CMD_FSYNC, linux.IOCB_CMD_FDSYNC:
err = fd.Sync(ctx)
}
// Update the result.
if err != nil {
err = HandleIOError(ctx, ev.Result != 0 /* partial */, err, nil /* never interrupted */, "aio", fd)
ev.Result = -int64(kernel.ExtractErrno(err, 0))
}
// Queue the result for delivery.
aioCtx.FinishRequest(ev)
// Notify the event file if one was specified. This needs to happen
// *after* queueing the result to avoid racing with the thread we may
// wake up.
if eventFD != nil {
eventFD.Impl().(*eventfd.EventFileDescription).Signal(1)
}
}
}
+122 -74
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The gVisor Authors.
// Copyright 2020 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.
@@ -15,142 +15,200 @@
package linux
import (
"math"
"time"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/epoll"
"gvisor.dev/gvisor/pkg/sentry/syscalls"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/waiter"
)
// LINT.IfChange
var sizeofEpollEvent = (*linux.EpollEvent)(nil).SizeBytes()
// EpollCreate1 implements the epoll_create1(2) linux syscall.
// EpollCreate1 implements Linux syscall epoll_create1(2).
func EpollCreate1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
flags := args[0].Int()
if flags & ^linux.EPOLL_CLOEXEC != 0 {
if flags&^linux.EPOLL_CLOEXEC != 0 {
return 0, nil, linuxerr.EINVAL
}
closeOnExec := flags&linux.EPOLL_CLOEXEC != 0
fd, err := syscalls.CreateEpoll(t, closeOnExec)
file, err := t.Kernel().VFS().NewEpollInstanceFD(t)
if err != nil {
return 0, nil, err
}
defer file.DecRef(t)
fd, err := t.NewFDFromVFS2(0, file, kernel.FDFlags{
CloseOnExec: flags&linux.EPOLL_CLOEXEC != 0,
})
if err != nil {
return 0, nil, err
}
return uintptr(fd), nil, nil
}
// EpollCreate implements the epoll_create(2) linux syscall.
// EpollCreate implements Linux syscall epoll_create(2).
func EpollCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
size := args[0].Int()
// "Since Linux 2.6.8, the size argument is ignored, but must be greater
// than zero" - epoll_create(2)
if size <= 0 {
return 0, nil, linuxerr.EINVAL
}
fd, err := syscalls.CreateEpoll(t, false)
file, err := t.Kernel().VFS().NewEpollInstanceFD(t)
if err != nil {
return 0, nil, err
}
defer file.DecRef(t)
fd, err := t.NewFDFromVFS2(0, file, kernel.FDFlags{})
if err != nil {
return 0, nil, err
}
return uintptr(fd), nil, nil
}
// EpollCtl implements the epoll_ctl(2) linux syscall.
// EpollCtl implements Linux syscall epoll_ctl(2).
func EpollCtl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
epfd := args[0].Int()
op := args[1].Int()
fd := args[2].Int()
eventAddr := args[3].Pointer()
// Capture the event state if needed.
flags := epoll.EntryFlags(0)
mask := waiter.EventMask(0)
var data [2]int32
if op != linux.EPOLL_CTL_DEL {
var e linux.EpollEvent
if _, err := e.CopyIn(t, eventAddr); err != nil {
return 0, nil, err
}
if e.Events&linux.EPOLLONESHOT != 0 {
flags |= epoll.OneShot
}
if e.Events&linux.EPOLLET != 0 {
flags |= epoll.EdgeTriggered
}
mask = waiter.EventMaskFromLinux(e.Events)
data = e.Data
epfile := t.GetFileVFS2(epfd)
if epfile == nil {
return 0, nil, linuxerr.EBADF
}
defer epfile.DecRef(t)
ep, ok := epfile.Impl().(*vfs.EpollInstance)
if !ok {
return 0, nil, linuxerr.EINVAL
}
file := t.GetFileVFS2(fd)
if file == nil {
return 0, nil, linuxerr.EBADF
}
defer file.DecRef(t)
if epfile == file {
return 0, nil, linuxerr.EINVAL
}
// Perform the requested operations.
var event linux.EpollEvent
switch op {
case linux.EPOLL_CTL_ADD:
// See fs/eventpoll.c.
mask |= waiter.EventHUp | waiter.EventErr
return 0, nil, syscalls.AddEpoll(t, epfd, fd, flags, mask, data)
if _, err := event.CopyIn(t, eventAddr); err != nil {
return 0, nil, err
}
return 0, nil, ep.AddInterest(file, fd, event)
case linux.EPOLL_CTL_DEL:
return 0, nil, syscalls.RemoveEpoll(t, epfd, fd)
return 0, nil, ep.DeleteInterest(file, fd)
case linux.EPOLL_CTL_MOD:
// Same as EPOLL_CTL_ADD.
mask |= waiter.EventHUp | waiter.EventErr
return 0, nil, syscalls.UpdateEpoll(t, epfd, fd, flags, mask, data)
if _, err := event.CopyIn(t, eventAddr); err != nil {
return 0, nil, err
}
return 0, nil, ep.ModifyInterest(file, fd, event)
default:
return 0, nil, linuxerr.EINVAL
}
}
func waitEpoll(t *kernel.Task, fd int32, eventsAddr hostarch.Addr, max int, timeoutInNanos int64) (uintptr, *kernel.SyscallControl, error) {
r, err := syscalls.WaitEpoll(t, fd, max, timeoutInNanos)
if err != nil {
return 0, nil, linuxerr.ConvertIntr(err, linuxerr.EINTR)
func waitEpoll(t *kernel.Task, epfd int32, eventsAddr hostarch.Addr, maxEvents int, timeoutInNanos int64) (uintptr, *kernel.SyscallControl, error) {
var _EP_MAX_EVENTS = math.MaxInt32 / sizeofEpollEvent // Linux: fs/eventpoll.c:EP_MAX_EVENTS
if maxEvents <= 0 || maxEvents > _EP_MAX_EVENTS {
return 0, nil, linuxerr.EINVAL
}
if len(r) != 0 {
if _, err := linux.CopyEpollEventSliceOut(t, eventsAddr, r); err != nil {
epfile := t.GetFileVFS2(epfd)
if epfile == nil {
return 0, nil, linuxerr.EBADF
}
defer epfile.DecRef(t)
ep, ok := epfile.Impl().(*vfs.EpollInstance)
if !ok {
return 0, nil, linuxerr.EINVAL
}
// Allocate space for a few events on the stack for the common case in
// which we don't have too many events.
var (
eventsArr [16]linux.EpollEvent
ch chan struct{}
haveDeadline bool
deadline ktime.Time
)
for {
events := ep.ReadEvents(eventsArr[:0], maxEvents)
if len(events) != 0 {
copiedBytes, err := linux.CopyEpollEventSliceOut(t, eventsAddr, events)
copiedEvents := copiedBytes / sizeofEpollEvent // rounded down
if copiedEvents != 0 {
return uintptr(copiedEvents), nil, nil
}
return 0, nil, err
}
if timeoutInNanos == 0 {
return 0, nil, nil
}
// In the first iteration of this loop, register with the epoll
// instance for readability events, but then immediately continue the
// loop since we need to retry ReadEvents() before blocking. In all
// subsequent iterations, block until events are available, the timeout
// expires, or an interrupt arrives.
if ch == nil {
var w waiter.Entry
w, ch = waiter.NewChannelEntry(waiter.ReadableEvents)
if err := epfile.EventRegister(&w); err != nil {
return 0, nil, err
}
defer epfile.EventUnregister(&w)
} else {
// Set up the timer if a timeout was specified.
if timeoutInNanos > 0 && !haveDeadline {
timeoutDur := time.Duration(timeoutInNanos) * time.Nanosecond
deadline = t.Kernel().MonotonicClock().Now().Add(timeoutDur)
haveDeadline = true
}
if err := t.BlockWithDeadline(ch, haveDeadline, deadline); err != nil {
if linuxerr.Equals(linuxerr.ETIMEDOUT, err) {
err = nil
}
return 0, nil, err
}
}
}
return uintptr(len(r)), nil, nil
}
// EpollWait implements the epoll_wait(2) linux syscall.
// EpollWait implements Linux syscall epoll_wait(2).
func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
epfd := args[0].Int()
eventsAddr := args[1].Pointer()
maxEvents := int(args[2].Int())
// Convert milliseconds to nanoseconds.
timeoutInNanos := int64(args[3].Int()) * 1000000
return waitEpoll(t, epfd, eventsAddr, maxEvents, timeoutInNanos)
}
// EpollPwait implements the epoll_pwait(2) linux syscall.
// EpollPwait implements Linux syscall epoll_pwait(2).
func EpollPwait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
maskAddr := args[4].Pointer()
maskSize := uint(args[5].Uint())
if maskAddr != 0 {
mask, err := CopyInSigSet(t, maskAddr, maskSize)
if err != nil {
return 0, nil, err
}
oldmask := t.SignalMask()
t.SetSignalMask(mask)
t.SetSavedSignalMask(oldmask)
if err := setTempSignalSet(t, maskAddr, maskSize); err != nil {
return 0, nil, err
}
return EpollWait(t, args)
}
// EpollPwait2 implements the epoll_pwait(2) linux syscall.
// EpollPwait2 implements Linux syscall epoll_pwait(2).
func EpollPwait2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
epfd := args[0].Int()
eventsAddr := args[1].Pointer()
@@ -162,26 +220,16 @@ func EpollPwait2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.S
var timeoutInNanos int64 = -1
if haveTimeout {
timeout, err := copyTimespecIn(t, timeoutPtr)
if err != nil {
var timeout linux.Timespec
if _, err := timeout.CopyIn(t, timeoutPtr); err != nil {
return 0, nil, err
}
timeoutInNanos = timeout.ToNsec()
}
if maskAddr != 0 {
mask, err := CopyInSigSet(t, maskAddr, maskSize)
if err != nil {
return 0, nil, err
}
oldmask := t.SignalMask()
t.SetSignalMask(mask)
t.SetSavedSignalMask(oldmask)
if err := setTempSignalSet(t, maskAddr, maskSize); err != nil {
return 0, nil, err
}
return waitEpoll(t, epfd, eventsAddr, maxEvents, timeoutInNanos)
}
// LINT.ThenChange(vfs2/epoll.go)
+14 -9
View File
@@ -18,14 +18,13 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/eventfd"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/eventfd"
)
// Eventfd2 implements linux syscall eventfd2(2).
func Eventfd2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
initVal := args[0].Int()
initVal := uint64(args[0].Uint())
flags := uint(args[1].Uint())
allOps := uint(linux.EFD_SEMAPHORE | linux.EFD_NONBLOCK | linux.EFD_CLOEXEC)
@@ -33,13 +32,19 @@ func Eventfd2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
return 0, nil, linuxerr.EINVAL
}
event := eventfd.New(t, uint64(initVal), flags&linux.EFD_SEMAPHORE != 0)
event.SetFlags(fs.SettableFileFlags{
NonBlocking: flags&linux.EFD_NONBLOCK != 0,
})
defer event.DecRef(t)
vfsObj := t.Kernel().VFS()
fileFlags := uint32(linux.O_RDWR)
if flags&linux.EFD_NONBLOCK != 0 {
fileFlags |= linux.O_NONBLOCK
}
semMode := flags&linux.EFD_SEMAPHORE != 0
eventfd, err := eventfd.New(t, vfsObj, initVal, semMode, fileFlags)
if err != nil {
return 0, nil, err
}
defer eventfd.DecRef(t)
fd, err := t.NewFDFrom(0, event, kernel.FDFlags{
fd, err := t.NewFDFromVFS2(0, eventfd, kernel.FDFlags{
CloseOnExec: flags&linux.EFD_CLOEXEC != 0,
})
if err != nil {
File diff suppressed because it is too large Load Diff
+151 -206
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The gVisor Authors.
// Copyright 2020 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.
@@ -15,240 +15,185 @@
package linux
import (
"bytes"
"io"
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/usermem"
)
// LINT.IfChange
// Getdents implements linux syscall getdents(2) for 64bit systems.
// Getdents implements Linux syscall getdents(2).
func Getdents(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
fd := args[0].Int()
addr := args[1].Pointer()
size := int(args[2].Uint())
minSize := int(smallestDirent(t.Arch()))
if size < minSize {
// size is smaller than smallest possible dirent.
return 0, nil, linuxerr.EINVAL
}
n, err := getdents(t, fd, addr, size, (*dirent).Serialize)
return n, nil, err
return getdents(t, args, false /* isGetdents64 */)
}
// Getdents64 implements linux syscall getdents64(2).
// Getdents64 implements Linux syscall getdents64(2).
func Getdents64(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
return getdents(t, args, true /* isGetdents64 */)
}
// DirentStructBytesWithoutName is enough to fit (struct linux_dirent) and
// (struct linux_dirent64) without accounting for the name parameter.
const DirentStructBytesWithoutName = 8 + 8 + 2 + 1 + 1
func getdents(t *kernel.Task, args arch.SyscallArguments, isGetdents64 bool) (uintptr, *kernel.SyscallControl, error) {
fd := args[0].Int()
addr := args[1].Pointer()
size := int(args[2].Uint())
minSize := int(smallestDirent64(t.Arch()))
if size < minSize {
// size is smaller than smallest possible dirent.
if size < DirentStructBytesWithoutName {
return 0, nil, linuxerr.EINVAL
}
n, err := getdents(t, fd, addr, size, (*dirent).Serialize64)
return n, nil, err
}
// getdents implements the core of getdents(2)/getdents64(2).
// f is the syscall implementation dirent serialization function.
func getdents(t *kernel.Task, fd int32, addr hostarch.Addr, size int, f func(*dirent, io.Writer) (int, error)) (uintptr, error) {
dir := t.GetFile(fd)
if dir == nil {
return 0, linuxerr.EBADF
file := t.GetFileVFS2(fd)
if file == nil {
return 0, nil, linuxerr.EBADF
}
defer dir.DecRef(t)
defer file.DecRef(t)
w := &usermem.IOReadWriter{
Ctx: t,
IO: t.MemoryManager(),
Addr: addr,
Opts: usermem.IOOpts{
AddressSpaceActive: true,
},
// We want to be sure of the allowed buffer size before calling IterDirents,
// because this function depends on IterDirents saving state of which dirent
// was the last one that was successfully operated on.
allowedSize, err := t.MemoryManager().EnsurePMAsExist(t, addr, int64(size), usermem.IOOpts{
AddressSpaceActive: true,
})
if allowedSize == 0 {
return 0, nil, err
}
ds := newDirentSerializer(f, w, t.Arch(), size)
rerr := dir.Readdir(t, ds)
cb := getGetdentsCallback(t, int(allowedSize), size, isGetdents64)
err = file.IterDirents(t, cb)
n, _ := t.CopyOutBytes(addr, cb.buf[:cb.copied])
switch err := handleIOError(t, ds.Written() > 0, rerr, linuxerr.ERESTARTSYS, "getdents", dir); err {
case nil:
dir.Dirent.InotifyEvent(linux.IN_ACCESS, 0)
return uintptr(ds.Written()), nil
case io.EOF:
return 0, nil
default:
return 0, err
}
}
putGetdentsCallback(cb)
// oldDirentHdr is a fixed sized header matching the fixed size fields found in
// the old linux dirent struct.
//
// +marshal
type oldDirentHdr struct {
Ino uint64
Off uint64
Reclen uint16 `marshal:"unaligned"` // Struct ends mid-word.
}
// direntHdr is a fixed sized header matching the fixed size fields found in the
// new linux dirent struct.
//
// +marshal
type direntHdr struct {
OldHdr oldDirentHdr
Typ uint8 `marshal:"unaligned"` // Struct ends mid-word.
}
// dirent contains the data pointed to by a new linux dirent struct.
type dirent struct {
Hdr direntHdr
Name []byte
}
// newDirent returns a dirent from an fs.InodeOperationsInfo.
func newDirent(width uint, name string, attr fs.DentAttr, offset uint64) *dirent {
d := &dirent{
Hdr: direntHdr{
OldHdr: oldDirentHdr{
Ino: attr.InodeID,
Off: offset,
},
Typ: fs.ToDirentType(attr.Type),
},
Name: []byte(name),
}
d.Hdr.OldHdr.Reclen = d.padRec(int(width))
return d
}
// smallestDirent returns the size of the smallest possible dirent using
// the old linux dirent format.
func smallestDirent(a *arch.Context64) uint {
d := dirent{}
return uint(d.Hdr.OldHdr.SizeBytes()) + a.Width() + 1
}
// smallestDirent64 returns the size of the smallest possible dirent using
// the new linux dirent format.
func smallestDirent64(a *arch.Context64) uint {
d := dirent{}
return uint(d.Hdr.SizeBytes()) + a.Width()
}
// padRec pads the name field until the rec length is a multiple of the width,
// which must be a power of 2. It returns the padded rec length.
func (d *dirent) padRec(width int) uint16 {
a := d.Hdr.SizeBytes() + len(d.Name)
r := (a + width) &^ (width - 1)
padding := r - a
d.Name = append(d.Name, make([]byte, padding)...)
return uint16(r)
}
// Serialize64 serializes a Dirent struct to a byte slice, keeping the new
// linux dirent format. Returns the number of bytes serialized or an error.
func (d *dirent) Serialize64(w io.Writer) (int, error) {
n1, err := d.Hdr.WriteTo(w)
if err != nil {
return 0, err
}
n2, err := w.Write(d.Name)
if err != nil {
return 0, err
}
return int(n1) + n2, nil
}
// Serialize serializes a Dirent struct to a byte slice, using the old linux
// dirent format.
// Returns the number of bytes serialized or an error.
func (d *dirent) Serialize(w io.Writer) (int, error) {
n1, err := d.Hdr.OldHdr.WriteTo(w)
if err != nil {
return 0, err
}
n2, err := w.Write(d.Name)
if err != nil {
return 0, err
}
n3, err := w.Write([]byte{d.Hdr.Typ})
if err != nil {
return 0, err
}
return int(n1) + n2 + n3, nil
}
// direntSerializer implements fs.InodeOperationsInfoSerializer, serializing dirents to an
// io.Writer.
type direntSerializer struct {
serialize func(*dirent, io.Writer) (int, error)
w io.Writer
// width is the arch native value width.
width uint
// offset is the current dirent offset.
offset uint64
// written is the total bytes serialized.
written int
// size is the size of the buffer to serialize into.
size int
}
func newDirentSerializer(f func(d *dirent, w io.Writer) (int, error), w io.Writer, ac *arch.Context64, size int) *direntSerializer {
return &direntSerializer{
serialize: f,
w: w,
width: ac.Width(),
size: size,
}
}
// CopyOut implements fs.InodeOperationsInfoSerializer.CopyOut.
// It serializes and writes the fs.DentAttr to the direntSerializer io.Writer.
func (ds *direntSerializer) CopyOut(name string, attr fs.DentAttr) error {
ds.offset++
d := newDirent(ds.width, name, attr, ds.offset)
// Serialize dirent into a temp buffer.
var b bytes.Buffer
n, err := ds.serialize(d, &b)
if err != nil {
ds.offset--
return err
// Only report an error in case we didn't copy anything.
// If we did manage to give _something_ to the caller then the correct
// behaviour is to return success.
if n == 0 {
return 0, nil, err
}
// Check that we have enough room remaining to write the dirent.
if n > (ds.size - ds.written) {
ds.offset--
return io.EOF
return uintptr(n), nil, nil
}
type getdentsCallback struct {
t *kernel.Task
buf []byte
copied int
userReportedSize int
isGetdents64 bool
}
var getdentsCallbackPool = sync.Pool{
New: func() any {
return &getdentsCallback{}
},
}
func getGetdentsCallback(t *kernel.Task, size int, userReportedSize int, isGetdents64 bool) *getdentsCallback {
cb := getdentsCallbackPool.Get().(*getdentsCallback)
buf := cb.buf
if cap(buf) < size {
buf = make([]byte, size)
} else {
buf = buf[:size]
}
// Write out the temp buffer.
if _, err := b.WriteTo(ds.w); err != nil {
ds.offset--
return err
*cb = getdentsCallback{
t: t,
buf: buf,
copied: 0,
userReportedSize: userReportedSize,
isGetdents64: isGetdents64,
}
return cb
}
func putGetdentsCallback(cb *getdentsCallback) {
cb.t = nil
cb.buf = cb.buf[:0]
getdentsCallbackPool.Put(cb)
}
// Handle implements vfs.IterDirentsCallback.Handle.
func (cb *getdentsCallback) Handle(dirent vfs.Dirent) error {
remaining := len(cb.buf) - cb.copied
if cb.isGetdents64 {
// struct linux_dirent64 {
// ino64_t d_ino; /* 64-bit inode number */
// off64_t d_off; /* 64-bit offset to next structure */
// unsigned short d_reclen; /* Size of this dirent */
// unsigned char d_type; /* File type */
// char d_name[]; /* Filename (null-terminated) */
// };
size := DirentStructBytesWithoutName + len(dirent.Name)
size = (size + 7) &^ 7 // round up to multiple of 8
if size > remaining {
// This is only needed to imitate Linux, since it writes out to the user
// as it's iterating over dirs. We don't do that because we can't take
// the mm.mappingMu while holding the filesystem mutex.
if cb.copied == 0 && cb.userReportedSize >= size {
return linuxerr.EFAULT
}
return linuxerr.EINVAL
}
buf := cb.buf[cb.copied : cb.copied+size]
hostarch.ByteOrder.PutUint64(buf[0:8], dirent.Ino)
hostarch.ByteOrder.PutUint64(buf[8:16], uint64(dirent.NextOff))
hostarch.ByteOrder.PutUint16(buf[16:18], uint16(size))
buf[18] = dirent.Type
copy(buf[19:], dirent.Name)
// Zero out all remaining bytes in buf, including the NUL terminator
// after dirent.Name.
bufTail := buf[19+len(dirent.Name):]
for i := range bufTail {
bufTail[i] = 0
}
cb.copied += size
} else {
// struct linux_dirent {
// unsigned long d_ino; /* Inode number */
// unsigned long d_off; /* Offset to next linux_dirent */
// unsigned short d_reclen; /* Length of this linux_dirent */
// char d_name[]; /* Filename (null-terminated) */
// /* length is actually (d_reclen - 2 -
// offsetof(struct linux_dirent, d_name)) */
// /*
// char pad; // Zero padding byte
// char d_type; // File type (only since Linux
// // 2.6.4); offset is (d_reclen - 1)
// */
// };
if cb.t.Arch().Width() != 8 {
panic(fmt.Sprintf("unsupported sizeof(unsigned long): %d", cb.t.Arch().Width()))
}
size := DirentStructBytesWithoutName + len(dirent.Name)
size = (size + 7) &^ 7 // round up to multiple of sizeof(long)
if size > remaining {
if cb.copied == 0 && cb.userReportedSize >= size {
return linuxerr.EFAULT
}
return linuxerr.EINVAL
}
buf := cb.buf[cb.copied : cb.copied+size]
hostarch.ByteOrder.PutUint64(buf[0:8], dirent.Ino)
hostarch.ByteOrder.PutUint64(buf[8:16], uint64(dirent.NextOff))
hostarch.ByteOrder.PutUint16(buf[16:18], uint16(size))
copy(buf[18:], dirent.Name)
// Zero out all remaining bytes in buf, including the NUL terminator
// after dirent.Name and the zero padding byte between the name and
// dirent type.
bufTail := buf[18+len(dirent.Name) : size-1]
for i := range bufTail {
bufTail[i] = 0
}
buf[size-1] = dirent.Type
cb.copied += size
}
ds.written += n
return nil
}
// Written returns the total number of bytes written.
func (ds *direntSerializer) Written() int {
return ds.written
}
// LINT.ThenChange(vfs2/getdents.go)
+41 -41
View File
@@ -18,31 +18,26 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/anon"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
const allFlags = int(linux.IN_NONBLOCK | linux.IN_CLOEXEC)
const allFlags = linux.IN_NONBLOCK | linux.IN_CLOEXEC
// InotifyInit1 implements the inotify_init1() syscalls.
func InotifyInit1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
flags := int(args[0].Int())
flags := args[0].Int()
if flags&^allFlags != 0 {
return 0, nil, linuxerr.EINVAL
}
dirent := fs.NewDirent(t, anon.NewInode(t), "inotify")
fileFlags := fs.FileFlags{
Read: true,
Write: true,
NonBlocking: flags&linux.IN_NONBLOCK != 0,
ino, err := vfs.NewInotifyFD(t, t.Kernel().VFS(), uint32(flags))
if err != nil {
return 0, nil, err
}
n := fs.NewFile(t, dirent, fileFlags, fs.NewInotify(t))
defer n.DecRef(t)
defer ino.DecRef(t)
fd, err := t.NewFDFrom(0, n, kernel.FDFlags{
fd, err := t.NewFDFromVFS2(0, ino, kernel.FDFlags{
CloseOnExec: flags&linux.IN_CLOEXEC != 0,
})
@@ -61,21 +56,21 @@ func InotifyInit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.S
// fdToInotify resolves an fd to an inotify object. If successful, the file will
// have an extra ref and the caller is responsible for releasing the ref.
func fdToInotify(t *kernel.Task, fd int32) (*fs.Inotify, *fs.File, error) {
file := t.GetFile(fd)
if file == nil {
func fdToInotify(t *kernel.Task, fd int32) (*vfs.Inotify, *vfs.FileDescription, error) {
f := t.GetFileVFS2(fd)
if f == nil {
// Invalid fd.
return nil, nil, linuxerr.EBADF
}
ino, ok := file.FileOperations.(*fs.Inotify)
ino, ok := f.Impl().(*vfs.Inotify)
if !ok {
// Not an inotify fd.
file.DecRef(t)
f.DecRef(t)
return nil, nil, linuxerr.EINVAL
}
return ino, file, nil
return ino, f, nil
}
// InotifyAddWatch implements the inotify_add_watch() syscall.
@@ -84,39 +79,44 @@ func InotifyAddWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kern
addr := args[1].Pointer()
mask := args[2].Uint()
// "IN_DONT_FOLLOW: Don't dereference pathname if it is a symbolic link."
// -- inotify(7)
resolve := mask&linux.IN_DONT_FOLLOW == 0
// "EINVAL: The given event mask contains no valid events."
// -- inotify_add_watch(2)
if validBits := mask & linux.ALL_INOTIFY_BITS; validBits == 0 {
if mask&linux.ALL_INOTIFY_BITS == 0 {
return 0, nil, linuxerr.EINVAL
}
ino, file, err := fdToInotify(t, fd)
// "IN_DONT_FOLLOW: Don't dereference pathname if it is a symbolic link."
// -- inotify(7)
follow := followFinalSymlink
if mask&linux.IN_DONT_FOLLOW != 0 {
follow = nofollowFinalSymlink
}
ino, f, err := fdToInotify(t, fd)
if err != nil {
return 0, nil, err
}
defer file.DecRef(t)
defer f.DecRef(t)
path, _, err := copyInPath(t, addr, false /* allowEmpty */)
path, err := copyInPath(t, addr)
if err != nil {
return 0, nil, err
}
if mask&linux.IN_ONLYDIR != 0 {
path.Dir = true
}
tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, follow)
if err != nil {
return 0, nil, err
}
defer tpop.Release(t)
d, err := t.Kernel().VFS().GetDentryAt(t, t.Credentials(), &tpop.pop, &vfs.GetDentryOptions{})
if err != nil {
return 0, nil, err
}
defer d.DecRef(t)
err = fileOpOn(t, linux.AT_FDCWD, path, resolve, func(root *fs.Dirent, dirent *fs.Dirent, _ uint) error {
// "IN_ONLYDIR: Only watch pathname if it is a directory." -- inotify(7)
if onlyDir := mask&linux.IN_ONLYDIR != 0; onlyDir && !fs.IsDir(dirent.Inode.StableAttr) {
return linuxerr.ENOTDIR
}
// Copy out to the return frame.
fd = ino.AddWatch(dirent, mask)
return nil
})
return uintptr(fd), nil, err // Return from the existing value.
return uintptr(ino.AddWatch(d.Dentry(), mask)), nil, nil
}
// InotifyRmWatch implements the inotify_rm_watch() syscall.
@@ -124,10 +124,10 @@ func InotifyRmWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne
fd := args[0].Int()
wd := args[1].Int()
ino, file, err := fdToInotify(t, fd)
ino, f, err := fdToInotify(t, fd)
if err != nil {
return 0, nil, err
}
defer file.DecRef(t)
defer f.DecRef(t)
return 0, nil, ino.RmWatch(t, wd)
}
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package vfs2
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
-58
View File
@@ -1,58 +0,0 @@
// Copyright 2018 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.
package linux
import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
)
// LINT.IfChange
// Lseek implements linux syscall lseek(2).
func Lseek(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
fd := args[0].Int()
offset := args[1].Int64()
whence := args[2].Int()
file := t.GetFile(fd)
if file == nil {
return 0, nil, linuxerr.EBADF
}
defer file.DecRef(t)
var sw fs.SeekWhence
switch whence {
case 0:
sw = fs.SeekSet
case 1:
sw = fs.SeekCurrent
case 2:
sw = fs.SeekEnd
default:
return 0, nil, linuxerr.EINVAL
}
offset, serr := file.Seek(t, sw, offset)
err := handleIOError(t, false /* partialResult */, serr, linuxerr.ERESTARTSYS, "lseek", file)
if err != nil {
return 0, nil, err
}
return uintptr(offset), nil, err
}
// LINT.ThenChange(vfs2/read_write.go)
+11 -13
View File
@@ -21,6 +21,7 @@ import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/mm"
@@ -35,9 +36,7 @@ func Brk(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallCo
return uintptr(addr), nil, nil
}
// LINT.IfChange
// Mmap implements linux syscall mmap(2).
// Mmap implements Linux syscall mmap(2).
func Mmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
prot := args[2].Int()
flags := args[3].Int()
@@ -81,19 +80,18 @@ func Mmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC
if !anon {
// Convert the passed FD to a file reference.
file := t.GetFile(fd)
file := t.GetFileVFS2(fd)
if file == nil {
return 0, nil, linuxerr.EBADF
}
defer file.DecRef(t)
flags := file.Flags()
// mmap unconditionally requires that the FD is readable.
if !flags.Read {
if !file.IsReadable() {
return 0, nil, linuxerr.EACCES
}
// MAP_SHARED requires that the FD be writable for PROT_WRITE.
if shared && !flags.Write {
if shared && !file.IsWritable() {
opts.MaxPerms.Write = false
}
@@ -101,22 +99,22 @@ func Mmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC
return 0, nil, err
}
} else if shared {
// Back shared anonymous mappings with a special mappable.
// Back shared anonymous mappings with an anonymous tmpfs file.
opts.Offset = 0
m, err := mm.NewSharedAnonMappable(opts.Length, t.Kernel())
file, err := tmpfs.NewZeroFile(t, t.Credentials(), t.Kernel().ShmMount(), opts.Length)
if err != nil {
return 0, nil, err
}
opts.MappingIdentity = m // transfers ownership of m to opts
opts.Mappable = m
defer file.DecRef(t)
if err := file.ConfigureMMap(t, &opts); err != nil {
return 0, nil, err
}
}
rv, err := t.MemoryManager().MMap(t, opts)
return uintptr(rv), nil, err
}
// LINT.ThenChange(vfs2/mmap.go)
// Munmap implements linux syscall munmap(2).
func Munmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
return 0, nil, t.MemoryManager().MUnmap(t, args[0].Pointer(), args[1].Uint64())
+101 -83
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The gVisor Authors.
// Copyright 2020 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.
@@ -16,11 +16,13 @@ package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/bits"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
// Mount implements Linux syscall mount(2).
@@ -31,21 +33,76 @@ func Mount(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
flags := args[3].Uint64()
dataAddr := args[4].Pointer()
// Must have CAP_SYS_ADMIN in the current mount namespace's associated user
// namespace.
creds := t.Credentials()
if !creds.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespaceVFS2().Owner) {
return 0, nil, linuxerr.EPERM
}
// Ignore magic value that was required before Linux 2.4.
if flags&linux.MS_MGC_MSK == linux.MS_MGC_VAL {
flags = flags &^ linux.MS_MGC_MSK
}
// Silently allow MS_NOSUID, since we don't implement set-id bits anyway.
const unsupported = linux.MS_REMOUNT | linux.MS_SLAVE |
linux.MS_UNBINDABLE | linux.MS_MOVE | linux.MS_REC | linux.MS_NODIRATIME |
linux.MS_STRICTATIME
// Linux just allows passing any flags to mount(2) - it won't fail when
// unknown or unsupported flags are passed. Since we don't implement
// everything, we fail explicitly on flags that are unimplemented.
if flags&(unsupported) != 0 {
return 0, nil, linuxerr.EINVAL
}
// For null-terminated strings related to mount(2), Linux copies in at most
// a page worth of data. See fs/namespace.c:copy_mount_string().
targetPath, err := copyInPath(t, targetAddr)
if err != nil {
return 0, nil, err
}
target, err := getTaskPathOperation(t, linux.AT_FDCWD, targetPath, disallowEmptyPath, nofollowFinalSymlink)
if err != nil {
return 0, nil, err
}
defer target.Release(t)
if flags&linux.MS_BIND == linux.MS_BIND {
var sourcePath fspath.Path
sourcePath, err = copyInPath(t, sourceAddr)
if err != nil {
return 0, nil, err
}
var sourceTpop taskPathOperation
sourceTpop, err = getTaskPathOperation(t, linux.AT_FDCWD, sourcePath, disallowEmptyPath, nofollowFinalSymlink)
if err != nil {
return 0, nil, err
}
defer sourceTpop.Release(t)
_, err = t.Kernel().VFS().BindAt(t, creds, &sourceTpop.pop, &target.pop)
return 0, nil, err
}
const propagationFlags = linux.MS_SHARED | linux.MS_PRIVATE | linux.MS_SLAVE | linux.MS_UNBINDABLE
if propFlag := flags & propagationFlags; propFlag != 0 {
// Check if flags is a power of 2. If not then more than one flag is set.
if !bits.IsPowerOfTwo64(propFlag) {
return 0, nil, linuxerr.EINVAL
}
propType := vfs.PropagationTypeFromLinux(propFlag)
return 0, nil, t.Kernel().VFS().SetMountPropagationAt(t, creds, &target.pop, propType)
}
// Only copy in source, fstype, and data if we are doing a normal mount.
source, err := t.CopyInString(sourceAddr, hostarch.PageSize)
if err != nil {
return 0, nil, err
}
fsType, err := t.CopyInString(typeAddr, hostarch.PageSize)
if err != nil {
return 0, nil, err
}
sourcePath, _, err := copyInPath(t, sourceAddr, true /* allowEmpty */)
if err != nil {
return 0, nil, err
}
targetPath, _, err := copyInPath(t, targetAddr, false /* allowEmpty */)
if err != nil {
return 0, nil, err
}
data := ""
if dataAddr != 0 {
// In Linux, a full page is always copied in regardless of null
@@ -57,69 +114,25 @@ func Mount(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
return 0, nil, err
}
}
// Ignore magic value that was required before Linux 2.4.
if flags&linux.MS_MGC_MSK == linux.MS_MGC_VAL {
flags = flags &^ linux.MS_MGC_MSK
}
// Must have CAP_SYS_ADMIN in the mount namespace's associated user
// namespace.
if !t.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespace().UserNamespace()) {
return 0, nil, linuxerr.EPERM
}
const unsupportedOps = linux.MS_REMOUNT | linux.MS_BIND |
linux.MS_SHARED | linux.MS_PRIVATE | linux.MS_SLAVE |
linux.MS_UNBINDABLE | linux.MS_MOVE
// Silently allow MS_NOSUID, since we don't implement set-id bits
// anyway.
const unsupportedFlags = linux.MS_NODEV |
linux.MS_NODIRATIME | linux.MS_STRICTATIME
// Linux just allows passing any flags to mount(2) - it won't fail when
// unknown or unsupported flags are passed. Since we don't implement
// everything, we fail explicitly on flags that are unimplemented.
if flags&(unsupportedOps|unsupportedFlags) != 0 {
return 0, nil, linuxerr.EINVAL
}
rsys, ok := fs.FindFilesystem(fsType)
if !ok {
return 0, nil, linuxerr.ENODEV
}
if !rsys.AllowUserMount() {
return 0, nil, linuxerr.EPERM
}
var superFlags fs.MountSourceFlags
var opts vfs.MountOptions
if flags&linux.MS_NOATIME == linux.MS_NOATIME {
superFlags.NoAtime = true
}
if flags&linux.MS_RDONLY == linux.MS_RDONLY {
superFlags.ReadOnly = true
opts.Flags.NoATime = true
}
if flags&linux.MS_NOEXEC == linux.MS_NOEXEC {
superFlags.NoExec = true
opts.Flags.NoExec = true
}
rootInode, err := rsys.Mount(t, sourcePath, superFlags, data, nil)
if err != nil {
return 0, nil, linuxerr.EINVAL
if flags&linux.MS_NODEV == linux.MS_NODEV {
opts.Flags.NoDev = true
}
if err := fileOpOn(t, linux.AT_FDCWD, targetPath, true /* resolve */, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
// Mount will take a reference on rootInode if successful.
return t.MountNamespace().Mount(t, d, rootInode)
}); err != nil {
// Something went wrong. Drop our ref on rootInode before
// returning the error.
rootInode.DecRef(t)
return 0, nil, err
if flags&linux.MS_NOSUID == linux.MS_NOSUID {
opts.Flags.NoSUID = true
}
return 0, nil, nil
if flags&linux.MS_RDONLY == linux.MS_RDONLY {
opts.ReadOnly = true
}
opts.GetFilesystemOptions.Data = data
_, err = t.Kernel().VFS().MountAt(t, creds, source, &target.pop, fsType, &opts)
return 0, nil, err
}
// Umount2 implements Linux syscall umount2(2).
@@ -127,28 +140,33 @@ func Umount2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysca
addr := args[0].Pointer()
flags := args[1].Int()
// Must have CAP_SYS_ADMIN in the mount namespace's associated user
// namespace.
//
// Currently, this is always the init task's user namespace.
creds := t.Credentials()
if !creds.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespaceVFS2().Owner) {
return 0, nil, linuxerr.EPERM
}
const unsupported = linux.MNT_FORCE | linux.MNT_EXPIRE
if flags&unsupported != 0 {
return 0, nil, linuxerr.EINVAL
}
path, _, err := copyInPath(t, addr, false /* allowEmpty */)
path, err := copyInPath(t, addr)
if err != nil {
return 0, nil, err
}
tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink(flags&linux.UMOUNT_NOFOLLOW == 0))
if err != nil {
return 0, nil, err
}
defer tpop.Release(t)
// Must have CAP_SYS_ADMIN in the mount namespace's associated user
// namespace.
//
// Currently, this is always the init task's user namespace.
if !t.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespace().UserNamespace()) {
return 0, nil, linuxerr.EPERM
opts := vfs.UmountOptions{
Flags: uint32(flags &^ linux.UMOUNT_NOFOLLOW),
}
resolve := flags&linux.UMOUNT_NOFOLLOW != linux.UMOUNT_NOFOLLOW
detachOnly := flags&linux.MNT_DETACH == linux.MNT_DETACH
return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolve, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
return t.MountNamespace().Unmount(t, d, detachOnly)
})
return 0, nil, t.Kernel().VFS().UmountAt(t, creds, &tpop.pop, &opts)
}
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package vfs2
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
+26 -37
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The gVisor Authors.
// Copyright 2020 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.
@@ -20,59 +20,48 @@ import (
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/marshal/primitive"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/pipefs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/pipe"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
// LINT.IfChange
// Pipe implements Linux syscall pipe(2).
func Pipe(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
return 0, nil, pipe2(t, addr, 0)
}
// pipe2 implements the actual system call with flags.
func pipe2(t *kernel.Task, addr hostarch.Addr, flags uint) (uintptr, error) {
// Pipe2 implements Linux syscall pipe2(2).
func Pipe2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
flags := args[1].Int()
return 0, nil, pipe2(t, addr, flags)
}
func pipe2(t *kernel.Task, addr hostarch.Addr, flags int32) error {
if flags&^(linux.O_NONBLOCK|linux.O_CLOEXEC) != 0 {
return 0, linuxerr.EINVAL
return linuxerr.EINVAL
}
r, w, err := pipefs.NewConnectedPipeFDs(t, t.Kernel().PipeMount(), uint32(flags&linux.O_NONBLOCK))
if err != nil {
return err
}
r, w := pipe.NewConnectedPipe(t, pipe.DefaultPipeSize)
r.SetFlags(linuxToFlags(flags).Settable())
defer r.DecRef(t)
w.SetFlags(linuxToFlags(flags).Settable())
defer w.DecRef(t)
fds, err := t.NewFDs(0, []*fs.File{r, w}, kernel.FDFlags{
fds, err := t.NewFDsVFS2(0, []*vfs.FileDescription{r, w}, kernel.FDFlags{
CloseOnExec: flags&linux.O_CLOEXEC != 0,
})
if err != nil {
return 0, err
return err
}
if _, err := primitive.CopyInt32SliceOut(t, addr, fds); err != nil {
for _, fd := range fds {
if file, _ := t.FDTable().Remove(t, fd); file != nil {
if _, file := t.FDTable().Remove(t, fd); file != nil {
file.DecRef(t)
}
}
return 0, err
return err
}
return 0, nil
return nil
}
// Pipe implements linux syscall pipe(2).
func Pipe(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
n, err := pipe2(t, addr, 0)
return n, nil, err
}
// Pipe2 implements linux syscall pipe2(2).
func Pipe2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
flags := uint(args[1].Uint())
n, err := pipe2(t, addr, flags)
return n, nil, err
}
// LINT.ThenChange(vfs2/pipe.go)
+61 -38
View File
@@ -1,4 +1,4 @@
// Copyright 2018 The gVisor Authors.
// Copyright 2020 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.
@@ -15,20 +15,23 @@
package linux
import (
"fmt"
"time"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/sentry/limits"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/waiter"
)
// fileCap is the maximum allowable files for poll & select.
// fileCap is the maximum allowable files for poll & select. This has no
// equivalent in Linux; it exists in gVisor since allocation failure in Go is
// unrecoverable.
const fileCap = 1024 * 1024
// Masks for "readable", "writable", and "exceptional" events as defined by
@@ -47,9 +50,9 @@ const (
selectExceptEvents = linux.POLLPRI
)
// pollState tracks the associated file descriptor and waiter of a PollFD.
// pollState tracks the associated file description and waiter of a PollFD.
type pollState struct {
file *fs.File
file *vfs.FileDescription
waiter waiter.Entry
}
@@ -57,16 +60,16 @@ type pollState struct {
// stored in pfd.FD. If a channel is passed in, the waiter entry in "state" is
// used to register with the file for event notifications, and a reference to
// the file is stored in "state".
func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan struct{}) {
func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan struct{}) error {
if pfd.FD < 0 {
pfd.REvents = 0
return
return nil
}
file := t.GetFile(pfd.FD)
file := t.GetFileVFS2(pfd.FD)
if file == nil {
pfd.REvents = linux.POLLNVAL
return
return nil
}
if ch == nil {
@@ -74,11 +77,14 @@ func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan
} else {
state.file = file
state.waiter.Init(waiter.ChannelNotifier(ch), waiter.EventMaskFromLinux(uint32(pfd.Events)))
file.EventRegister(&state.waiter)
if err := file.EventRegister(&state.waiter); err != nil {
return err
}
}
r := file.Readiness(waiter.EventMaskFromLinux(uint32(pfd.Events)))
pfd.REvents = int16(r.ToLinux()) & pfd.Events
return nil
}
// releaseState releases all the pollState in "state".
@@ -110,7 +116,9 @@ func pollBlock(t *kernel.Task, pfd []linux.PollFD, timeout time.Duration) (time.
defer releaseState(t, state)
n := uintptr(0)
for i := range pfd {
initReadiness(t, &pfd[i], &state[i], ch)
if err := initReadiness(t, &pfd[i], &state[i], ch); err != nil {
return timeout, 0, err
}
if pfd[i].REvents != 0 {
n++
ch = nil
@@ -121,12 +129,12 @@ func pollBlock(t *kernel.Task, pfd []linux.PollFD, timeout time.Duration) (time.
return timeout, n, nil
}
forever := timeout < 0
haveTimeout := timeout >= 0
for n == 0 {
var err error
// Wait for a notification.
timeout, err = t.BlockWithTimeout(ch, !forever, timeout)
timeout, err = t.BlockWithTimeout(ch, haveTimeout, timeout)
if err != nil {
if linuxerr.Equals(linuxerr.ETIMEDOUT, err) {
err = nil
@@ -262,7 +270,7 @@ func doSelect(t *kernel.Task, nfds int, readFDs, writeFDs, exceptFDs hostarch.Ad
// immediately to ensure we don't leak. Note, another thread
// might be about to close fd. This is racy, but that's
// OK. Linux is racy in the same way.
file := t.GetFile(fd)
file := t.GetFileVFS2(fd)
if file == nil {
return 0, linuxerr.EBADF
}
@@ -371,7 +379,8 @@ func copyOutTimespecRemaining(t *kernel.Task, startNs ktime.Time, timeout time.D
}
remaining := timeoutRemaining(t, startNs, timeout)
tsRemaining := linux.NsecToTimespec(remaining.Nanoseconds())
return copyTimespecOut(t, timespecAddr, &tsRemaining)
_, err := tsRemaining.CopyOut(t, timespecAddr)
return err
}
// copyOutTimevalRemaining copies the time remaining in timeout to timevalAddr.
@@ -383,7 +392,8 @@ func copyOutTimevalRemaining(t *kernel.Task, startNs ktime.Time, timeout time.Du
}
remaining := timeoutRemaining(t, startNs, timeout)
tvRemaining := linux.NsecToTimeval(remaining.Nanoseconds())
return copyTimevalOut(t, timevalAddr, &tvRemaining)
_, err := tvRemaining.CopyOut(t, timevalAddr)
return err
}
// pollRestartBlock encapsulates the state required to restart poll(2) via
@@ -442,15 +452,8 @@ func Ppoll(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
startNs = t.Kernel().MonotonicClock().Now()
}
if maskAddr != 0 {
mask, err := CopyInSigSet(t, maskAddr, maskSize)
if err != nil {
return 0, nil, err
}
oldmask := t.SignalMask()
t.SetSignalMask(mask)
t.SetSavedSignalMask(oldmask)
if err := setTempSignalSet(t, maskAddr, maskSize); err != nil {
return 0, nil, err
}
_, n, err := doPoll(t, pfdAddr, nfds, timeout)
@@ -480,8 +483,8 @@ func Select(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
// Use a negative Duration to indicate "no timeout".
timeout := time.Duration(-1)
if timevalAddr != 0 {
timeval, err := copyTimevalIn(t, timevalAddr)
if err != nil {
var timeval linux.Timeval
if _, err := timeval.CopyIn(t, timevalAddr); err != nil {
return 0, nil, err
}
if timeval.Sec < 0 || timeval.Usec < 0 {
@@ -499,6 +502,12 @@ func Select(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
return n, nil, err
}
// +marshal
type sigSetWithSize struct {
sigsetAddr uint64
sizeofSigset uint64
}
// Pselect implements linux syscall pselect(2).
func Pselect(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
nfds := int(args[0].Int()) // select(2) uses an int.
@@ -519,19 +528,15 @@ func Pselect(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysca
}
if maskWithSizeAddr != 0 {
maskAddr, size, err := copyInSigSetWithSize(t, maskWithSizeAddr)
if err != nil {
if t.Arch().Width() != 8 {
panic(fmt.Sprintf("unsupported sizeof(void*): %d", t.Arch().Width()))
}
var maskStruct sigSetWithSize
if _, err := maskStruct.CopyIn(t, maskWithSizeAddr); err != nil {
return 0, nil, err
}
if maskAddr != 0 {
mask, err := CopyInSigSet(t, maskAddr, size)
if err != nil {
return 0, nil, err
}
oldmask := t.SignalMask()
t.SetSignalMask(mask)
t.SetSavedSignalMask(oldmask)
if err := setTempSignalSet(t, hostarch.Addr(maskStruct.sigsetAddr), uint(maskStruct.sizeofSigset)); err != nil {
return 0, nil, err
}
}
@@ -543,3 +548,21 @@ func Pselect(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysca
}
return n, nil, err
}
func setTempSignalSet(t *kernel.Task, maskAddr hostarch.Addr, maskSize uint) error {
if maskAddr == 0 {
return nil
}
if maskSize != linux.SignalSetSize {
return linuxerr.EINVAL
}
var mask linux.SignalSet
if _, err := mask.CopyIn(t, maskAddr); err != nil {
return err
}
mask &^= kernel.UnblockableSignals
oldmask := t.SignalMask()
t.SetSignalMask(mask)
t.SetSavedSignalMask(oldmask)
return nil
}

Some files were not shown because too many files have changed in this diff Show More