diff --git a/pkg/sentry/socket/hostinet/stack.go b/pkg/sentry/socket/hostinet/stack.go index 2a35bdbc8..4b7026803 100644 --- a/pkg/sentry/socket/hostinet/stack.go +++ b/pkg/sentry/socket/hostinet/stack.go @@ -54,9 +54,6 @@ var defaultSendBufSize = inet.TCPBufferSize{ // Stack implements inet.Stack for host sockets. type Stack struct { // Stack is immutable. - interfaces map[int32]*inet.Interface - interfaceAddrs map[int32][]inet.InterfaceAddr - routes []inet.Route supportsIPv6 bool tcpRecovery inet.TCPLossRecovery tcpRecvBufSize inet.TCPBufferSize @@ -74,22 +71,11 @@ func (*Stack) Destroy() { // NewStack returns an empty Stack containing no configuration. func NewStack() *Stack { - return &Stack{ - interfaces: make(map[int32]*inet.Interface), - interfaceAddrs: make(map[int32][]inet.InterfaceAddr), - } + return &Stack{} } // Configure sets up the stack using the current state of the host network. func (s *Stack) Configure(allowRawSockets bool) error { - if err := s.initializeInterfaces(); err != nil { - return err - } - - if err := s.initializeRoutes(); err != nil { - return err - } - if _, err := os.Stat("/proc/net/if_inet6"); err == nil { s.supportsIPv6 = true } @@ -193,12 +179,12 @@ func extractHostRoutes(routeMsgs []syscall.NetlinkMessage) ([]inet.Route, error) return routes, nil } -func getHostLinks() (map[int32]*inet.Interface, error) { +func getHostInterfaces() (map[int32]inet.Interface, error) { msgs, err := doNetlinkRouteRequest(unix.RTM_GETLINK) if err != nil { return nil, fmt.Errorf("RTM_GETLINK failed: %v", err) } - links := make(map[int32]*inet.Interface, len(msgs)) + ifs := make(map[int32]inet.Interface, len(msgs)) for _, msg := range msgs { if msg.Header.Type != unix.RTM_NEWLINK { continue @@ -227,12 +213,12 @@ func getHostLinks() (map[int32]*inet.Interface, error) { inetIF.Name = string(attr.Value[:len(attr.Value)-1]) } } - links[ifinfo.Index] = &inetIF + ifs[ifinfo.Index] = inetIF } - return links, nil + return ifs, nil } -func getHostRoutes() (map[int32][]inet.InterfaceAddr, error) { +func getHostInterfaceAddrs() (map[int32][]inet.InterfaceAddr, error) { msgs, err := doNetlinkRouteRequest(unix.RTM_GETADDR) if err != nil { return nil, fmt.Errorf("RTM_GETADDR failed: %v", err) @@ -268,40 +254,6 @@ func getHostRoutes() (map[int32][]inet.InterfaceAddr, error) { return addrs, nil } -func (s *Stack) initializeInterfaces() error { - links, err := getHostLinks() - if err != nil { - return err - } - s.interfaces = links - - addrs, err := getHostRoutes() - if err != nil { - return err - } - s.interfaceAddrs = addrs - - // query interface features for each of the host interfaces. - if err := queryInterfaceFeatures(s.interfaces); err != nil { - return err - } - return nil -} - -func (s *Stack) initializeRoutes() error { - routes, err := doNetlinkRouteRequest(unix.RTM_GETROUTE) - if err != nil { - return fmt.Errorf("RTM_GETROUTE failed: %v", err) - } - - s.routes, err = extractHostRoutes(routes) - if err != nil { - return err - } - - return nil -} - func doNetlinkRouteRequest(req int) ([]syscall.NetlinkMessage, error) { data, err := syscall.NetlinkRIB(req, syscall.AF_UNSPEC) if err != nil { @@ -329,11 +281,18 @@ func readTCPBufferSizeFile(filename string) (inet.TCPBufferSize, error) { // Interfaces implements inet.Stack.Interfaces. func (s *Stack) Interfaces() map[int32]inet.Interface { - interfaces := make(map[int32]inet.Interface) - for k, v := range s.interfaces { - interfaces[k] = *v + ifs, err := getHostInterfaces() + if err != nil { + log.Warningf("could not get host interface: %v", err) + return nil } - return interfaces + + // query interface features for each of the host interfaces. + if err := queryInterfaceFeatures(ifs); err != nil { + log.Warningf("could not query host interfaces: %v", err) + return nil + } + return ifs } // RemoveInterface implements inet.Stack.RemoveInterface. @@ -343,9 +302,10 @@ func (*Stack) RemoveInterface(int32) error { // InterfaceAddrs implements inet.Stack.InterfaceAddrs. func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr { - addrs := make(map[int32][]inet.InterfaceAddr) - for k, v := range s.interfaceAddrs { - addrs[k] = append([]inet.InterfaceAddr(nil), v...) + addrs, err := getHostInterfaceAddrs() + if err != nil { + log.Warningf("failed to get host interface addresses: %v", err) + return nil } return addrs } @@ -498,7 +458,19 @@ func (s *Stack) Statistics(stat any, arg string) error { // RouteTable implements inet.Stack.RouteTable. func (s *Stack) RouteTable() []inet.Route { - return append([]inet.Route(nil), s.routes...) + msgs, err := doNetlinkRouteRequest(unix.RTM_GETROUTE) + if err != nil { + log.Warningf("RTM_GETROUTE failed: %v", err) + return nil + } + + routes, err := extractHostRoutes(msgs) + if err != nil { + log.Warningf("failed to extract host routes: %v", err) + return nil + } + + return append([]inet.Route(nil), routes...) } // Pause implements inet.Stack.Pause. diff --git a/pkg/sentry/socket/hostinet/stack_unsafe.go b/pkg/sentry/socket/hostinet/stack_unsafe.go index e16aef32b..2416b5d54 100644 --- a/pkg/sentry/socket/hostinet/stack_unsafe.go +++ b/pkg/sentry/socket/hostinet/stack_unsafe.go @@ -24,7 +24,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/inet" ) -func queryInterfaceFeatures(interfaces map[int32]*inet.Interface) error { +func queryInterfaceFeatures(interfaces map[int32]inet.Interface) error { fd, err := queryFD() if err != nil { return err @@ -76,8 +76,10 @@ func queryInterfaceFeatures(interfaces map[int32]*inet.Interface) error { next = next[unsafe.Sizeof(linux.EthtoolGetFeaturesBlock{}):] } // Store the queried features. - interfaces[idx].Features = make([]linux.EthtoolGetFeaturesBlock, gfeatures.Size) - copy(interfaces[idx].Features, featureBlocks) + iface := interfaces[idx] + iface.Features = make([]linux.EthtoolGetFeaturesBlock, gfeatures.Size) + copy(iface.Features, featureBlocks) + interfaces[idx] = iface // This ensures b is not garbage collected before this point to ensure that // the slice is not collected before the syscall returns and we copy out the diff --git a/runsc/boot/filter/extra_filters_hostinet.go b/runsc/boot/filter/extra_filters_hostinet.go index e8521e3f1..2f6db6b31 100644 --- a/runsc/boot/filter/extra_filters_hostinet.go +++ b/runsc/boot/filter/extra_filters_hostinet.go @@ -53,6 +53,11 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { seccomp.MatchAny{}, seccomp.EqualTo(unix.SIOCGIFCONF), }, + // Needed to query netlink sockets. + { + seccomp.MatchAny{}, + seccomp.EqualTo(unix.SIOCETHTOOL), + }, }, unix.SYS_LISTEN: {}, unix.SYS_READV: {}, @@ -79,7 +84,26 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { // Generate rules for socket creation based on hostinet's supported // socket types. - socketRules := []seccomp.Rule{} + socketRules := []seccomp.Rule{ + // Need NETLINK_ROUTE and stream sockets to query host + // interfaces and routes. + seccomp.Rule{ + seccomp.EqualTo(unix.AF_NETLINK), + seccomp.EqualTo(unix.SOCK_RAW | unix.SOCK_CLOEXEC), + seccomp.EqualTo(unix.NETLINK_ROUTE), + }, + seccomp.Rule{ + seccomp.EqualTo(unix.AF_INET), + seccomp.EqualTo(unix.SOCK_STREAM), + seccomp.EqualTo(0), + }, + seccomp.Rule{ + seccomp.EqualTo(unix.AF_INET6), + seccomp.EqualTo(unix.SOCK_STREAM), + seccomp.EqualTo(0), + }, + } + stypes := hostinet.AllowedSocketTypes if allowRawSockets { stypes = append(stypes, hostinet.AllowedRawSocketTypes...)