From c227d185a4c513aa71eff950506a257d7f95ec8a Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Tue, 5 Sep 2023 19:12:53 -0700 Subject: [PATCH] Emit SentryTcpListenEvent when the application listens on a tcp port. PiperOrigin-RevId: 562957239 --- pkg/sentry/socket/netstack/BUILD | 11 ++++++++++- pkg/sentry/socket/netstack/events.proto | 24 ++++++++++++++++++++++++ pkg/sentry/socket/netstack/netstack.go | 20 +++++++++++++++++++- pkg/tcpip/transport/tcp/endpoint.go | 6 +++--- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 pkg/sentry/socket/netstack/events.proto diff --git a/pkg/sentry/socket/netstack/BUILD b/pkg/sentry/socket/netstack/BUILD index b46eb7e38..c71c07124 100644 --- a/pkg/sentry/socket/netstack/BUILD +++ b/pkg/sentry/socket/netstack/BUILD @@ -1,4 +1,4 @@ -load("//tools:defs.bzl", "go_library") +load("//tools:defs.bzl", "go_library", "proto_library") package( default_applicable_licenses = ["//:license"], @@ -19,10 +19,12 @@ go_library( "//pkg/sentry:internal", ], deps = [ + ":events_go_proto", "//pkg/abi/linux", "//pkg/abi/linux/errno", "//pkg/context", "//pkg/errors/linuxerr", + "//pkg/eventchannel", "//pkg/hostarch", "//pkg/log", "//pkg/marshal", @@ -51,6 +53,13 @@ go_library( "//pkg/tcpip/transport/udp", "//pkg/usermem", "//pkg/waiter", + "@org_golang_google_protobuf//proto:go_default_library", "@org_golang_x_sys//unix:go_default_library", ], ) + +proto_library( + name = "events", + srcs = ["events.proto"], + visibility = ["//visibility:public"], +) diff --git a/pkg/sentry/socket/netstack/events.proto b/pkg/sentry/socket/netstack/events.proto new file mode 100644 index 000000000..16e288c97 --- /dev/null +++ b/pkg/sentry/socket/netstack/events.proto @@ -0,0 +1,24 @@ +// 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. + +syntax = "proto3"; + +package gvisor; + +// SentryTcpListenEvent is emitted when the application successfully +// listens on a netstack TCP socket. +message SentryTcpListenEvent { + // port is the port the socket is bound to. + optional int32 port = 1; +} diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 31c17af42..68e58aea5 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -35,10 +35,12 @@ import ( "time" "golang.org/x/sys/unix" + "google.golang.org/protobuf/proto" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/abi/linux/errno" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" + "gvisor.dev/gvisor/pkg/eventchannel" "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/marshal" @@ -52,6 +54,7 @@ import ( ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time" "gvisor.dev/gvisor/pkg/sentry/socket" "gvisor.dev/gvisor/pkg/sentry/socket/netfilter" + epb "gvisor.dev/gvisor/pkg/sentry/socket/netstack/events_go_proto" "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/syserr" @@ -794,7 +797,22 @@ func (s *sock) Bind(_ *kernel.Task, sockaddr []byte) *syserr.Error { // Listen implements the linux syscall listen(2) for sockets backed by // tcpip.Endpoint. func (s *sock) Listen(_ *kernel.Task, backlog int) *syserr.Error { - return syserr.TranslateNetstackError(s.Endpoint.Listen(backlog)) + if err := s.Endpoint.Listen(backlog); err != nil { + return syserr.TranslateNetstackError(err) + } + if !socket.IsTCP(s) { + return nil + } + + // Emit SentryTCPListenEvent with the bound port for tcp sockets. + addr, err := s.Endpoint.GetLocalAddress() + if err != nil { + panic(fmt.Sprintf("GetLocalAddress failed for tcp socket: %s", err)) + } + eventchannel.Emit(&epb.SentryTcpListenEvent{ + Port: proto.Int32(int32(addr.Port)), + }) + return nil } // blockingAccept implements a blocking version of accept(2), that is, if no diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 7ae7043ec..b05fdb484 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -2599,14 +2599,14 @@ func (e *endpoint) shutdownLocked(flags tcpip.ShutdownFlags) tcpip.Error { // Listen puts the endpoint in "listen" mode, which allows it to accept // new connections. func (e *endpoint) Listen(backlog int) tcpip.Error { - err := e.listen(backlog) - if err != nil { + if err := e.listen(backlog); err != nil { if !err.IgnoreStats() { e.stack.Stats().TCP.FailedConnectionAttempts.Increment() e.stats.FailedConnectionAttempts.Increment() } + return err } - return err + return nil } func (e *endpoint) listen(backlog int) tcpip.Error {