hostinet: Generate socket validation and filters from list of supported sockets

This cuts down on the amount of duplication between socket() syscall handling
and the filters.

No new functionality.

PiperOrigin-RevId: 511862459
This commit is contained in:
Nicolas Lacasse
2023-02-23 12:57:01 -08:00
committed by gVisor bot
parent 71781cc29a
commit f905e456ed
2 changed files with 60 additions and 50 deletions
+43 -28
View File
@@ -48,6 +48,26 @@ const (
maxControlLen = 1024
)
// AllowedSocketType is a tuple of socket family, type, and protocol.
type AllowedSocketType struct {
Family int
Type int
Protocol int
}
// AllowedSocketTypes are the socket types which are supported by hostinet.
// These are used to validate the arguments to socket(), and also to generate
// syscall filters.
var AllowedSocketTypes = []AllowedSocketType{
// Family, Type, Protocol.
{unix.AF_INET, unix.SOCK_STREAM, unix.IPPROTO_TCP},
{unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP},
{unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_ICMP},
{unix.AF_INET6, unix.SOCK_STREAM, unix.IPPROTO_TCP},
{unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP},
}
// Socket implements socket.Socket (and by extension, vfs.FileDescriptionImpl)
// for host sockets.
//
@@ -173,41 +193,36 @@ func (p *socketProvider) Socket(t *kernel.Task, stypeflags linux.SockType, proto
return nil, nil
}
// Only accept TCP and UDP.
stype := stypeflags & linux.SOCK_TYPE_MASK
switch stype {
case unix.SOCK_STREAM:
switch protocol {
case unix.IPPROTO_IP:
// IPPROTO_IP with SOCK_STREAM causes proto to actually
// be IPPROTO_TCP.
protocol = unix.IPPROTO_TCP
case unix.IPPROTO_TCP:
// ok
default:
return nil, nil
// Convert generic IPPROTO_IP protocol to the actual protocol depending
// on family and type.
if protocol == linux.IPPROTO_IP && (p.family == linux.AF_INET || p.family == linux.AF_INET6) {
switch stype {
case linux.SOCK_STREAM:
protocol = linux.IPPROTO_TCP
case linux.SOCK_DGRAM:
protocol = linux.IPPROTO_UDP
}
case unix.SOCK_DGRAM:
switch protocol {
case unix.IPPROTO_IP:
// IPPROTO_IP with SOCK_DGRAM causes proto to actually
// be IPPROTO_UDP.
protocol = unix.IPPROTO_UDP
case unix.IPPROTO_ICMP:
// ok
case unix.IPPROTO_UDP:
// ok
default:
return nil, nil
}
// Validate the socket based on family, type, and protocol.
var supported bool
for _, allowed := range AllowedSocketTypes {
if p.family == allowed.Family && int(stype) == allowed.Type && protocol == allowed.Protocol {
supported = true
break
}
default:
}
if !supported {
// Return nil error here to give other socket providers a
// chance to create this socket.
return nil, nil
}
// Conservatively ignore all flags specified by the application and add
// SOCK_NONBLOCK since socketOperations requires it. Pass a protocol of 0
// to simplify the syscall filters, since 0 and IPPROTO_* are equivalent.
fd, err := unix.Socket(p.family, int(stype)|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, 0)
// SOCK_NONBLOCK since socketOperations requires it.
fd, err := unix.Socket(p.family, int(stype)|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, protocol)
if err != nil {
return nil, syserr.FromError(err)
}
+17 -22
View File
@@ -16,6 +16,7 @@ package filter
import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/seccomp"
"gvisor.dev/gvisor/pkg/sentry/socket/hostinet"
)
@@ -73,31 +74,24 @@ func hostInetFilters() seccomp.SyscallRules {
seccomp.EqualTo(unix.SHUT_RDWR),
},
},
unix.SYS_SOCKET: []seccomp.Rule{
{
seccomp.EqualTo(unix.AF_INET),
seccomp.EqualTo(unix.SOCK_STREAM | unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC),
seccomp.EqualTo(0),
},
{
seccomp.EqualTo(unix.AF_INET),
seccomp.EqualTo(unix.SOCK_DGRAM | unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC),
seccomp.EqualTo(0),
},
{
seccomp.EqualTo(unix.AF_INET6),
seccomp.EqualTo(unix.SOCK_STREAM | unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC),
seccomp.EqualTo(0),
},
{
seccomp.EqualTo(unix.AF_INET6),
seccomp.EqualTo(unix.SOCK_DGRAM | unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC),
seccomp.EqualTo(0),
},
},
unix.SYS_WRITEV: {},
}
// Generate rules for socket creation based on hostinet's supported
// socket types.
socketRules := []seccomp.Rule{}
for _, sock := range hostinet.AllowedSocketTypes {
socketRules = append(socketRules, seccomp.Rule{
seccomp.EqualTo(sock.Family),
// We always set SOCK_NONBLOCK and SOCK_CLOEXEC
seccomp.EqualTo(sock.Type | linux.SOCK_NONBLOCK | linux.SOCK_CLOEXEC),
seccomp.EqualTo(sock.Protocol),
})
}
rules[unix.SYS_SOCKET] = socketRules
// Generate rules for socket options based on hostinet's supported
// socket options.
getSockOptRules := []seccomp.Rule{}
setSockOptRules := []seccomp.Rule{}
for _, opt := range hostinet.SockOpts {
@@ -128,5 +122,6 @@ func hostInetFilters() seccomp.SyscallRules {
}
rules[unix.SYS_GETSOCKOPT] = getSockOptRules
rules[unix.SYS_SETSOCKOPT] = setSockOptRules
return rules
}