diff options
author | Fabricio Voznika <fvoznika@google.com> | 2018-11-19 15:25:00 -0800 |
---|---|---|
committer | Nicolas Lacasse <nlacasse@google.com> | 2018-11-20 14:04:12 -0800 |
commit | fadffa2ff831034ff63146abf408ff71462b9f43 (patch) | |
tree | 62f4ad4de0431409a4d63409fad6704b3551aef0 /pkg/sentry | |
parent | 237f9c7a5e7078b46303f1262b77372a2f6a7f7b (diff) |
Add unsupported syscall events for get/setsockopt
PiperOrigin-RevId: 222148953
Change-Id: I21500a9f08939c45314a6414e0824490a973e5aa
Diffstat (limited to 'pkg/sentry')
-rw-r--r-- | pkg/sentry/socket/epsocket/epsocket.go | 675 | ||||
-rw-r--r-- | pkg/sentry/socket/netlink/socket.go | 33 | ||||
-rw-r--r-- | pkg/sentry/socket/socket.go | 91 |
3 files changed, 581 insertions, 218 deletions
diff --git a/pkg/sentry/socket/epsocket/epsocket.go b/pkg/sentry/socket/epsocket/epsocket.go index d14bbad01..c5ce289b5 100644 --- a/pkg/sentry/socket/epsocket/epsocket.go +++ b/pkg/sentry/socket/epsocket/epsocket.go @@ -515,189 +515,233 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name, outLen int) ( func GetSockOpt(t *kernel.Task, s socket.Socket, ep commonEndpoint, family int, skType transport.SockType, level, name, outLen int) (interface{}, *syserr.Error) { switch level { case linux.SOL_SOCKET: - switch name { - case linux.SO_TYPE: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } - return int32(skType), nil + return getSockOptSocket(t, s, ep, family, skType, name, outLen) - case linux.SO_ERROR: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + case linux.SOL_TCP: + return getSockOptTCP(t, ep, name, outLen) - // Get the last error and convert it. - err := ep.GetSockOpt(tcpip.ErrorOption{}) - if err == nil { - return int32(0), nil - } - return int32(syserr.TranslateNetstackError(err).ToLinux().Number()), nil + case linux.SOL_IPV6: + return getSockOptIPv6(t, ep, name, outLen) - case linux.SO_PEERCRED: - if family != linux.AF_UNIX || outLen < syscall.SizeofUcred { - return nil, syserr.ErrInvalidArgument - } + case linux.SOL_IP, + linux.SOL_UDP, + linux.SOL_ICMPV6, + linux.SOL_RAW, + linux.SOL_PACKET: - tcred := t.Credentials() - return syscall.Ucred{ - Pid: int32(t.ThreadGroup().ID()), - Uid: uint32(tcred.EffectiveKUID.In(tcred.UserNamespace).OrOverflow()), - Gid: uint32(tcred.EffectiveKGID.In(tcred.UserNamespace).OrOverflow()), - }, nil + t.Kernel().EmitUnimplementedEvent(t) + } - case linux.SO_PASSCRED: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + return nil, syserr.ErrProtocolNotAvailable +} - var v tcpip.PasscredOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } +// getSockOptSocket implements GetSockOpt when level is SOL_SOCKET. +func getSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, family int, skType transport.SockType, name, outLen int) (interface{}, *syserr.Error) { + switch name { + case linux.SO_TYPE: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } + return int32(skType), nil - return int32(v), nil + case linux.SO_ERROR: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - case linux.SO_SNDBUF: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + // Get the last error and convert it. + err := ep.GetSockOpt(tcpip.ErrorOption{}) + if err == nil { + return int32(0), nil + } + return int32(syserr.TranslateNetstackError(err).ToLinux().Number()), nil - var size tcpip.SendBufferSizeOption - if err := ep.GetSockOpt(&size); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + case linux.SO_PEERCRED: + if family != linux.AF_UNIX || outLen < syscall.SizeofUcred { + return nil, syserr.ErrInvalidArgument + } - if size > math.MaxInt32 { - size = math.MaxInt32 - } + tcred := t.Credentials() + return syscall.Ucred{ + Pid: int32(t.ThreadGroup().ID()), + Uid: uint32(tcred.EffectiveKUID.In(tcred.UserNamespace).OrOverflow()), + Gid: uint32(tcred.EffectiveKGID.In(tcred.UserNamespace).OrOverflow()), + }, nil - return int32(size), nil + case linux.SO_PASSCRED: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - case linux.SO_RCVBUF: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + var v tcpip.PasscredOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - var size tcpip.ReceiveBufferSizeOption - if err := ep.GetSockOpt(&size); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + return int32(v), nil - if size > math.MaxInt32 { - size = math.MaxInt32 - } + case linux.SO_SNDBUF: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - return int32(size), nil + var size tcpip.SendBufferSizeOption + if err := ep.GetSockOpt(&size); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - case linux.SO_REUSEADDR: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + if size > math.MaxInt32 { + size = math.MaxInt32 + } - var v tcpip.ReuseAddressOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + return int32(size), nil - return int32(v), nil + case linux.SO_RCVBUF: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - case linux.SO_KEEPALIVE: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } - return int32(0), nil + var size tcpip.ReceiveBufferSizeOption + if err := ep.GetSockOpt(&size); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - case linux.SO_LINGER: - if outLen < syscall.SizeofLinger { - return nil, syserr.ErrInvalidArgument - } - return syscall.Linger{}, nil + if size > math.MaxInt32 { + size = math.MaxInt32 + } - case linux.SO_RCVTIMEO: - if outLen < linux.SizeOfTimeval { - return nil, syserr.ErrInvalidArgument - } + return int32(size), nil - return linux.NsecToTimeval(s.RecvTimeout()), nil + case linux.SO_REUSEADDR: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - case linux.SO_TIMESTAMP: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + var v tcpip.ReuseAddressOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - var v tcpip.TimestampOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + return int32(v), nil - return int32(v), nil + case linux.SO_KEEPALIVE: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument } + return int32(0), nil - case syscall.SOL_TCP: - switch name { - case syscall.TCP_NODELAY: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + case linux.SO_LINGER: + if outLen < syscall.SizeofLinger { + return nil, syserr.ErrInvalidArgument + } + return syscall.Linger{}, nil - var v tcpip.DelayOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + case linux.SO_RCVTIMEO: + if outLen < linux.SizeOfTimeval { + return nil, syserr.ErrInvalidArgument + } - if v == 0 { - return int32(1), nil - } - return int32(0), nil + return linux.NsecToTimeval(s.RecvTimeout()), nil - case syscall.TCP_CORK: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + case linux.SO_TIMESTAMP: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - var v tcpip.CorkOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + var v tcpip.TimestampOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - return int32(v), nil + return int32(v), nil - case syscall.TCP_INFO: - var v tcpip.TCPInfoOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + default: + socket.GetSockOptEmitUnimplementedEvent(t, name) + } + return nil, syserr.ErrProtocolNotAvailable +} + +// getSockOptTCP implements GetSockOpt when level is SOL_TCP. +func getSockOptTCP(t *kernel.Task, ep commonEndpoint, name, outLen int) (interface{}, *syserr.Error) { + switch name { + case linux.TCP_NODELAY: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } - // TODO: Translate fields once they are added to - // tcpip.TCPInfoOption. - info := linux.TCPInfo{} + var v tcpip.DelayOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - // Linux truncates the output binary to outLen. - ib := binary.Marshal(nil, usermem.ByteOrder, &info) - if len(ib) > outLen { - ib = ib[:outLen] - } + if v == 0 { + return int32(1), nil + } + return int32(0), nil - return ib, nil + case linux.TCP_CORK: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument } - case syscall.SOL_IPV6: - switch name { - case syscall.IPV6_V6ONLY: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } + var v tcpip.CorkOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } - var v tcpip.V6OnlyOption - if err := ep.GetSockOpt(&v); err != nil { - return nil, syserr.TranslateNetstackError(err) - } + return int32(v), nil - return int32(v), nil + case linux.TCP_INFO: + var v tcpip.TCPInfoOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } + + // TODO: Translate fields once they are added to + // tcpip.TCPInfoOption. + info := linux.TCPInfo{} + + // Linux truncates the output binary to outLen. + ib := binary.Marshal(nil, usermem.ByteOrder, &info) + if len(ib) > outLen { + ib = ib[:outLen] } + + return ib, nil + + case linux.TCP_CC_INFO, + linux.TCP_NOTSENT_LOWAT, + linux.TCP_ZEROCOPY_RECEIVE: + + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUmplementedEventTCP(t, name) } + return nil, syserr.ErrProtocolNotAvailable +} + +// getSockOptIPv6 implements GetSockOpt when level is SOL_IPV6. +func getSockOptIPv6(t *kernel.Task, ep commonEndpoint, name, outLen int) (interface{}, *syserr.Error) { + switch name { + case linux.IPV6_V6ONLY: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } + var v tcpip.V6OnlyOption + if err := ep.GetSockOpt(&v); err != nil { + return nil, syserr.TranslateNetstackError(err) + } + + return int32(v), nil + + case linux.IPV6_PATHMTU: + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUmplementedEventIPv6(t, name) + } return nil, syserr.ErrProtocolNotAvailable } @@ -712,109 +756,304 @@ func (s *SocketOperations) SetSockOpt(t *kernel.Task, level int, name int, optVa func SetSockOpt(t *kernel.Task, s socket.Socket, ep commonEndpoint, level int, name int, optVal []byte) *syserr.Error { switch level { case linux.SOL_SOCKET: - switch name { - case linux.SO_SNDBUF: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + return setSockOptSocket(t, s, ep, name, optVal) - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.SendBufferSizeOption(v))) + case linux.SOL_TCP: + return setSockOptTCP(t, ep, name, optVal) - case linux.SO_RCVBUF: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + case linux.SOL_IPV6: + return setSockOptIPv6(t, ep, name, optVal) - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReceiveBufferSizeOption(v))) + case linux.SOL_IP: + return setSockOptIP(t, ep, name, optVal) - case linux.SO_REUSEADDR: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + case linux.SOL_UDP, + linux.SOL_ICMPV6, + linux.SOL_RAW, + linux.SOL_PACKET: - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReuseAddressOption(v))) + t.Kernel().EmitUnimplementedEvent(t) + } - case linux.SO_PASSCRED: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + // Default to the old behavior; hand off to network stack. + return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) +} - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.PasscredOption(v))) +// setSockOptSocket implements SetSockOpt when level is SOL_SOCKET. +func setSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int, optVal []byte) *syserr.Error { + switch name { + case linux.SO_SNDBUF: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } - case linux.SO_RCVTIMEO: - if len(optVal) < linux.SizeOfTimeval { - return syserr.ErrInvalidArgument - } + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.SendBufferSizeOption(v))) - var v linux.Timeval - binary.Unmarshal(optVal[:linux.SizeOfTimeval], usermem.ByteOrder, &v) - s.SetRecvTimeout(v.ToNsecCapped()) - return nil + case linux.SO_RCVBUF: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } - case linux.SO_TIMESTAMP: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReceiveBufferSizeOption(v))) - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.TimestampOption(v))) + case linux.SO_REUSEADDR: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument } - case syscall.SOL_TCP: - switch name { - case syscall.TCP_NODELAY: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReuseAddressOption(v))) - v := usermem.ByteOrder.Uint32(optVal) - var o tcpip.DelayOption - if v == 0 { - o = 1 - } - return syserr.TranslateNetstackError(ep.SetSockOpt(o)) - case syscall.TCP_CORK: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } + case linux.SO_PASSCRED: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.PasscredOption(v))) - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.CorkOption(v))) + case linux.SO_RCVTIMEO: + if len(optVal) < linux.SizeOfTimeval { + return syserr.ErrInvalidArgument } - case syscall.SOL_IPV6: - switch name { - case syscall.IPV6_V6ONLY: - if len(optVal) < sizeOfInt32 { - return syserr.ErrInvalidArgument - } - v := usermem.ByteOrder.Uint32(optVal) - return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.V6OnlyOption(v))) - } - case syscall.SOL_IP: - const ( - _IP_MULTICAST_IF = 32 - _IP_ADD_MEMBERSHIP = 35 - _MCAST_JOIN_GROUP = 42 - ) - switch name { - case _IP_ADD_MEMBERSHIP, _MCAST_JOIN_GROUP, _IP_MULTICAST_IF: - // FIXME: Disallow IP-level multicast group options by - // default. These will need to be supported by appropriately plumbing - // the level through to the network stack (if at all). However, we - // still allow setting TTL, and multicast-enable/disable type options. + var v linux.Timeval + binary.Unmarshal(optVal[:linux.SizeOfTimeval], usermem.ByteOrder, &v) + s.SetRecvTimeout(v.ToNsecCapped()) + return nil + + case linux.SO_TIMESTAMP: + if len(optVal) < sizeOfInt32 { return syserr.ErrInvalidArgument } + + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.TimestampOption(v))) + + default: + socket.SetSockOptEmitUnimplementedEvent(t, name) } // Default to the old behavior; hand off to network stack. return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) } +// setSockOptTCP implements SetSockOpt when level is SOL_TCP. +func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *syserr.Error { + switch name { + case linux.TCP_NODELAY: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + v := usermem.ByteOrder.Uint32(optVal) + var o tcpip.DelayOption + if v == 0 { + o = 1 + } + return syserr.TranslateNetstackError(ep.SetSockOpt(o)) + + case linux.TCP_CORK: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.CorkOption(v))) + + case linux.TCP_REPAIR_OPTIONS: + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUmplementedEventTCP(t, name) + } + + // Default to the old behavior; hand off to network stack. + return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) +} + +// setSockOptIPv6 implements SetSockOpt when level is SOL_IPV6. +func setSockOptIPv6(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *syserr.Error { + switch name { + case linux.IPV6_V6ONLY: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + v := usermem.ByteOrder.Uint32(optVal) + return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.V6OnlyOption(v))) + + case linux.IPV6_ADD_MEMBERSHIP, + linux.IPV6_DROP_MEMBERSHIP, + linux.IPV6_IPSEC_POLICY, + linux.IPV6_JOIN_ANYCAST, + linux.IPV6_LEAVE_ANYCAST, + linux.IPV6_PKTINFO, + linux.IPV6_ROUTER_ALERT, + linux.IPV6_XFRM_POLICY, + linux.MCAST_BLOCK_SOURCE, + linux.MCAST_JOIN_GROUP, + linux.MCAST_JOIN_SOURCE_GROUP, + linux.MCAST_LEAVE_GROUP, + linux.MCAST_LEAVE_SOURCE_GROUP, + linux.MCAST_UNBLOCK_SOURCE: + + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUmplementedEventIPv6(t, name) + } + + // Default to the old behavior; hand off to network stack. + return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) +} + +// setSockOptIP implements SetSockOpt when level is SOL_IP. +func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *syserr.Error { + switch name { + case linux.IP_ADD_MEMBERSHIP, linux.MCAST_JOIN_GROUP, linux.IP_MULTICAST_IF: + // FIXME: Disallow IP-level multicast group options by + // default. These will need to be supported by appropriately plumbing + // the level through to the network stack (if at all). However, we + // still allow setting TTL, and multicast-enable/disable type options. + t.Kernel().EmitUnimplementedEvent(t) + return syserr.ErrInvalidArgument + + case linux.IP_ADD_SOURCE_MEMBERSHIP, + linux.IP_BIND_ADDRESS_NO_PORT, + linux.IP_BLOCK_SOURCE, + linux.IP_CHECKSUM, + linux.IP_DROP_MEMBERSHIP, + linux.IP_DROP_SOURCE_MEMBERSHIP, + linux.IP_FREEBIND, + linux.IP_HDRINCL, + linux.IP_IPSEC_POLICY, + linux.IP_MINTTL, + linux.IP_MSFILTER, + linux.IP_MTU_DISCOVER, + linux.IP_MULTICAST_ALL, + linux.IP_MULTICAST_LOOP, + linux.IP_MULTICAST_TTL, + linux.IP_NODEFRAG, + linux.IP_OPTIONS, + linux.IP_PASSSEC, + linux.IP_PKTINFO, + linux.IP_RECVERR, + linux.IP_RECVFRAGSIZE, + linux.IP_RECVOPTS, + linux.IP_RECVORIGDSTADDR, + linux.IP_RECVTOS, + linux.IP_RECVTTL, + linux.IP_RETOPTS, + linux.IP_TOS, + linux.IP_TRANSPARENT, + linux.IP_TTL, + linux.IP_UNBLOCK_SOURCE, + linux.IP_UNICAST_IF, + linux.IP_XFRM_POLICY, + linux.MCAST_BLOCK_SOURCE, + linux.MCAST_JOIN_SOURCE_GROUP, + linux.MCAST_LEAVE_GROUP, + linux.MCAST_LEAVE_SOURCE_GROUP, + linux.MCAST_MSFILTER, + linux.MCAST_UNBLOCK_SOURCE: + + t.Kernel().EmitUnimplementedEvent(t) + } + + // Default to the old behavior; hand off to network stack. + return syserr.TranslateNetstackError(ep.SetSockOpt(struct{}{})) +} + +// emitUmplementedEventTCP emits unimplemented event if name is valid. This +// function contains names that are common between Get and SetSockOpt when +// level is SOL_TCP. +func emitUmplementedEventTCP(t *kernel.Task, name int) { + switch name { + case linux.TCP_CONGESTION, + linux.TCP_CORK, + linux.TCP_DEFER_ACCEPT, + linux.TCP_FASTOPEN, + linux.TCP_FASTOPEN_CONNECT, + linux.TCP_FASTOPEN_KEY, + linux.TCP_FASTOPEN_NO_COOKIE, + linux.TCP_INQ, + linux.TCP_KEEPCNT, + linux.TCP_KEEPIDLE, + linux.TCP_KEEPINTVL, + linux.TCP_LINGER2, + linux.TCP_MAXSEG, + linux.TCP_QUEUE_SEQ, + linux.TCP_QUICKACK, + linux.TCP_REPAIR, + linux.TCP_REPAIR_QUEUE, + linux.TCP_REPAIR_WINDOW, + linux.TCP_SAVED_SYN, + linux.TCP_SAVE_SYN, + linux.TCP_SYNCNT, + linux.TCP_THIN_DUPACK, + linux.TCP_THIN_LINEAR_TIMEOUTS, + linux.TCP_TIMESTAMP, + linux.TCP_ULP, + linux.TCP_USER_TIMEOUT, + linux.TCP_WINDOW_CLAMP: + + t.Kernel().EmitUnimplementedEvent(t) + } +} + +// emitUmplementedEventIPv6 emits unimplemented event if name is valid. It +// contains names that are common between Get and SetSockOpt when level is +// SOL_IPV6. +func emitUmplementedEventIPv6(t *kernel.Task, name int) { + switch name { + case linux.IPV6_2292DSTOPTS, + linux.IPV6_2292HOPLIMIT, + linux.IPV6_2292HOPOPTS, + linux.IPV6_2292PKTINFO, + linux.IPV6_2292PKTOPTIONS, + linux.IPV6_2292RTHDR, + linux.IPV6_ADDR_PREFERENCES, + linux.IPV6_AUTOFLOWLABEL, + linux.IPV6_DONTFRAG, + linux.IPV6_DSTOPTS, + linux.IPV6_FLOWINFO, + linux.IPV6_FLOWINFO_SEND, + linux.IPV6_FLOWLABEL_MGR, + linux.IPV6_FREEBIND, + linux.IPV6_HOPOPTS, + linux.IPV6_MINHOPCOUNT, + linux.IPV6_MTU, + linux.IPV6_MTU_DISCOVER, + linux.IPV6_MULTICAST_ALL, + linux.IPV6_MULTICAST_HOPS, + linux.IPV6_MULTICAST_IF, + linux.IPV6_MULTICAST_LOOP, + linux.IPV6_RECVDSTOPTS, + linux.IPV6_RECVERR, + linux.IPV6_RECVFRAGSIZE, + linux.IPV6_RECVHOPLIMIT, + linux.IPV6_RECVHOPOPTS, + linux.IPV6_RECVORIGDSTADDR, + linux.IPV6_RECVPATHMTU, + linux.IPV6_RECVPKTINFO, + linux.IPV6_RECVRTHDR, + linux.IPV6_RECVTCLASS, + linux.IPV6_RTHDR, + linux.IPV6_RTHDRDSTOPTS, + linux.IPV6_TCLASS, + linux.IPV6_TRANSPARENT, + linux.IPV6_UNICAST_HOPS, + linux.IPV6_UNICAST_IF, + linux.MCAST_MSFILTER, + linux.IPV6_ADDRFORM: + + t.Kernel().EmitUnimplementedEvent(t) + } +} + // isLinkLocal determines if the given IPv6 address is link-local. This is the // case when it has the fe80::/10 prefix. This check is used to determine when // the NICID is relevant for a given IPv6 address. diff --git a/pkg/sentry/socket/netlink/socket.go b/pkg/sentry/socket/netlink/socket.go index f901cfa0b..b1f6620de 100644 --- a/pkg/sentry/socket/netlink/socket.go +++ b/pkg/sentry/socket/netlink/socket.go @@ -299,6 +299,21 @@ func (s *Socket) GetSockOpt(t *kernel.Task, level int, name int, outLen int) (in } // We don't have limit on receiving size. return math.MaxInt32, nil + + default: + socket.GetSockOptEmitUnimplementedEvent(t, name) + } + case linux.SOL_NETLINK: + switch name { + case linux.NETLINK_BROADCAST_ERROR, + linux.NETLINK_CAP_ACK, + linux.NETLINK_DUMP_STRICT_CHK, + linux.NETLINK_EXT_ACK, + linux.NETLINK_LIST_MEMBERSHIPS, + linux.NETLINK_NO_ENOBUFS, + linux.NETLINK_PKTINFO: + + t.Kernel().EmitUnimplementedEvent(t) } } // TODO: other sockopts are not supported. @@ -329,7 +344,25 @@ func (s *Socket) SetSockOpt(t *kernel.Task, level int, name int, opt []byte) *sy // We don't have limit on receiving size. So just accept anything as // valid for compatibility. return nil + default: + socket.SetSockOptEmitUnimplementedEvent(t, name) } + + case linux.SOL_NETLINK: + switch name { + case linux.NETLINK_ADD_MEMBERSHIP, + linux.NETLINK_BROADCAST_ERROR, + linux.NETLINK_CAP_ACK, + linux.NETLINK_DROP_MEMBERSHIP, + linux.NETLINK_DUMP_STRICT_CHK, + linux.NETLINK_EXT_ACK, + linux.NETLINK_LISTEN_ALL_NSID, + linux.NETLINK_NO_ENOBUFS, + linux.NETLINK_PKTINFO: + + t.Kernel().EmitUnimplementedEvent(t) + } + } // TODO: other sockopts are not supported. return syserr.ErrProtocolNotAvailable diff --git a/pkg/sentry/socket/socket.go b/pkg/sentry/socket/socket.go index a235c5249..b1dcbf7b0 100644 --- a/pkg/sentry/socket/socket.go +++ b/pkg/sentry/socket/socket.go @@ -213,3 +213,94 @@ func (rt *ReceiveTimeout) SetRecvTimeout(nanoseconds int64) { func (rt *ReceiveTimeout) RecvTimeout() int64 { return atomic.LoadInt64(&rt.ns) } + +// GetSockOptEmitUnimplementedEvent emits unimplemented event if name is valid. +// It contains names that are valid for GetSockOpt when level is SOL_SOCKET. +func GetSockOptEmitUnimplementedEvent(t *kernel.Task, name int) { + switch name { + case linux.SO_ACCEPTCONN, + linux.SO_BPF_EXTENSIONS, + linux.SO_COOKIE, + linux.SO_DOMAIN, + linux.SO_ERROR, + linux.SO_GET_FILTER, + linux.SO_INCOMING_NAPI_ID, + linux.SO_MEMINFO, + linux.SO_PEERCRED, + linux.SO_PEERGROUPS, + linux.SO_PEERNAME, + linux.SO_PEERSEC, + linux.SO_PROTOCOL, + linux.SO_SNDLOWAT, + linux.SO_TYPE: + + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUnimplementedEvent(t, name) + } +} + +// SetSockOptEmitUnimplementedEvent emits unimplemented event if name is valid. +// It contains names that are valid for SetSockOpt when level is SOL_SOCKET. +func SetSockOptEmitUnimplementedEvent(t *kernel.Task, name int) { + switch name { + case linux.SO_ATTACH_BPF, + linux.SO_ATTACH_FILTER, + linux.SO_ATTACH_REUSEPORT_CBPF, + linux.SO_ATTACH_REUSEPORT_EBPF, + linux.SO_CNX_ADVICE, + linux.SO_DETACH_FILTER, + linux.SO_RCVBUFFORCE, + linux.SO_SNDBUFFORCE: + + t.Kernel().EmitUnimplementedEvent(t) + + default: + emitUnimplementedEvent(t, name) + } +} + +// emitUnimplementedEvent emits unimplemented event if name is valid. It +// contains names that are common between Get and SetSocketOpt when level is +// SOL_SOCKET. +func emitUnimplementedEvent(t *kernel.Task, name int) { + switch name { + case linux.SO_BINDTODEVICE, + linux.SO_BROADCAST, + linux.SO_BSDCOMPAT, + linux.SO_BUSY_POLL, + linux.SO_DEBUG, + linux.SO_DONTROUTE, + linux.SO_INCOMING_CPU, + linux.SO_KEEPALIVE, + linux.SO_LINGER, + linux.SO_LOCK_FILTER, + linux.SO_MARK, + linux.SO_MAX_PACING_RATE, + linux.SO_NOFCS, + linux.SO_NO_CHECK, + linux.SO_OOBINLINE, + linux.SO_PASSCRED, + linux.SO_PASSSEC, + linux.SO_PEEK_OFF, + linux.SO_PRIORITY, + linux.SO_RCVBUF, + linux.SO_RCVLOWAT, + linux.SO_RCVTIMEO, + linux.SO_REUSEADDR, + linux.SO_REUSEPORT, + linux.SO_RXQ_OVFL, + linux.SO_SELECT_ERR_QUEUE, + linux.SO_SNDBUF, + linux.SO_SNDTIMEO, + linux.SO_TIMESTAMP, + linux.SO_TIMESTAMPING, + linux.SO_TIMESTAMPNS, + linux.SO_TXTIME, + linux.SO_WIFI_STATUS, + linux.SO_ZEROCOPY: + + t.Kernel().EmitUnimplementedEvent(t) + } +} |