Port socket-related syscalls to VFS2.

Note that most kinds of sockets are not yet supported in VFS2
(only Unix sockets are partially supported at the moment), so
these syscalls will still generally fail. Enabling them allows
us to begin running socket tests for VFS2 as more features are
ported over.

Updates #1476, #1478, #1484, #1485.

PiperOrigin-RevId: 306292294
This commit is contained in:
Dean Deng 2020-04-13 13:01:28 -07:00 committed by gVisor bot
parent aa75a3da51
commit 5d885d7fb2
6 changed files with 1238 additions and 19 deletions

View File

@ -307,6 +307,61 @@ func (f *FDTable) NewFDs(ctx context.Context, fd int32, files []*fs.File, flags
return fds, nil
}
// NewFDsVFS2 allocates new FDs guaranteed to be the lowest number available
// greater than or equal to the fd parameter. All files will share the set
// flags. Success is guaranteed to be all or none.
func (f *FDTable) NewFDsVFS2(ctx context.Context, fd int32, files []*vfs.FileDescription, flags FDFlags) (fds []int32, err error) {
if fd < 0 {
// Don't accept negative FDs.
return nil, syscall.EINVAL
}
// Default limit.
end := int32(math.MaxInt32)
// Ensure we don't get past the provided limit.
if limitSet := limits.FromContext(ctx); limitSet != nil {
lim := limitSet.Get(limits.NumberOfFiles)
if lim.Cur != limits.Infinity {
end = int32(lim.Cur)
}
if fd >= end {
return nil, syscall.EMFILE
}
}
f.mu.Lock()
defer f.mu.Unlock()
// From f.next to find available fd.
if fd < f.next {
fd = f.next
}
// Install all entries.
for i := fd; i < end && len(fds) < len(files); i++ {
if d, _, _ := f.getVFS2(i); d == nil {
f.setVFS2(i, files[len(fds)], flags) // Set the descriptor.
fds = append(fds, i) // Record the file descriptor.
}
}
// Failure? Unwind existing FDs.
if len(fds) < len(files) {
for _, i := range fds {
f.setVFS2(i, nil, FDFlags{}) // Zap entry.
}
return nil, syscall.EMFILE
}
if fd == f.next {
// Update next search start position.
f.next = fds[len(fds)-1] + 1
}
return fds, nil
}
// NewFDVFS2 allocates a file descriptor greater than or equal to minfd for
// the given file description. If it succeeds, it takes a reference on file.
func (f *FDTable) NewFDVFS2(ctx context.Context, minfd int32, file *vfs.FileDescription, flags FDFlags) (int32, error) {

View File

@ -777,6 +777,15 @@ func (t *Task) NewFDs(fd int32, files []*fs.File, flags FDFlags) ([]int32, error
return t.fdTable.NewFDs(t, fd, files, flags)
}
// NewFDsVFS2 is a convenience wrapper for t.FDTable().NewFDsVFS2.
//
// This automatically passes the task as the context.
//
// Precondition: same as FDTable.
func (t *Task) NewFDsVFS2(fd int32, files []*vfs.FileDescription, flags FDFlags) ([]int32, error) {
return t.fdTable.NewFDsVFS2(t, fd, files, flags)
}
// NewFDFrom is a convenience wrapper for t.FDTable().NewFDs with a single file.
//
// This automatically passes the task as the context.

View File

@ -31,6 +31,8 @@ import (
"gvisor.dev/gvisor/pkg/usermem"
)
// LINT.IfChange
// minListenBacklog is the minimum reasonable backlog for listening sockets.
const minListenBacklog = 8
@ -244,7 +246,10 @@ func SocketPair(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy
// Copy the file descriptors out.
if _, err := t.CopyOut(socks, fds); err != nil {
// Note that we don't close files here; see pipe(2) also.
for _, fd := range fds {
_, file := t.FDTable().Remove(fd)
file.DecRef()
}
return 0, nil, err
}
@ -1128,3 +1133,5 @@ func SendTo(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
n, err := sendTo(t, fd, bufPtr, bufLen, flags, namePtr, nameLen)
return n, nil, err
}
// LINT.ThenChange(./vfs2/socket.go)

View File

@ -21,6 +21,7 @@ go_library(
"poll.go",
"read_write.go",
"setstat.go",
"socket.go",
"stat.go",
"stat_amd64.go",
"stat_arm64.go",
@ -32,6 +33,7 @@ go_library(
visibility = ["//:sandbox"],
deps = [
"//pkg/abi/linux",
"//pkg/binary",
"//pkg/bits",
"//pkg/fspath",
"//pkg/gohacks",
@ -43,10 +45,14 @@ go_library(
"//pkg/sentry/limits",
"//pkg/sentry/loader",
"//pkg/sentry/memmap",
"//pkg/sentry/socket",
"//pkg/sentry/socket/control",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/syscalls",
"//pkg/sentry/syscalls/linux",
"//pkg/sentry/vfs",
"//pkg/sync",
"//pkg/syserr",
"//pkg/syserror",
"//pkg/usermem",
"//pkg/waiter",

View File

@ -44,21 +44,22 @@ func Override(table map[uintptr]kernel.Syscall) {
table[32] = syscalls.Supported("dup", Dup)
table[33] = syscalls.Supported("dup2", Dup2)
delete(table, 40) // sendfile
delete(table, 41) // socket
delete(table, 42) // connect
delete(table, 43) // accept
delete(table, 44) // sendto
delete(table, 45) // recvfrom
delete(table, 46) // sendmsg
delete(table, 47) // recvmsg
delete(table, 48) // shutdown
delete(table, 49) // bind
delete(table, 50) // listen
delete(table, 51) // getsockname
delete(table, 52) // getpeername
delete(table, 53) // socketpair
delete(table, 54) // setsockopt
delete(table, 55) // getsockopt
// TODO(gvisor.dev/issue/1485): Port all socket variants to VFS2.
table[41] = syscalls.PartiallySupported("socket", Socket, "In process of porting socket syscalls to VFS2.", nil)
table[42] = syscalls.PartiallySupported("connect", Connect, "In process of porting socket syscalls to VFS2.", nil)
table[43] = syscalls.PartiallySupported("accept", Accept, "In process of porting socket syscalls to VFS2.", nil)
table[44] = syscalls.PartiallySupported("sendto", SendTo, "In process of porting socket syscalls to VFS2.", nil)
table[45] = syscalls.PartiallySupported("recvfrom", RecvFrom, "In process of porting socket syscalls to VFS2.", nil)
table[46] = syscalls.PartiallySupported("sendmsg", SendMsg, "In process of porting socket syscalls to VFS2.", nil)
table[47] = syscalls.PartiallySupported("recvmsg", RecvMsg, "In process of porting socket syscalls to VFS2.", nil)
table[48] = syscalls.PartiallySupported("shutdown", Shutdown, "In process of porting socket syscalls to VFS2.", nil)
table[49] = syscalls.PartiallySupported("bind", Bind, "In process of porting socket syscalls to VFS2.", nil)
table[50] = syscalls.PartiallySupported("listen", Listen, "In process of porting socket syscalls to VFS2.", nil)
table[51] = syscalls.PartiallySupported("getsockname", GetSockName, "In process of porting socket syscalls to VFS2.", nil)
table[52] = syscalls.PartiallySupported("getpeername", GetPeerName, "In process of porting socket syscalls to VFS2.", nil)
table[53] = syscalls.PartiallySupported("socketpair", SocketPair, "In process of porting socket syscalls to VFS2.", nil)
table[54] = syscalls.PartiallySupported("getsockopt", GetSockOpt, "In process of porting socket syscalls to VFS2.", nil)
table[55] = syscalls.PartiallySupported("setsockopt", SetSockOpt, "In process of porting socket syscalls to VFS2.", nil)
table[59] = syscalls.Supported("execve", Execve)
table[72] = syscalls.Supported("fcntl", Fcntl)
delete(table, 73) // flock
@ -144,7 +145,8 @@ func Override(table map[uintptr]kernel.Syscall) {
delete(table, 285) // fallocate
table[286] = syscalls.Supported("timerfd_settime", TimerfdSettime)
table[287] = syscalls.Supported("timerfd_gettime", TimerfdGettime)
delete(table, 288) // accept4
// TODO(gvisor.dev/issue/1485): Port all socket variants to VFS2.
table[288] = syscalls.PartiallySupported("accept4", Accept4, "In process of porting socket syscalls to VFS2.", nil)
delete(table, 289) // signalfd4
delete(table, 290) // eventfd2
table[291] = syscalls.Supported("epoll_create1", EpollCreate1)
@ -153,9 +155,11 @@ func Override(table map[uintptr]kernel.Syscall) {
delete(table, 294) // inotify_init1
table[295] = syscalls.Supported("preadv", Preadv)
table[296] = syscalls.Supported("pwritev", Pwritev)
delete(table, 299) // recvmmsg
// TODO(gvisor.dev/issue/1485): Port all socket variants to VFS2.
table[299] = syscalls.PartiallySupported("recvmmsg", RecvMMsg, "In process of porting socket syscalls to VFS2.", nil)
table[306] = syscalls.Supported("syncfs", Syncfs)
delete(table, 307) // sendmmsg
// TODO(gvisor.dev/issue/1485): Port all socket variants to VFS2.
table[307] = syscalls.PartiallySupported("sendmmsg", SendMMsg, "In process of porting socket syscalls to VFS2.", nil)
table[316] = syscalls.Supported("renameat2", Renameat2)
delete(table, 319) // memfd_create
table[322] = syscalls.Supported("execveat", Execveat)

File diff suppressed because it is too large Load Diff