diff --git a/pkg/sentry/kernel/task_clone.go b/pkg/sentry/kernel/task_clone.go index f515637d9..78e7a4bd2 100644 --- a/pkg/sentry/kernel/task_clone.go +++ b/pkg/sentry/kernel/task_clone.go @@ -245,8 +245,8 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) { // nt that it must receive before its task goroutine starts running. defer nt.Start() - if args.Flags&linux.CLONE_THREAD == 0 && seccheck.Global.Enabled(seccheck.PointCloneProcess) { - mask, info := getCloneSeccheckInfo(t, nt) + if seccheck.Global.Enabled(seccheck.PointClone) { + mask, info := getCloneSeccheckInfo(t, nt, args.Flags) if err := seccheck.Global.SendToCheckers(func(c seccheck.Checker) error { return c.Clone(t, mask, info) }); err != nil { @@ -307,8 +307,8 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) { return ntid, nil, nil } -func getCloneSeccheckInfo(t, nt *Task) (seccheck.FieldSet, *pb.CloneInfo) { - fields := seccheck.Global.GetFieldSet(seccheck.PointCloneProcess) +func getCloneSeccheckInfo(t, nt *Task, flags uint64) (seccheck.FieldSet, *pb.CloneInfo) { + fields := seccheck.Global.GetFieldSet(seccheck.PointClone) t.k.tasks.mu.RLock() defer t.k.tasks.mu.RUnlock() @@ -316,6 +316,7 @@ func getCloneSeccheckInfo(t, nt *Task) (seccheck.FieldSet, *pb.CloneInfo) { CreatedThreadId: int32(nt.k.tasks.Root.tids[nt]), CreatedThreadGroupId: int32(nt.k.tasks.Root.tgids[nt.tg]), CreatedThreadStartTimeNs: nt.startTime.Nanoseconds(), + Flags: flags, } if !fields.Context.Empty() { diff --git a/pkg/sentry/kernel/task_exit.go b/pkg/sentry/kernel/task_exit.go index 5ce711051..50584c47c 100644 --- a/pkg/sentry/kernel/task_exit.go +++ b/pkg/sentry/kernel/task_exit.go @@ -662,12 +662,9 @@ func (t *Task) exitNotifyLocked(fromPtraceDetach bool) { t.parent.tg.eventQueue.Notify(EventExit | EventChildGroupStop | EventGroupContinue) } - // We don't send exit events for threads because we don't send CloneProcessStart events - // for threads (clone calls with CLONE_THREAD set). - // We also don't send exit events for the root process because we don't send + // We don't send exit events for the root process because we don't send // Clone or Exec events for the initial process. - shouldSendExit := t == t.tg.leader && t.tg != t.k.globalInit - if seccheck.Global.Enabled(seccheck.PointExitNotifyParent) && shouldSendExit { + if t.tg != t.k.globalInit && seccheck.Global.Enabled(seccheck.PointExitNotifyParent) { mask, info := getExitNotifyParentSeccheckInfo(t) if err := seccheck.Global.SendToCheckers(func(c seccheck.Checker) error { return c.ExitNotifyParent(t, mask, info) diff --git a/pkg/sentry/seccheck/metadata.go b/pkg/sentry/seccheck/metadata.go index 57a776074..f7c8287a4 100644 --- a/pkg/sentry/seccheck/metadata.go +++ b/pkg/sentry/seccheck/metadata.go @@ -24,7 +24,7 @@ import ( // PointX represents the checkpoint X. const ( - PointCloneProcess Point = iota + PointClone Point = iota PointContainerStart PointExecve PointExitNotifyParent @@ -225,7 +225,7 @@ func init() { // Points from the sentry namespace. registerPoint(PointDesc{ - ID: PointCloneProcess, + ID: PointClone, Name: "sentry/clone", ContextFields: defaultContextFields, }) diff --git a/pkg/sentry/seccheck/points/sentry.proto b/pkg/sentry/seccheck/points/sentry.proto index 6618533c0..313856d2e 100644 --- a/pkg/sentry/seccheck/points/sentry.proto +++ b/pkg/sentry/seccheck/points/sentry.proto @@ -22,13 +22,16 @@ import "pkg/sentry/seccheck/points/common.proto"; message CloneInfo { gvisor.common.ContextData context_data = 1; - // CreatedThreadID is the thread's ID in the root PID namespace. + // created_thread_id is the thread's ID in the root PID namespace. int32 created_thread_id = 3; int32 created_thread_group_id = 4; - // CreatedThreadStartTime is the thread's CLOCK_REALTIME start time. + // created_thread_start_time_ns is the thread's CLOCK_REALTIME start time. int64 created_thread_start_time_ns = 5; + + // flags are equivalent to the flags passed to clone(2). + uint64 flags = 6; } // ExecveInfo contains information used by the Execve checkpoint. diff --git a/pkg/sentry/seccheck/seccheck_test.go b/pkg/sentry/seccheck/seccheck_test.go index 9d80ecb3a..109fbfb2e 100644 --- a/pkg/sentry/seccheck/seccheck_test.go +++ b/pkg/sentry/seccheck/seccheck_test.go @@ -38,7 +38,7 @@ func (c *testChecker) Clone(ctx context.Context, fields FieldSet, info *pb.Clone func TestNoChecker(t *testing.T) { var s State - if s.Enabled(PointCloneProcess) { + if s.Enabled(PointClone) { t.Errorf("Enabled(PointClone): got true, wanted false") } } @@ -46,7 +46,7 @@ func TestNoChecker(t *testing.T) { func TestCheckerNotRegisteredForPoint(t *testing.T) { var s State s.AppendChecker(&testChecker{}, nil) - if s.Enabled(PointCloneProcess) { + if s.Enabled(PointClone) { t.Errorf("Enabled(PointClone): got true, wanted false") } } @@ -62,16 +62,16 @@ func TestCheckerRegistered(t *testing.T) { } req := []PointReq{ { - Pt: PointCloneProcess, + Pt: PointClone, Fields: FieldSet{Context: MakeFieldMask(FieldCtxtCredentials)}, }, } s.AppendChecker(checker, req) - if !s.Enabled(PointCloneProcess) { + if !s.Enabled(PointClone) { t.Errorf("Enabled(PointClone): got false, wanted true") } - fields := s.GetFieldSet(PointCloneProcess) + fields := s.GetFieldSet(PointClone) if !fields.Context.Contains(FieldCtxtCredentials) { t.Errorf("fields.Context.Contains(PointContextCredentials): got false, wanted true") } @@ -95,7 +95,7 @@ func TestMultipleCheckersRegistered(t *testing.T) { }, } reqs := []PointReq{ - {Pt: PointCloneProcess}, + {Pt: PointClone}, } s.AppendChecker(checker, reqs) @@ -104,16 +104,16 @@ func TestMultipleCheckersRegistered(t *testing.T) { return nil }} reqs = []PointReq{ - {Pt: PointCloneProcess}, + {Pt: PointClone}, } s.AppendChecker(checker, reqs) - if !s.Enabled(PointCloneProcess) { + if !s.Enabled(PointClone) { t.Errorf("Enabled(PointClone): got false, wanted true") } // CloneReq() should return the union of requested fields from all calls to // AppendChecker. - fields := s.GetFieldSet(PointCloneProcess) + fields := s.GetFieldSet(PointClone) if err := s.SendToCheckers(func(c Checker) error { return c.Clone(context.Background(), fields, &pb.CloneInfo{}) }); err != nil { @@ -139,7 +139,7 @@ func TestCheckpointReturnsFirstCheckerError(t *testing.T) { }, } reqs := []PointReq{ - {Pt: PointCloneProcess}, + {Pt: PointClone}, } s.AppendChecker(checker, reqs) @@ -152,7 +152,7 @@ func TestCheckpointReturnsFirstCheckerError(t *testing.T) { } s.AppendChecker(checker, reqs) - if !s.Enabled(PointCloneProcess) { + if !s.Enabled(PointClone) { t.Errorf("Enabled(PointClone): got false, wanted true") } if err := s.SendToCheckers(func(c Checker) error {