diff --git a/pkg/sentry/socket/hostinet/BUILD b/pkg/sentry/socket/hostinet/BUILD index c61d9b6aa..6f9a34c0b 100644 --- a/pkg/sentry/socket/hostinet/BUILD +++ b/pkg/sentry/socket/hostinet/BUILD @@ -9,6 +9,7 @@ go_library( "hostinet.go", "socket.go", "socket_unsafe.go", + "sockopt.go", "sockopt_impl.go", "stack.go", "stack_unsafe.go", diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go index 26fc35b26..99cad809d 100644 --- a/pkg/sentry/socket/hostinet/socket.go +++ b/pkg/sentry/socket/hostinet/socket.go @@ -16,16 +16,13 @@ package hostinet import ( "fmt" - "time" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fdnotifier" - "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/log" - "gvisor.dev/gvisor/pkg/marshal" "gvisor.dev/gvisor/pkg/marshal/primitive" "gvisor.dev/gvisor/pkg/safemem" "gvisor.dev/gvisor/pkg/sentry/arch" @@ -42,8 +39,6 @@ import ( ) const ( - sizeofInt32 = 4 - // sizeofSockaddr is the size in bytes of the largest sockaddr type // supported by this package. sizeofSockaddr = unix.SizeofSockaddrInet6 // sizeof(sockaddr_in6) > sizeof(sockaddr_in) @@ -388,149 +383,6 @@ func (s *Socket) Shutdown(_ *kernel.Task, how int) *syserr.Error { } } -// GetSockOpt implements socket.Socket.GetSockOpt. -func (s *Socket) GetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch.Addr, outLen int) (marshal.Marshallable, *syserr.Error) { - if outLen < 0 { - return nil, syserr.ErrInvalidArgument - } - - // Only allow known and safe options. - optlen, copyIn := getSockOptLen(t, level, name) - switch level { - case linux.SOL_IP: - switch name { - case linux.IP_TOS, linux.IP_RECVTOS, linux.IP_TTL, linux.IP_RECVTTL, linux.IP_PKTINFO, linux.IP_RECVORIGDSTADDR, linux.IP_RECVERR: - optlen = sizeofInt32 - } - case linux.SOL_IPV6: - switch name { - case linux.IPV6_TCLASS, linux.IPV6_RECVTCLASS, linux.IPV6_RECVPKTINFO, linux.IPV6_UNICAST_HOPS, linux.IPV6_MULTICAST_HOPS, linux.IPV6_RECVHOPLIMIT, linux.IPV6_RECVERR, linux.IPV6_V6ONLY, linux.IPV6_RECVORIGDSTADDR: - optlen = sizeofInt32 - } - case linux.SOL_SOCKET: - switch name { - case linux.SO_BROADCAST, linux.SO_ERROR, linux.SO_KEEPALIVE, linux.SO_SNDBUF, linux.SO_RCVBUF, linux.SO_REUSEADDR, linux.SO_TIMESTAMP, linux.SO_ACCEPTCONN: - optlen = sizeofInt32 - case linux.SO_LINGER: - optlen = unix.SizeofLinger - case linux.SO_RCVTIMEO: - optlen = linux.SizeOfTimeval - recvTimeout := linux.NsecToTimeval(s.RecvTimeout()) - return &recvTimeout, nil - case linux.SO_SNDTIMEO: - optlen = linux.SizeOfTimeval - sndTimeout := linux.NsecToTimeval(s.SendTimeout()) - return &sndTimeout, nil - } - case linux.SOL_TCP: - switch name { - case linux.TCP_NODELAY, linux.TCP_MAXSEG, linux.TCP_INQ, linux.TCP_USER_TIMEOUT, linux.TCP_DEFER_ACCEPT, linux.TCP_SYNCNT, linux.TCP_WINDOW_CLAMP: - optlen = sizeofInt32 - case linux.TCP_INFO: - optlen = linux.SizeOfTCPInfo - // Truncate the output buffer to outLen size. - if optlen > outLen { - optlen = outLen - } - case linux.TCP_CONGESTION: - optlen = outLen - } - } - - if optlen == 0 { - return nil, syserr.ErrProtocolNotAvailable // ENOPROTOOPT - } - if outLen < optlen { - return nil, syserr.ErrInvalidArgument - } - - opt := make([]byte, optlen) - if copyIn { - // This is non-intuitive as normally in getsockopt one assumes that the - // parameter is purely an out parameter. But some custom options do require - // copying in the optVal so we do it here only for those custom options. - if _, err := t.CopyInBytes(optValAddr, opt); err != nil { - return nil, syserr.FromError(err) - } - } - var err error - opt, err = getsockopt(s.fd, level, name, opt) - if err != nil { - return nil, syserr.FromError(err) - } - opt = postGetSockOpt(t, level, name, opt) - optP := primitive.ByteSlice(opt) - return &optP, nil -} - -// SetSockOpt implements socket.Socket.SetSockOpt. -func (s *Socket) SetSockOpt(t *kernel.Task, level, name int, opt []byte) *syserr.Error { - // Only allow known and safe options. - optlen := setSockOptLen(t, level, name) - switch level { - case linux.SOL_IP: - switch name { - case linux.IP_TOS, linux.IP_RECVTOS, linux.IP_TTL, linux.IP_RECVTTL, linux.IP_PKTINFO, linux.IP_RECVORIGDSTADDR, linux.IP_RECVERR: - optlen = sizeofInt32 - } - case linux.SOL_IPV6: - switch name { - case linux.IPV6_TCLASS, linux.IPV6_RECVTCLASS, linux.IPV6_RECVPKTINFO, linux.IPV6_UNICAST_HOPS, linux.IPV6_MULTICAST_HOPS, linux.IPV6_RECVHOPLIMIT, linux.IPV6_RECVERR, linux.IPV6_V6ONLY, linux.IPV6_RECVORIGDSTADDR: - optlen = sizeofInt32 - } - case linux.SOL_SOCKET: - switch name { - case linux.SO_BROADCAST, linux.SO_SNDBUF, linux.SO_RCVBUF, linux.SO_REUSEADDR, linux.SO_TIMESTAMP: - optlen = sizeofInt32 - case linux.SO_RCVTIMEO: - // Since our host sockets are always non-blocking, - // there is no point in setting these timeouts on the - // host. But we must store them internally so that we - // can put deadlines on our own blocking. - optlen = linux.SizeOfTimeval - var v linux.Timeval - v.UnmarshalBytes(opt[:optlen]) - if v.Usec < 0 || v.Usec >= int64(time.Second/time.Microsecond) { - return syserr.ErrDomain - } - s.SetRecvTimeout(v.ToNsecCapped()) - return nil - case linux.SO_SNDTIMEO: - // See above. - optlen = linux.SizeOfTimeval - var v linux.Timeval - v.UnmarshalBytes(opt[:optlen]) - if v.Usec < 0 || v.Usec >= int64(time.Second/time.Microsecond) { - return syserr.ErrDomain - } - s.SetSendTimeout(v.ToNsecCapped()) - return nil - } - case linux.SOL_TCP: - switch name { - case linux.TCP_NODELAY, linux.TCP_INQ, linux.TCP_MAXSEG, linux.TCP_USER_TIMEOUT, linux.TCP_DEFER_ACCEPT, linux.TCP_SYNCNT, linux.TCP_WINDOW_CLAMP: - optlen = sizeofInt32 - case linux.TCP_CONGESTION: - optlen = len(opt) - } - } - - if optlen == 0 { - // Pretend to accept socket options we don't understand. This seems - // dangerous, but it's what netstack does... - return nil - } - if len(opt) < optlen { - return syserr.ErrInvalidArgument - } - opt = opt[:optlen] - _, _, errno := unix.Syscall6(unix.SYS_SETSOCKOPT, uintptr(s.fd), uintptr(level), uintptr(name), uintptr(firstBytePtr(opt)), uintptr(len(opt)), 0) - if errno != 0 { - return syserr.FromError(errno) - } - return nil -} - func (s *Socket) recvMsgFromHost(iovs []unix.Iovec, flags int, senderRequested bool, controlLen uint64) (uint64, int, []byte, []byte, error) { // We always do a non-blocking recv*(). sysflags := flags | unix.MSG_DONTWAIT diff --git a/pkg/sentry/socket/hostinet/sockopt.go b/pkg/sentry/socket/hostinet/sockopt.go new file mode 100644 index 000000000..bc14ebee3 --- /dev/null +++ b/pkg/sentry/socket/hostinet/sockopt.go @@ -0,0 +1,219 @@ +// Copyright 2023 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 hostinet + +import ( + "fmt" + "sync" + "time" + + "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/hostarch" + "gvisor.dev/gvisor/pkg/marshal" + "gvisor.dev/gvisor/pkg/marshal/primitive" + "gvisor.dev/gvisor/pkg/sentry/kernel" + "gvisor.dev/gvisor/pkg/syserr" +) + +const ( + sizeofInt16 = 2 + sizeofInt32 = 4 +) + +// SockOpt is used to generate get/setsockopt handlers and filters. +type SockOpt struct { + // Level the socket option applies to. + Level uint64 + // Name of the option. + Name uint64 + // Size of the parameter. A size of 0 indicates that any size is + // allowed (used for strings types). + Size uint64 + // Support getsockopt on this option. + AllowGet bool + // Support setsockopt on this option. + AllowSet bool +} + +// SockOpts are the socket options supported by hostinet. +var SockOpts = []SockOpt{ + {linux.SOL_IP, linux.IP_PKTINFO, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_RECVERR, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_RECVORIGDSTADDR, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_RECVTOS, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_RECVTTL, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_TOS, sizeofInt32, true, true}, + {linux.SOL_IP, linux.IP_TTL, sizeofInt32, true, true}, + + {linux.SOL_IPV6, linux.IPV6_MULTICAST_HOPS, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_RECVERR, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_RECVHOPLIMIT, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_RECVORIGDSTADDR, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_RECVPKTINFO, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_RECVTCLASS, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_TCLASS, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_UNICAST_HOPS, sizeofInt32, true, true}, + {linux.SOL_IPV6, linux.IPV6_V6ONLY, sizeofInt32, true, true}, + + {linux.SOL_SOCKET, linux.SO_ACCEPTCONN, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_BROADCAST, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_ERROR, sizeofInt32, false, true}, + {linux.SOL_SOCKET, linux.SO_KEEPALIVE, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_LINGER, linux.SizeOfLinger, true, true}, + {linux.SOL_SOCKET, linux.SO_RCVBUF, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_REUSEADDR, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_SNDBUF, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_TIMESTAMP, sizeofInt32, true, true}, + {linux.SOL_SOCKET, linux.SO_TYPE, sizeofInt32, false, true}, + + {linux.SOL_TCP, linux.TCP_CONGESTION, 0 /* string */, true, true}, + {linux.SOL_TCP, linux.TCP_DEFER_ACCEPT, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_INFO, uint64(linux.SizeOfTCPInfo), true, false}, + {linux.SOL_TCP, linux.TCP_INQ, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_MAXSEG, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_NODELAY, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_SYNCNT, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_USER_TIMEOUT, sizeofInt32, true, true}, + {linux.SOL_TCP, linux.TCP_WINDOW_CLAMP, sizeofInt32, true, true}, +} + +// sockOptMap is a map of {level, name} -> SockOpts. It is an optimization for +// looking up SockOpts by level and name. The map is initialized in the first +// call to Get/SetSockOpt. +var ( + sockOptMap map[levelName]SockOpt + sockOptMapOnce sync.Once +) + +type levelName struct { + level uint64 + name uint64 +} + +func initSockOptMap(t *kernel.Task) { + opts := append(SockOpts, extraSockOpts(t)...) + sockOptMap = make(map[levelName]SockOpt, len(opts)) + for _, opt := range opts { + ln := levelName{opt.Level, opt.Name} + if _, ok := sockOptMap[ln]; ok { + panic(fmt.Sprintf("multiple sockopts with level=%d and name=%d", opt.Level, opt.Name)) + } + sockOptMap[ln] = opt + } +} + +// GetSockOpt implements socket.Socket.GetSockOpt. +func (s *Socket) GetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch.Addr, optLen int) (marshal.Marshallable, *syserr.Error) { + sockOptMapOnce.Do(func() { initSockOptMap(t) }) + + if optLen < 0 { + return nil, syserr.ErrInvalidArgument + } + + // Special case send/recv timeouts since those are handled internally. + if level == linux.SOL_SOCKET { + switch name { + case linux.SO_RCVTIMEO: + recvTimeout := linux.NsecToTimeval(s.RecvTimeout()) + return &recvTimeout, nil + case linux.SO_SNDTIMEO: + sndTimeout := linux.NsecToTimeval(s.SendTimeout()) + return &sndTimeout, nil + } + } + + sockOpt, ok := sockOptMap[levelName{uint64(level), uint64(name)}] + if !ok { + return nil, syserr.ErrProtocolNotAvailable + } + var opt []byte + if sockOpt.Size > 0 { + // Validate size of input buffer. + if uint64(optLen) < sockOpt.Size { + // Special case for TCP_INFO. We allow smaller buffers, and + // only fill up what we can. + if level != linux.SOL_TCP || name != linux.TCP_INFO { + return nil, syserr.ErrInvalidArgument + } + } + opt = make([]byte, sockOpt.Size) + } else { + // No size checking. This is probably a string. Use the size + // they gave us. + opt = make([]byte, optLen) + } + if err := preGetSockOpt(t, level, name, optValAddr, opt); err != nil { + return nil, syserr.FromError(err) + } + var err error + opt, err = getsockopt(s.fd, level, name, opt) + if err != nil { + return nil, syserr.FromError(err) + } + opt = postGetSockOpt(t, level, name, opt) + // Special-case for TCP_INFO. We truncate the buffer to whatever size + // the user requested. + if level == linux.SOL_TCP && name == linux.TCP_INFO && uint64(optLen) < sockOpt.Size { + opt = opt[:optLen] + } + optP := primitive.ByteSlice(opt) + return &optP, nil +} + +// SetSockOpt implements socket.Socket.SetSockOpt. +func (s *Socket) SetSockOpt(t *kernel.Task, level, name int, opt []byte) *syserr.Error { + sockOptMapOnce.Do(func() { initSockOptMap(t) }) + + // Special case send/recv timeouts since those are handled internally. + if level == linux.SOL_SOCKET { + switch name { + case linux.SO_RCVTIMEO: + optLen := linux.SizeOfTimeval + var v linux.Timeval + v.UnmarshalBytes(opt[:optLen]) + if v.Usec < 0 || v.Usec >= int64(time.Second/time.Microsecond) { + return syserr.ErrDomain + } + s.SetRecvTimeout(v.ToNsecCapped()) + return nil + case linux.SO_SNDTIMEO: + optLen := linux.SizeOfTimeval + var v linux.Timeval + v.UnmarshalBytes(opt[:optLen]) + if v.Usec < 0 || v.Usec >= int64(time.Second/time.Microsecond) { + return syserr.ErrDomain + } + s.SetSendTimeout(v.ToNsecCapped()) + return nil + } + } + sockOpt, ok := sockOptMap[levelName{uint64(level), uint64(name)}] + if !ok { + // Pretend to accept socket options we don't understand. This + // seems dangerous, but it's what netstack does... + return nil + } + if sockOpt.Size > 0 { + if uint64(len(opt)) < sockOpt.Size { + return syserr.ErrInvalidArgument + } + opt = opt[:sockOpt.Size] + } + if _, _, errno := unix.Syscall6(unix.SYS_SETSOCKOPT, uintptr(s.fd), uintptr(level), uintptr(name), uintptr(firstBytePtr(opt)), uintptr(len(opt)), 0); errno != 0 { + return syserr.FromError(errno) + } + return nil +} diff --git a/pkg/sentry/socket/hostinet/sockopt_impl.go b/pkg/sentry/socket/hostinet/sockopt_impl.go index 66994e365..33d4136af 100644 --- a/pkg/sentry/socket/hostinet/sockopt_impl.go +++ b/pkg/sentry/socket/hostinet/sockopt_impl.go @@ -18,17 +18,17 @@ package hostinet import ( + "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/sentry/kernel" ) -func getSockOptLen(t *kernel.Task, level, name int) (len int, copyIn bool) { - return 0, false // No custom options. +func extraSockOpts(t *kernel.Task) []SockOpt { + return nil } - -func setSockOptLen(t *kernel.Task, level, name int) int { - return 0 // No custom options. +func preGetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch.Addr, opt []byte) error { + return nil } func postGetSockOpt(t *kernel.Task, level, name int, opt []byte) []byte { - return opt // No custom changes to option value. + return opt } diff --git a/runsc/boot/filter/BUILD b/runsc/boot/filter/BUILD index d391d93e1..24ad5dbba 100644 --- a/runsc/boot/filter/BUILD +++ b/runsc/boot/filter/BUILD @@ -25,6 +25,7 @@ go_library( "//pkg/log", "//pkg/seccomp", "//pkg/sentry/platform", + "//pkg/sentry/socket/hostinet", "//pkg/tcpip/link/fdbased", "@org_golang_x_sys//unix:go_default_library", ], diff --git a/runsc/boot/filter/extra_filters_hostinet.go b/runsc/boot/filter/extra_filters_hostinet.go index 6adc69427..458f5303a 100644 --- a/runsc/boot/filter/extra_filters_hostinet.go +++ b/runsc/boot/filter/extra_filters_hostinet.go @@ -16,13 +16,13 @@ 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" ) // hostInetFilters contains syscalls that are needed by sentry/socket/hostinet. func hostInetFilters() seccomp.SyscallRules { - return seccomp.SyscallRules{ + rules := seccomp.SyscallRules{ unix.SYS_ACCEPT4: []seccomp.Rule{ { seccomp.MatchAny{}, @@ -35,183 +35,6 @@ func hostInetFilters() seccomp.SyscallRules { unix.SYS_CONNECT: {}, unix.SYS_GETPEERNAME: {}, unix.SYS_GETSOCKNAME: {}, - unix.SYS_GETSOCKOPT: []seccomp.Rule{ - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_TOS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVTOS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_TTL), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVTTL), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_PKTINFO), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVORIGDSTADDR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVERR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_TCLASS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVTCLASS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVPKTINFO), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_UNICAST_HOPS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_MULTICAST_HOPS), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVHOPLIMIT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVERR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_V6ONLY), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(linux.IPV6_RECVORIGDSTADDR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_BROADCAST), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_ERROR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_KEEPALIVE), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_SNDBUF), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_RCVBUF), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_REUSEADDR), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_TYPE), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_LINGER), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_TIMESTAMP), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_ACCEPTCONN), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(unix.TCP_NODELAY), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(unix.TCP_INFO), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_INQ), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_MAXSEG), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_CONGESTION), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_USER_TIMEOUT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_DEFER_ACCEPT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_SYNCNT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_WINDOW_CLAMP), - }, - }, unix.SYS_IOCTL: []seccomp.Rule{ { seccomp.MatchAny{}, @@ -236,201 +59,6 @@ func hostInetFilters() seccomp.SyscallRules { unix.SYS_RECVMSG: {}, unix.SYS_SENDMSG: {}, unix.SYS_SENDTO: {}, - unix.SYS_SETSOCKOPT: []seccomp.Rule{ - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_BROADCAST), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_SNDBUF), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_RCVBUF), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_REUSEADDR), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_TIMESTAMP), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(unix.TCP_NODELAY), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_INQ), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_MAXSEG), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_CONGESTION), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_USER_TIMEOUT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_DEFER_ACCEPT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_SYNCNT), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_TCP), - seccomp.EqualTo(linux.TCP_WINDOW_CLAMP), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_TOS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVTOS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_TTL), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVTTL), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_PKTINFO), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVPKTINFO), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVORIGDSTADDR), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IP), - seccomp.EqualTo(unix.IP_RECVERR), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_TCLASS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVTCLASS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_UNICAST_HOPS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_MULTICAST_HOPS), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVHOPLIMIT), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(linux.IPV6_RECVORIGDSTADDR), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_RECVERR), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - { - seccomp.MatchAny{}, - seccomp.EqualTo(unix.SOL_IPV6), - seccomp.EqualTo(unix.IPV6_V6ONLY), - seccomp.MatchAny{}, - seccomp.EqualTo(4), - }, - }, unix.SYS_SHUTDOWN: []seccomp.Rule{ { seccomp.MatchAny{}, @@ -469,4 +97,36 @@ func hostInetFilters() seccomp.SyscallRules { }, unix.SYS_WRITEV: {}, } + + getSockOptRules := []seccomp.Rule{} + setSockOptRules := []seccomp.Rule{} + for _, opt := range hostinet.SockOpts { + if opt.AllowGet { + getSockOptRules = append(getSockOptRules, seccomp.Rule{ + seccomp.MatchAny{}, + seccomp.EqualTo(opt.Level), + seccomp.EqualTo(opt.Name), + }) + } + if opt.AllowSet { + if opt.Size > 0 { + setSockOptRules = append(setSockOptRules, seccomp.Rule{ + seccomp.MatchAny{}, + seccomp.EqualTo(opt.Level), + seccomp.EqualTo(opt.Name), + seccomp.MatchAny{}, + seccomp.EqualTo(opt.Size), + }) + } else { + setSockOptRules = append(setSockOptRules, seccomp.Rule{ + seccomp.MatchAny{}, + seccomp.EqualTo(opt.Level), + seccomp.EqualTo(opt.Name), + }) + } + } + } + rules[unix.SYS_GETSOCKOPT] = getSockOptRules + rules[unix.SYS_SETSOCKOPT] = setSockOptRules + return rules }