Fire clone point for thread creation

Thread creation tracking is required by Falco.

Updates #4805

PiperOrigin-RevId: 447003670
This commit is contained in:
Fabricio Voznika
2022-05-06 09:28:44 -07:00
committed by gVisor bot
parent 2d6e64019b
commit a23e60af39
5 changed files with 25 additions and 24 deletions
+5 -4
View File
@@ -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() {
+2 -5
View File
@@ -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)
+2 -2
View File
@@ -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,
})
+5 -2
View File
@@ -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.
+11 -11
View File
@@ -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 {