From 129734a35201b1bbcddbdbd3bd765bae9585d383 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 24 Apr 2024 18:36:27 -0700 Subject: [PATCH] Pass NEWLINK netlink commands to network stacks The NEWLINK commands contains many properties and here is no reason to have another abstract interface between the Sentry and network stacks. PiperOrigin-RevId: 627916629 --- pkg/sentry/inet/BUILD | 1 + pkg/sentry/inet/inet.go | 6 +++ pkg/sentry/inet/test_stack.go | 8 +++ pkg/sentry/socket/hostinet/BUILD | 1 + pkg/sentry/socket/hostinet/stack.go | 60 +++++++++++++++++++++ pkg/sentry/socket/netlink/route/protocol.go | 58 +------------------- pkg/sentry/socket/netstack/BUILD | 1 + pkg/sentry/socket/netstack/stack.go | 60 +++++++++++++++++++++ 8 files changed, 138 insertions(+), 57 deletions(-) diff --git a/pkg/sentry/inet/BUILD b/pkg/sentry/inet/BUILD index 2392cf2e4..035dc3b09 100644 --- a/pkg/sentry/inet/BUILD +++ b/pkg/sentry/inet/BUILD @@ -44,6 +44,7 @@ go_library( "//pkg/refs", "//pkg/sentry/fsimpl/nsfs", "//pkg/sentry/kernel/auth", + "//pkg/sentry/socket/netlink/nlmsg", "//pkg/sentry/socket/unix/transport", "//pkg/sync", "//pkg/sync/locking", diff --git a/pkg/sentry/inet/inet.go b/pkg/sentry/inet/inet.go index 71909e761..2a73abdb8 100644 --- a/pkg/sentry/inet/inet.go +++ b/pkg/sentry/inet/inet.go @@ -17,6 +17,9 @@ package inet import ( "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg" + "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -39,6 +42,9 @@ type Stack interface { // idx. AddInterfaceAddr(idx int32, addr InterfaceAddr) error + // SetInterface modifies or adds a new interface. + SetInterface(ctx context.Context, msg *nlmsg.Message) *syserr.Error + // RemoveInterfaceAddr removes an address from the network interface // identified by idx. RemoveInterfaceAddr(idx int32, addr InterfaceAddr) error diff --git a/pkg/sentry/inet/test_stack.go b/pkg/sentry/inet/test_stack.go index d8683645f..b8e88510a 100644 --- a/pkg/sentry/inet/test_stack.go +++ b/pkg/sentry/inet/test_stack.go @@ -19,6 +19,9 @@ import ( "fmt" "time" + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg" + "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -61,6 +64,11 @@ func (s *TestStack) RemoveInterface(idx int32) error { return nil } +// SetInterface implements Stack. +func (s *TestStack) SetInterface(ctx context.Context, msg *nlmsg.Message) *syserr.Error { + panic("unimplemented") +} + // InterfaceAddrs implements Stack. func (s *TestStack) InterfaceAddrs() map[int32][]InterfaceAddr { return s.InterfaceAddrsMap diff --git a/pkg/sentry/socket/hostinet/BUILD b/pkg/sentry/socket/hostinet/BUILD index 741337e18..5ac214e28 100644 --- a/pkg/sentry/socket/hostinet/BUILD +++ b/pkg/sentry/socket/hostinet/BUILD @@ -39,6 +39,7 @@ go_library( "//pkg/sentry/kernel/time", "//pkg/sentry/socket", "//pkg/sentry/socket/control", + "//pkg/sentry/socket/netlink/nlmsg", "//pkg/sentry/vfs", "//pkg/syserr", "//pkg/tcpip", diff --git a/pkg/sentry/socket/hostinet/stack.go b/pkg/sentry/socket/hostinet/stack.go index 028e507c8..8e6a5121d 100644 --- a/pkg/sentry/socket/hostinet/stack.go +++ b/pkg/sentry/socket/hostinet/stack.go @@ -23,10 +23,12 @@ import ( "strconv" "strings" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/inet" + "gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg" "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -165,6 +167,64 @@ func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr { return addrs } +// SetInterface implements inet.Stack.SetInterface. +func (s *Stack) SetInterface(ctx context.Context, msg *nlmsg.Message) *syserr.Error { + var ifinfomsg linux.InterfaceInfoMessage + attrs, ok := msg.GetData(&ifinfomsg) + if !ok { + return syserr.ErrInvalidArgument + } + for !attrs.Empty() { + // The index is unspecified, search by the interface name. + ahdr, value, rest, ok := attrs.ParseFirst() + if !ok { + return syserr.ErrInvalidArgument + } + attrs = rest + switch ahdr.Type { + case linux.IFLA_IFNAME: + if len(value) < 1 { + return syserr.ErrInvalidArgument + } + if ifinfomsg.Index != 0 { + // Device name changing isn't supported yet. + return syserr.ErrNotSupported + } + ifname := string(value[:len(value)-1]) + for idx, ifa := range s.Interfaces() { + if ifname == ifa.Name { + ifinfomsg.Index = idx + break + } + } + default: + ctx.Warningf("unexpected attribute: %x", ahdr.Type) + return syserr.ErrNotSupported + } + } + if ifinfomsg.Index == 0 { + return syserr.ErrNoDevice + } + + flags := msg.Header().Flags + if flags&(linux.NLM_F_EXCL|linux.NLM_F_REPLACE) != 0 { + return syserr.ErrExists + } + + if ifinfomsg.Flags != 0 || ifinfomsg.Change != 0 { + if ifinfomsg.Change & ^uint32(linux.IFF_UP) != 0 { + ctx.Warningf("Unsupported ifi_change flags: %x", ifinfomsg.Change) + return syserr.ErrInvalidArgument + } + if ifinfomsg.Flags & ^uint32(linux.IFF_UP) != 0 { + ctx.Warningf("Unsupported ifi_flags: %x", ifinfomsg.Change) + return syserr.ErrInvalidArgument + } + // Netstack interfaces are always up. + } + return nil +} + // AddInterfaceAddr implements inet.Stack.AddInterfaceAddr. func (*Stack) AddInterfaceAddr(idx int32, addr inet.InterfaceAddr) error { return addInterfaceAddr(idx, addr) diff --git a/pkg/sentry/socket/netlink/route/protocol.go b/pkg/sentry/socket/netlink/route/protocol.go index 2469cdde6..bfaa00765 100644 --- a/pkg/sentry/socket/netlink/route/protocol.go +++ b/pkg/sentry/socket/netlink/route/protocol.go @@ -169,63 +169,7 @@ func (p *Protocol) newLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me return syserr.ErrProtocolNotSupported } - var ifinfomsg linux.InterfaceInfoMessage - attrs, ok := msg.GetData(&ifinfomsg) - if !ok { - return syserr.ErrInvalidArgument - } - for !attrs.Empty() { - // The index is unspecified, search by the interface name. - ahdr, value, rest, ok := attrs.ParseFirst() - if !ok { - return syserr.ErrInvalidArgument - } - attrs = rest - switch ahdr.Type { - case linux.IFLA_IFNAME: - if len(value) < 1 { - return syserr.ErrInvalidArgument - } - if ifinfomsg.Index != 0 { - // Device name changing isn't supported yet. - return syserr.ErrNotSupported - } - ifname := string(value[:len(value)-1]) - for idx, ifa := range stack.Interfaces() { - if ifname == ifa.Name { - ifinfomsg.Index = idx - break - } - } - default: - ctx.Warningf("unexpected attribute: %x", ahdr.Type) - return syserr.ErrNotSupported - } - } - if ifinfomsg.Index == 0 { - return syserr.ErrNoDevice - } - - flags := msg.Header().Flags - if flags&linux.NLM_F_EXCL != 0 { - return syserr.ErrExists - } - if flags&linux.NLM_F_REPLACE != 0 { - return syserr.ErrExists - } - - if ifinfomsg.Flags != 0 || ifinfomsg.Change != 0 { - if ifinfomsg.Change & ^uint32(linux.IFF_UP) != 0 { - ctx.Warningf("Unsupported ifi_change flags: %x", ifinfomsg.Change) - return syserr.ErrInvalidArgument - } - if ifinfomsg.Flags & ^uint32(linux.IFF_UP) != 0 { - ctx.Warningf("Unsupported ifi_flags: %x", ifinfomsg.Change) - return syserr.ErrInvalidArgument - } - // Netstack interfaces are always up. - } - return nil + return stack.SetInterface(ctx, msg) } // delLink handles RTM_DELLINK requests. diff --git a/pkg/sentry/socket/netstack/BUILD b/pkg/sentry/socket/netstack/BUILD index c71c07124..511e09e9b 100644 --- a/pkg/sentry/socket/netstack/BUILD +++ b/pkg/sentry/socket/netstack/BUILD @@ -39,6 +39,7 @@ go_library( "//pkg/sentry/kernel/time", "//pkg/sentry/socket", "//pkg/sentry/socket/netfilter", + "//pkg/sentry/socket/netlink/nlmsg", "//pkg/sentry/vfs", "//pkg/sync", "//pkg/syserr", diff --git a/pkg/sentry/socket/netstack/stack.go b/pkg/sentry/socket/netstack/stack.go index 577b43263..2dcb1be39 100644 --- a/pkg/sentry/socket/netstack/stack.go +++ b/pkg/sentry/socket/netstack/stack.go @@ -18,10 +18,12 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/sentry/inet" + "gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg" "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -99,6 +101,64 @@ func (s *Stack) RemoveInterface(idx int32) error { return syserr.TranslateNetstackError(s.Stack.RemoveNIC(nic)).ToError() } +// SetInterface implements inet.Stack.SetInterface. +func (s *Stack) SetInterface(ctx context.Context, msg *nlmsg.Message) *syserr.Error { + var ifinfomsg linux.InterfaceInfoMessage + attrs, ok := msg.GetData(&ifinfomsg) + if !ok { + return syserr.ErrInvalidArgument + } + for !attrs.Empty() { + // The index is unspecified, search by the interface name. + ahdr, value, rest, ok := attrs.ParseFirst() + if !ok { + return syserr.ErrInvalidArgument + } + attrs = rest + switch ahdr.Type { + case linux.IFLA_IFNAME: + if len(value) < 1 { + return syserr.ErrInvalidArgument + } + if ifinfomsg.Index != 0 { + // Device name changing isn't supported yet. + return syserr.ErrNotSupported + } + ifname := string(value[:len(value)-1]) + for idx, ifa := range s.Interfaces() { + if ifname == ifa.Name { + ifinfomsg.Index = idx + break + } + } + default: + ctx.Warningf("unexpected attribute: %x", ahdr.Type) + return syserr.ErrNotSupported + } + } + if ifinfomsg.Index == 0 { + return syserr.ErrNoDevice + } + + flags := msg.Header().Flags + if flags&(linux.NLM_F_EXCL|linux.NLM_F_REPLACE) != 0 { + return syserr.ErrExists + } + + if ifinfomsg.Flags != 0 || ifinfomsg.Change != 0 { + if ifinfomsg.Change & ^uint32(linux.IFF_UP) != 0 { + ctx.Warningf("Unsupported ifi_change flags: %x", ifinfomsg.Change) + return syserr.ErrInvalidArgument + } + if ifinfomsg.Flags & ^uint32(linux.IFF_UP) != 0 { + ctx.Warningf("Unsupported ifi_flags: %x", ifinfomsg.Change) + return syserr.ErrInvalidArgument + } + // Netstack interfaces are always up. + } + return nil +} + // InterfaceAddrs implements inet.Stack.InterfaceAddrs. func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr { nicAddrs := make(map[int32][]inet.InterfaceAddr)