diff --git a/examples/seccheck/BUILD b/examples/seccheck/BUILD index ed4fbbabb..9fd199133 100644 --- a/examples/seccheck/BUILD +++ b/examples/seccheck/BUILD @@ -9,6 +9,7 @@ cc_binary( deps = [ # any_cc_proto placeholder, "//pkg/sentry/seccheck/points:points_cc_proto", + "@com_google_absl//absl/cleanup", "@com_google_absl//absl/strings", ], ) diff --git a/examples/seccheck/pod_init.json b/examples/seccheck/pod_init.json index a6ee6cca8..d606b2245 100644 --- a/examples/seccheck/pod_init.json +++ b/examples/seccheck/pod_init.json @@ -2,6 +2,9 @@ "trace_session": { "name": "Default", "points": [ + { + "name": "container/start" + }, { "name": "sentry/clone" } diff --git a/examples/seccheck/server.cc b/examples/seccheck/server.cc index 38f91d37e..51729d39e 100644 --- a/examples/seccheck/server.cc +++ b/examples/seccheck/server.cc @@ -27,7 +27,9 @@ #include #include "google/protobuf/any.pb.h" +#include "absl/cleanup/cleanup.h" #include "absl/strings/string_view.h" +#include "pkg/sentry/seccheck/points/container.pb.h" #include "pkg/sentry/seccheck/points/sentry.pb.h" typedef std::function Callback; @@ -65,6 +67,7 @@ void unpack(const google::protobuf::Any& any) { } std::map dispatchers = { + {"gvisor.container.Start", unpack<::gvisor::container::Start>}, {"gvisor.sentry.CloneInfo", unpack<::gvisor::sentry::CloneInfo>}, {"gvisor.sentry.ExecveInfo", unpack<::gvisor::sentry::ExecveInfo>}, {"gvisor.sentry.ExitNotifyParentInfo", @@ -179,6 +182,7 @@ extern "C" int main(int argc, char** argv) { if (sock < 0) { err(1, "socket"); } + auto sock_closer = absl::MakeCleanup([sock] { close(sock); }); struct sockaddr_un addr; addr.sun_family = AF_UNIX; @@ -194,6 +198,7 @@ extern "C" int main(int argc, char** argv) { if (epoll_fd < 0) { err(1, "epoll_create"); } + auto epoll_closer = absl::MakeCleanup([epoll_fd] { close(epoll_fd); }); startPollThread(epoll_fd); for (;;) { @@ -213,9 +218,4 @@ extern "C" int main(int argc, char** argv) { err(1, "epoll_ctl(ADD)"); } } - - close(sock); - unlink(path.c_str()); - - return 0; } diff --git a/pkg/sentry/kernel/seccheck.go b/pkg/sentry/kernel/seccheck.go index 91e17697b..9afb7c130 100644 --- a/pkg/sentry/kernel/seccheck.go +++ b/pkg/sentry/kernel/seccheck.go @@ -33,10 +33,6 @@ func LoadSeccheckDataLocked(t *Task, mask seccheck.FieldMask, info *pb.ContextDa if mask.Contains(seccheck.FieldCtxtTime) { info.TimeNs = t.k.RealtimeClock().Now().Nanoseconds() } - - if t == nil { - return - } if mask.Contains(seccheck.FieldCtxtThreadID) { info.ThreadId = int32(t.k.tasks.Root.tids[t]) } diff --git a/pkg/sentry/seccheck/checkers/remote/remote.go b/pkg/sentry/seccheck/checkers/remote/remote.go index c7534fb17..b2b25dc30 100644 --- a/pkg/sentry/seccheck/checkers/remote/remote.go +++ b/pkg/sentry/seccheck/checkers/remote/remote.go @@ -173,3 +173,8 @@ func (r *Remote) ExitNotifyParent(_ context.Context, _ seccheck.FieldSet, info * r.write(info) return nil } + +func (r *Remote) ContainerStart(_ context.Context, _ seccheck.FieldSet, info *pb.Start) error { + r.write(info) + return nil +} diff --git a/pkg/sentry/seccheck/metadata.go b/pkg/sentry/seccheck/metadata.go index bf4a73eac..868835df0 100644 --- a/pkg/sentry/seccheck/metadata.go +++ b/pkg/sentry/seccheck/metadata.go @@ -21,6 +21,12 @@ import ( "gvisor.dev/gvisor/pkg/fd" ) +const ( + // ContainerStartFieldEnv is an optional field to collect list of environment + // variables set for the container start process. + ContainerStartFieldEnv Field = iota +) + var points = map[string]PointDesc{} var sinks = map[string]SinkDesc{} @@ -146,6 +152,18 @@ func validateFields(fields []FieldDesc) error { // These are all the points available in the system. func init() { + // Points from the container namespace. + registerPoint(PointDesc{ + ID: PointContainerStart, + Name: "container/start", + OptionalFields: []FieldDesc{ + { + ID: ContainerStartFieldEnv, + Name: "env", + }, + }, + }) + // Points from the sentry namespace. registerPoint(PointDesc{ ID: PointClone, diff --git a/pkg/sentry/seccheck/points/BUILD b/pkg/sentry/seccheck/points/BUILD index 0142b4b73..d584d55fa 100644 --- a/pkg/sentry/seccheck/points/BUILD +++ b/pkg/sentry/seccheck/points/BUILD @@ -8,6 +8,7 @@ proto_library( name = "points", srcs = [ "common.proto", + "container.proto", "sentry.proto", ], ) diff --git a/pkg/sentry/seccheck/points/container.proto b/pkg/sentry/seccheck/points/container.proto new file mode 100644 index 000000000..da216fa57 --- /dev/null +++ b/pkg/sentry/seccheck/points/container.proto @@ -0,0 +1,27 @@ +// Copyright 2022 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.container; + +import "pkg/sentry/seccheck/points/common.proto"; + +message Start { + gvisor.common.ContextData context_data = 1; + string id = 2; + string cwd = 3; + repeated string args = 4; + repeated string env = 5; +} diff --git a/pkg/sentry/seccheck/seccheck.go b/pkg/sentry/seccheck/seccheck.go index 102571d69..d24cc3d15 100644 --- a/pkg/sentry/seccheck/seccheck.go +++ b/pkg/sentry/seccheck/seccheck.go @@ -31,6 +31,7 @@ const ( PointClone Point = iota PointExecve PointExitNotifyParent + PointContainerStart // Add new Points above this line. pointLength @@ -116,6 +117,7 @@ type Checker interface { Clone(ctx context.Context, fields FieldSet, info *pb.CloneInfo) error Execve(ctx context.Context, fields FieldSet, info *pb.ExecveInfo) error ExitNotifyParent(ctx context.Context, fields FieldSet, info *pb.ExitNotifyParentInfo) error + ContainerStart(context.Context, FieldSet, *pb.Start) error } // CheckerDefaults may be embedded by implementations of Checker to obtain @@ -139,6 +141,11 @@ func (CheckerDefaults) ExitNotifyParent(context.Context, FieldSet, *pb.ExitNotif return nil } +// ContainerStart implements Checker.ContainerStart. +func (CheckerDefaults) ContainerStart(context.Context, FieldSet, *pb.Start) error { + return nil +} + // PointReq indicates what Point a corresponding Checker runs at, and what // information it requires at those Points. type PointReq struct { @@ -209,6 +216,16 @@ func (s *State) appendCheckerLocked(c Checker) { s.registrationSeq.EndWrite() } +// SendToCheckers iterates over all checkers and calls fn for each one of them. +func (s *State) SendToCheckers(fn func(c Checker) error) error { + for _, c := range s.getCheckers() { + if err := fn(c); err != nil { + return err + } + } + return nil +} + // GetFieldSet returns the FieldSet that has been configured for a given Point. func (s *State) GetFieldSet(p Point) FieldSet { s.registrationMu.RLock() diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD index 8aaee6612..40b6439cd 100644 --- a/runsc/boot/BUILD +++ b/runsc/boot/BUILD @@ -84,6 +84,7 @@ go_library( "//pkg/sentry/platform", "//pkg/sentry/seccheck", "//pkg/sentry/seccheck/checkers/remote", + "//pkg/sentry/seccheck/points:points_go_proto", "//pkg/sentry/socket/hostinet", "//pkg/sentry/socket/netfilter", "//pkg/sentry/socket/netlink", diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 428ae77ec..0dc711598 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -48,6 +48,8 @@ import ( "gvisor.dev/gvisor/pkg/sentry/loader" "gvisor.dev/gvisor/pkg/sentry/pgalloc" "gvisor.dev/gvisor/pkg/sentry/platform" + "gvisor.dev/gvisor/pkg/sentry/seccheck" + pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto" "gvisor.dev/gvisor/pkg/sentry/socket/netfilter" "gvisor.dev/gvisor/pkg/sentry/syscalls/linux/vfs2" "gvisor.dev/gvisor/pkg/sentry/time" @@ -642,6 +644,23 @@ func (l *Loader) run() error { if err != nil { return err } + + if seccheck.Global.Enabled(seccheck.PointContainerStart) { + evt := pb.Start{ + Id: l.sandboxID, + Cwd: l.root.spec.Process.Cwd, + Args: l.root.spec.Process.Args, + } + fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart) + if fields.Local.Contains(seccheck.ContainerStartFieldEnv) { + evt.Env = l.root.spec.Process.Env + } + + ctx := l.root.procArgs.NewContext(l.k) + _ = seccheck.Global.SendToCheckers(func(c seccheck.Checker) error { + return c.ContainerStart(ctx, fields, &evt) + }) + } } ep.tg = l.k.GlobalInit() @@ -770,6 +789,23 @@ func (l *Loader) startSubcontainer(spec *specs.Spec, conf *config.Config, cid st if err != nil { return err } + + if seccheck.Global.Enabled(seccheck.PointContainerStart) { + evt := pb.Start{ + Id: cid, + Cwd: spec.Process.Cwd, + Args: spec.Process.Args, + } + fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart) + if fields.Local.Contains(seccheck.ContainerStartFieldEnv) { + evt.Env = spec.Process.Env + } + ctx := info.procArgs.NewContext(l.k) + _ = seccheck.Global.SendToCheckers(func(c seccheck.Checker) error { + return c.ContainerStart(ctx, fields, &evt) + }) + } + l.k.StartProcess(ep.tg) return nil }