diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go index 9b4a64d14..d8b2fde0a 100644 --- a/pkg/sentry/socket/hostinet/socket.go +++ b/pkg/sentry/socket/hostinet/socket.go @@ -51,11 +51,18 @@ const ( // AllowedSocketType is a tuple of socket family, type, and protocol. type AllowedSocketType struct { - Family int - Type int + Family int + Type int + + // Protocol of AllowAllProtocols indicates that all protocols are + // allowed. Protocol int } +// AllowAllProtocols indicates that all protocols are allowed by the stack and +// in the syscall filters. +var AllowAllProtocols = -1 + // 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. @@ -82,6 +89,9 @@ var AllowedRawSocketTypes = []AllowedSocketType{ {unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_TCP}, {unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_UDP}, {unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_ICMPV6}, + + {unix.AF_PACKET, unix.SOCK_DGRAM, AllowAllProtocols}, + {unix.AF_PACKET, unix.SOCK_RAW, AllowAllProtocols}, } // Socket implements socket.Socket (and by extension, vfs.FileDescriptionImpl) @@ -212,8 +222,8 @@ func (p *socketProvider) Socket(t *kernel.Task, stypeflags linux.SockType, proto stype := stypeflags & linux.SOCK_TYPE_MASK - // Raw sockets require CAP_NET_RAW. - if stype == linux.SOCK_RAW { + // Raw and packet sockets require CAP_NET_RAW. + if stype == linux.SOCK_RAW || p.family == linux.AF_PACKET { if creds := auth.CredentialsFromContext(t); !creds.HasCapability(linux.CAP_NET_RAW) { return nil, syserr.ErrNotPermitted } @@ -233,7 +243,10 @@ func (p *socketProvider) Socket(t *kernel.Task, stypeflags linux.SockType, proto // Validate the socket based on family, type, and protocol. var supported bool for _, allowed := range stack.allowedSocketTypes { - if p.family == allowed.Family && int(stype) == allowed.Type && protocol == allowed.Protocol { + isAllowedFamily := p.family == allowed.Family + isAllowedType := int(stype) == allowed.Type + isAllowedProtocol := protocol == allowed.Protocol || allowed.Protocol == AllowAllProtocols + if isAllowedFamily && isAllowedType && isAllowedProtocol { supported = true break } @@ -770,7 +783,16 @@ func (s *Socket) Type() (family int, skType linux.SockType, protocol int) { } func init() { - for _, family := range []int{unix.AF_INET, unix.AF_INET6} { - socket.RegisterProvider(family, &socketProvider{family}) + // Register all families in AllowedSocketTypes and AllowedRawSocket + // types. If we don't allow raw sockets, they will be rejected in the + // Socket call. + registered := make(map[int]struct{}) + for _, sockType := range append(AllowedSocketTypes, AllowedRawSocketTypes...) { + fam := sockType.Family + if _, ok := registered[fam]; ok { + continue + } + socket.RegisterProvider(fam, &socketProvider{fam}) + registered[fam] = struct{}{} } } diff --git a/pkg/sentry/socket/socket.go b/pkg/sentry/socket/socket.go index 9c88df8ef..7fdff04c6 100644 --- a/pkg/sentry/socket/socket.go +++ b/pkg/sentry/socket/socket.go @@ -432,6 +432,10 @@ func UnmarshalSockAddr(family int, data []byte) linux.SockAddr { var addr linux.SockAddrNetlink addr.UnmarshalUnsafe(data) return &addr + case unix.AF_PACKET: + var addr linux.SockAddrLink + addr.UnmarshalUnsafe(data) + return &addr default: panic(fmt.Sprintf("Unsupported socket family %v", family)) } diff --git a/runsc/boot/filter/extra_filters_hostinet.go b/runsc/boot/filter/extra_filters_hostinet.go index 540dd58a6..e8521e3f1 100644 --- a/runsc/boot/filter/extra_filters_hostinet.go +++ b/runsc/boot/filter/extra_filters_hostinet.go @@ -85,12 +85,18 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { stypes = append(stypes, hostinet.AllowedRawSocketTypes...) } for _, sock := range stypes { - socketRules = append(socketRules, seccomp.Rule{ + rule := seccomp.Rule{ seccomp.EqualTo(sock.Family), - // We always set SOCK_NONBLOCK and SOCK_CLOEXEC + // We always set SOCK_NONBLOCK and SOCK_CLOEXEC. seccomp.EqualTo(sock.Type | linux.SOCK_NONBLOCK | linux.SOCK_CLOEXEC), + // Match specific protocol by default. seccomp.EqualTo(sock.Protocol), - }) + } + if sock.Protocol == hostinet.AllowAllProtocols { + // Change protocol filter to MatchAny. + rule[2] = seccomp.MatchAny{} + } + socketRules = append(socketRules, rule) } rules[unix.SYS_SOCKET] = socketRules diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD index 390715a27..e2e6ceda8 100644 --- a/test/syscalls/BUILD +++ b/test/syscalls/BUILD @@ -425,14 +425,17 @@ syscall_test( ) syscall_test( + add_hostinet = True, test = "//test/syscalls/linux:packet_socket_dgram_test", ) syscall_test( + add_hostinet = True, test = "//test/syscalls/linux:packet_socket_raw_test", ) syscall_test( + add_hostinet = True, test = "//test/syscalls/linux:packet_socket_test", ) diff --git a/test/syscalls/linux/packet_socket_dgram.cc b/test/syscalls/linux/packet_socket_dgram.cc index bdf0dae5b..b4f6d5356 100644 --- a/test/syscalls/linux/packet_socket_dgram.cc +++ b/test/syscalls/linux/packet_socket_dgram.cc @@ -226,6 +226,10 @@ TEST_P(CookedPacketTest, Receive) { // Send via a packet socket. TEST_P(CookedPacketTest, Send) { + // TODO(b/267210840): Fix this test for hostinet. Something is wrong with + // poll(). + SKIP_IF(IsRunningWithHostinet()); + // Let's send a UDP packet and receive it using a regular UDP socket. FileDescriptor udp_sock = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); diff --git a/test/syscalls/linux/packet_socket_raw.cc b/test/syscalls/linux/packet_socket_raw.cc index a3cf74012..aaa20a039 100644 --- a/test/syscalls/linux/packet_socket_raw.cc +++ b/test/syscalls/linux/packet_socket_raw.cc @@ -205,6 +205,10 @@ TEST_P(RawPacketTest, Receive) { // Send via a packet socket. TEST_P(RawPacketTest, Send) { + // TODO(b/267210840): Fix this test for hostinet. Something is wrong with + // poll(). + SKIP_IF(IsRunningWithHostinet()); + // Let's send a UDP packet and receive it using a regular UDP socket. FileDescriptor udp_sock = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0));