gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/trace/trace_test.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package trace provides end-to-end integration tests for `runsc trace`.
    16  package trace
    17  
    18  import (
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"golang.org/x/sys/unix"
    27  	"google.golang.org/protobuf/proto"
    28  	"gvisor.dev/gvisor/pkg/sentry/seccheck"
    29  	pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
    30  	"gvisor.dev/gvisor/pkg/sentry/seccheck/sinks/remote/test"
    31  	"gvisor.dev/gvisor/pkg/test/testutil"
    32  	"gvisor.dev/gvisor/test/trace/config"
    33  )
    34  
    35  var cutoffTime time.Time
    36  
    37  type checkers struct {
    38  	checker func(test.Message) error
    39  	count   int
    40  }
    41  
    42  // TestAll enabled all trace points in the system with all optional and context
    43  // fields enabled. Then it runs a workload that will trigger those points and
    44  // run some basic validation over the points generated.
    45  func TestAll(t *testing.T) {
    46  	server, err := test.NewServer()
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	runsc, err := testutil.FindFile("runsc/runsc")
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	builder := config.Builder{}
    56  	if err := builder.LoadAllPoints(runsc); err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	builder.AddSink(seccheck.SinkConfig{
    60  		Name: "remote",
    61  		Config: map[string]any{
    62  			"endpoint": server.Endpoint,
    63  		},
    64  	})
    65  
    66  	cfgFile, err := os.CreateTemp(testutil.TmpDir(), "config")
    67  	if err != nil {
    68  		t.Fatalf("error creating tmp file: %v", err)
    69  	}
    70  	defer cfgFile.Close()
    71  	if err := builder.WriteInitConfig(cfgFile); err != nil {
    72  		t.Fatalf("writing config file: %v", err)
    73  	}
    74  
    75  	workload, err := testutil.FindFile("test/trace/workload/workload")
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	// No trace point should have a time lesser than this.
    80  	cutoffTime = time.Now()
    81  	cmd := exec.Command(
    82  		runsc,
    83  		"--debug", "--alsologtostderr", // Debug logging for troubleshooting
    84  		"--rootless", "--network=none", "--TESTONLY-unsafe-nonroot", // Disable features that we don't care
    85  		"--pod-init-config", cfgFile.Name(),
    86  		"do", workload)
    87  	out, err := cmd.CombinedOutput()
    88  	t.Log(string(out))
    89  	if err != nil {
    90  		t.Fatalf("runsc do: %v", err)
    91  	}
    92  
    93  	// Wait until the sandbox disconnects to ensure all points were gathered.
    94  	server.WaitForNoClients()
    95  
    96  	matchers := matchPoints(t, server.GetPoints())
    97  	extraMatchers(t, server.GetPoints(), matchers)
    98  	validatePoints(t, server.GetPoints(), matchers)
    99  }
   100  
   101  func matchPoints(t *testing.T, msgs []test.Message) map[pb.MessageType]*checkers {
   102  	// Register functions that verify each available point.
   103  	matchers := map[pb.MessageType]*checkers{
   104  		pb.MessageType_MESSAGE_CONTAINER_START:           {checker: checkContainerStart},
   105  		pb.MessageType_MESSAGE_SENTRY_CLONE:              {checker: checkSentryClone},
   106  		pb.MessageType_MESSAGE_SENTRY_EXEC:               {checker: checkSentryExec},
   107  		pb.MessageType_MESSAGE_SENTRY_EXIT_NOTIFY_PARENT: {checker: checkSentryExitNotifyParent},
   108  		pb.MessageType_MESSAGE_SENTRY_TASK_EXIT:          {checker: checkSentryTaskExit},
   109  		pb.MessageType_MESSAGE_SYSCALL_CLOSE:             {checker: checkSyscallClose},
   110  		pb.MessageType_MESSAGE_SYSCALL_CONNECT:           {checker: checkSyscallConnect},
   111  		pb.MessageType_MESSAGE_SYSCALL_EXECVE:            {checker: checkSyscallExecve},
   112  		pb.MessageType_MESSAGE_SYSCALL_OPEN:              {checker: checkSyscallOpen},
   113  		pb.MessageType_MESSAGE_SYSCALL_RAW:               {checker: checkSyscallRaw},
   114  		pb.MessageType_MESSAGE_SYSCALL_READ:              {checker: checkSyscallRead},
   115  		pb.MessageType_MESSAGE_SYSCALL_SOCKET:            {checker: checkSyscallSocket},
   116  		pb.MessageType_MESSAGE_SYSCALL_WRITE:             {checker: checkSyscallWrite},
   117  		pb.MessageType_MESSAGE_SYSCALL_CHDIR:             {checker: checkSyscallChdir},
   118  		pb.MessageType_MESSAGE_SYSCALL_SETID:             {checker: checkSyscallSetid},
   119  		pb.MessageType_MESSAGE_SYSCALL_SETRESID:          {checker: checkSyscallSetresid},
   120  		pb.MessageType_MESSAGE_SYSCALL_CHROOT:            {checker: checkSyscallChroot},
   121  		pb.MessageType_MESSAGE_SYSCALL_DUP:               {checker: checkSyscallDup},
   122  		pb.MessageType_MESSAGE_SYSCALL_PRLIMIT64:         {checker: checkSyscallPrlimit64},
   123  		pb.MessageType_MESSAGE_SYSCALL_EVENTFD:           {checker: checkSyscallEventfd},
   124  		pb.MessageType_MESSAGE_SYSCALL_SIGNALFD:          {checker: checkSyscallSignalfd},
   125  		pb.MessageType_MESSAGE_SYSCALL_BIND:              {checker: checkSyscallBind},
   126  		pb.MessageType_MESSAGE_SYSCALL_ACCEPT:            {checker: checkSyscallAccept},
   127  		pb.MessageType_MESSAGE_SYSCALL_FCNTL:             {checker: checkSyscallFcntl},
   128  		pb.MessageType_MESSAGE_SYSCALL_PIPE:              {checker: checkSyscallPipe},
   129  		pb.MessageType_MESSAGE_SYSCALL_TIMERFD_CREATE:    {checker: checkSyscallTimerfdCreate},
   130  		pb.MessageType_MESSAGE_SYSCALL_TIMERFD_SETTIME:   {checker: checkSyscallTimerfdSettime},
   131  		pb.MessageType_MESSAGE_SYSCALL_TIMERFD_GETTIME:   {checker: checkSyscallTimerfdGettime},
   132  		pb.MessageType_MESSAGE_SYSCALL_INOTIFY_INIT:      {checker: checkSyscallInotifyInit},
   133  		pb.MessageType_MESSAGE_SYSCALL_INOTIFY_ADD_WATCH: {checker: checkSyscallInotifyInitAddWatch},
   134  		pb.MessageType_MESSAGE_SYSCALL_INOTIFY_RM_WATCH:  {checker: checkSyscallInotifyInitRmWatch},
   135  		pb.MessageType_MESSAGE_SYSCALL_CLONE:             {checker: checkSyscallClone},
   136  	}
   137  	return matchers
   138  }
   139  
   140  func validatePoints(t *testing.T, msgs []test.Message, matchers map[pb.MessageType]*checkers) {
   141  	for _, msg := range msgs {
   142  		t.Logf("Processing message type %v", msg.MsgType)
   143  		if handler := matchers[msg.MsgType]; handler == nil {
   144  			// All points generated should have a corresponding matcher.
   145  			t.Errorf("No matcher for message type %v", msg.MsgType)
   146  		} else {
   147  			handler.count++
   148  			if err := handler.checker(msg); err != nil {
   149  				t.Errorf("message type %v: %v", msg.MsgType, err)
   150  			}
   151  		}
   152  	}
   153  	for msgType, match := range matchers {
   154  		t.Logf("Processed %d messages for %v", match.count, msgType)
   155  		if match.count == 0 {
   156  			// All matchers should be triggered at least once to ensure points are
   157  			// firing with the workload.
   158  			t.Errorf("no point was generated for %v", msgType)
   159  		}
   160  	}
   161  }
   162  
   163  func checkTimeNs(ns int64) error {
   164  	if ns <= int64(cutoffTime.Nanosecond()) {
   165  		return fmt.Errorf("time: got: %d (%v), should not be less than %d (%v)", ns, time.Unix(0, ns), cutoffTime.Nanosecond(), cutoffTime)
   166  	}
   167  	return nil
   168  }
   169  
   170  type contextDataOpts struct {
   171  	skipCwd bool
   172  }
   173  
   174  func checkContextData(data *pb.ContextData) error {
   175  	return checkContextDataOpts(data, contextDataOpts{})
   176  }
   177  
   178  func checkContextDataOpts(data *pb.ContextData, opts contextDataOpts) error {
   179  	if data == nil {
   180  		return fmt.Errorf("ContextData should not be nil")
   181  	}
   182  	if !strings.HasPrefix(data.ContainerId, "runsc-") {
   183  		return fmt.Errorf("invalid container ID %q", data.ContainerId)
   184  	}
   185  
   186  	if err := checkTimeNs(data.TimeNs); err != nil {
   187  		return err
   188  	}
   189  	if err := checkTimeNs(data.ThreadStartTimeNs); err != nil {
   190  		return err
   191  	}
   192  	if data.ThreadStartTimeNs > data.TimeNs {
   193  		return fmt.Errorf("thread_start_time should not be greater than point time: %d (%v), got: %d (%v)", data.TimeNs, time.Unix(0, data.TimeNs), data.ThreadStartTimeNs, time.Unix(0, data.ThreadStartTimeNs))
   194  	}
   195  	if err := checkTimeNs(data.ThreadGroupStartTimeNs); err != nil {
   196  		return err
   197  	}
   198  	if data.ThreadGroupStartTimeNs > data.TimeNs {
   199  		return fmt.Errorf("thread_group_start_time should not be greater than point time: %d (%v), got: %d (%v)", data.TimeNs, time.Unix(0, data.TimeNs), data.ThreadGroupStartTimeNs, time.Unix(0, data.ThreadGroupStartTimeNs))
   200  	}
   201  
   202  	if data.ThreadId <= 0 {
   203  		return fmt.Errorf("invalid thread_id: %v", data.ThreadId)
   204  	}
   205  	if data.ThreadGroupId <= 0 {
   206  		return fmt.Errorf("invalid thread_group_id: %v", data.ThreadGroupId)
   207  	}
   208  	if !opts.skipCwd && len(data.Cwd) == 0 {
   209  		return fmt.Errorf("invalid cwd: %v", data.Cwd)
   210  	}
   211  	if len(data.ProcessName) == 0 {
   212  		return fmt.Errorf("invalid process_name: %v", data.ProcessName)
   213  	}
   214  	return nil
   215  }
   216  
   217  func checkContainerStart(msg test.Message) error {
   218  	p := pb.Start{}
   219  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   220  		return err
   221  	}
   222  	if err := checkContextData(p.ContextData); err != nil {
   223  		return err
   224  	}
   225  	if !strings.HasPrefix(p.Id, "runsc-") {
   226  		return fmt.Errorf("invalid container ID %q", p.Id)
   227  	}
   228  	cwd, err := os.Getwd()
   229  	if err != nil {
   230  		return fmt.Errorf("Getwd(): %v", err)
   231  	}
   232  	if cwd != p.Cwd {
   233  		return fmt.Errorf("invalid cwd, want: %q, got: %q", cwd, p.Cwd)
   234  	}
   235  	if len(p.Args) == 0 {
   236  		return fmt.Errorf("empty args")
   237  	}
   238  	if len(p.Env) == 0 {
   239  		return fmt.Errorf("empty env")
   240  	}
   241  	for _, e := range p.Env {
   242  		if strings.IndexRune(e, '=') == -1 {
   243  			return fmt.Errorf("malformed env: %q", e)
   244  		}
   245  	}
   246  	if p.Terminal {
   247  		return fmt.Errorf("terminal should be off")
   248  	}
   249  	return nil
   250  }
   251  
   252  func checkSentryTaskExit(msg test.Message) error {
   253  	p := pb.TaskExit{}
   254  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   255  		return err
   256  	}
   257  	if err := checkContextData(p.ContextData); err != nil {
   258  		return err
   259  	}
   260  	return nil
   261  }
   262  
   263  func checkSyscallRaw(msg test.Message) error {
   264  	p := pb.Syscall{}
   265  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   266  		return err
   267  	}
   268  	if err := checkContextData(p.ContextData); err != nil {
   269  		return err
   270  	}
   271  	// Sanity check that Sysno is within valid range. If sysno could be larger
   272  	// than the value below, update it accordingly.
   273  	if p.Sysno > 500 {
   274  		return fmt.Errorf("invalid syscall number %d", p.Sysno)
   275  	}
   276  	return nil
   277  }
   278  
   279  func checkSyscallClose(msg test.Message) error {
   280  	p := pb.Close{}
   281  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   282  		return err
   283  	}
   284  	if err := checkContextData(p.ContextData); err != nil {
   285  		return err
   286  	}
   287  	if p.Fd < 0 {
   288  		// Although negative FD is possible, it doesn't happen in the test.
   289  		return fmt.Errorf("closing negative FD: %d", p.Fd)
   290  	}
   291  	return nil
   292  }
   293  
   294  func checkSyscallOpen(msg test.Message) error {
   295  	p := pb.Open{}
   296  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   297  		return err
   298  	}
   299  	if err := checkContextData(p.ContextData); err != nil {
   300  		return err
   301  	}
   302  	return nil
   303  }
   304  
   305  func checkSyscallRead(msg test.Message) error {
   306  	p := pb.Read{}
   307  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   308  		return err
   309  	}
   310  	if err := checkContextData(p.ContextData); err != nil {
   311  		return err
   312  	}
   313  	if p.Fd < 0 {
   314  		// Although negative FD is possible, it doesn't happen in the test.
   315  		return fmt.Errorf("read negative FD: %d", p.Fd)
   316  	}
   317  	if p.HasOffset {
   318  		// Workload always uses 20 for read offsets (account for partial reads).
   319  		if lower, upper := int64(20), int64(120); p.Offset < lower && p.Offset > upper {
   320  			return fmt.Errorf("invalid offset, want: [%d, %d], got: %d", lower, upper, p.Offset)
   321  		}
   322  	} else if p.Offset != 0 {
   323  		return fmt.Errorf("offset should be 0: %+v", &p)
   324  	}
   325  	if p.Flags != 0 && p.Flags != unix.RWF_HIPRI {
   326  		return fmt.Errorf("invalid flag value, want: 0 || RWF_HIPRI, got: %+x", p.Flags)
   327  	}
   328  	return nil
   329  }
   330  
   331  func checkSyscallWrite(msg test.Message) error {
   332  	p := pb.Write{}
   333  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   334  		return err
   335  	}
   336  	if err := checkContextData(p.ContextData); err != nil {
   337  		return err
   338  	}
   339  	if p.Fd < 0 {
   340  		// Although negative FD is possible, it doesn't happen in the test.
   341  		return fmt.Errorf("write negative FD: %d", p.Fd)
   342  	}
   343  	if p.HasOffset {
   344  		// Workload always uses 10 for write offsets (account for partial writes).
   345  		if lower, upper := int64(10), int64(110); p.Offset < lower && p.Offset > upper {
   346  			return fmt.Errorf("invalid offset, want: [%d, %d], got: %d", lower, upper, p.Offset)
   347  		}
   348  	} else if p.Offset != 0 {
   349  		return fmt.Errorf("offset should be 0: %+v", &p)
   350  	}
   351  	if p.Flags != 0 && p.Flags != unix.RWF_HIPRI {
   352  		return fmt.Errorf("invalid flag value, want: 0 || RWF_HIPRI, got: %+x", p.Flags)
   353  	}
   354  	return nil
   355  }
   356  
   357  func checkSentryClone(msg test.Message) error {
   358  	p := pb.CloneInfo{}
   359  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   360  		return err
   361  	}
   362  	if err := checkContextData(p.ContextData); err != nil {
   363  		return err
   364  	}
   365  	if p.CreatedThreadId < 0 {
   366  		return fmt.Errorf("invalid TID: %d", p.CreatedThreadId)
   367  	}
   368  	if p.CreatedThreadGroupId < 0 {
   369  		return fmt.Errorf("invalid TGID: %d", p.CreatedThreadGroupId)
   370  	}
   371  	if p.CreatedThreadStartTimeNs < 0 {
   372  		return fmt.Errorf("invalid TID: %d", p.CreatedThreadId)
   373  	}
   374  	return checkTimeNs(p.CreatedThreadStartTimeNs)
   375  }
   376  
   377  func checkSentryExec(msg test.Message) error {
   378  	p := pb.ExecveInfo{}
   379  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   380  		return err
   381  	}
   382  	if err := checkContextData(p.ContextData); err != nil {
   383  		return err
   384  	}
   385  	// As test runs locally the binary path may resolve to a symlink so would not be exactly same
   386  	// as the pathname passed.
   387  	if want := "/bin/true"; !strings.Contains(p.BinaryPath, want) {
   388  		return fmt.Errorf("wrong BinaryPath, want: %q, got: %q", want, p.BinaryPath)
   389  	}
   390  	if len(p.Argv) == 0 {
   391  		return fmt.Errorf("empty Argv")
   392  	}
   393  	if !strings.Contains(p.BinaryPath, p.Argv[0]) {
   394  		return fmt.Errorf("wrong Argv[0], want: %q, got: %q", p.BinaryPath, p.Argv[0])
   395  	}
   396  	if len(p.Env) == 0 {
   397  		return fmt.Errorf("empty Env")
   398  	}
   399  	if want := "TEST=123"; want != p.Env[0] {
   400  		return fmt.Errorf("wrong Env[0], want: %q, got: %q", want, p.Env[0])
   401  	}
   402  	if (p.BinaryMode & 0111) == 0 {
   403  		return fmt.Errorf("executing non-executable file, mode: %#o (%#x)", p.BinaryMode, p.BinaryMode)
   404  	}
   405  	const nobody = 65534
   406  	if p.BinaryUid != nobody {
   407  		return fmt.Errorf("BinaryUid, want: %d, got: %d", nobody, p.BinaryUid)
   408  	}
   409  	if p.BinaryGid != nobody {
   410  		return fmt.Errorf("BinaryGid, want: %d, got: %d", nobody, p.BinaryGid)
   411  	}
   412  	return nil
   413  }
   414  
   415  func checkSyscallExecve(msg test.Message) error {
   416  	p := pb.Execve{}
   417  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   418  		return err
   419  	}
   420  	if err := checkContextData(p.ContextData); err != nil {
   421  		return err
   422  	}
   423  	if p.Fd < 3 {
   424  		return fmt.Errorf("execve invalid FD: %d", p.Fd)
   425  	}
   426  	if want := "/"; want != p.FdPath {
   427  		return fmt.Errorf("wrong FdPath, want: %q, got: %q", want, p.FdPath)
   428  	}
   429  	if want := "/bin/true"; want != p.Pathname {
   430  		return fmt.Errorf("wrong Pathname, want: %q, got: %q", want, p.Pathname)
   431  	}
   432  	if len(p.Argv) == 0 {
   433  		return fmt.Errorf("empty Argv")
   434  	}
   435  	if p.Argv[0] != p.Pathname {
   436  		return fmt.Errorf("wrong Argv[0], want: %q, got: %q", p.Pathname, p.Argv[0])
   437  	}
   438  	if len(p.Envv) == 0 {
   439  		return fmt.Errorf("empty Envv")
   440  	}
   441  	if want := "TEST=123"; want != p.Envv[0] {
   442  		return fmt.Errorf("wrong Envv[0], want: %q, got: %q", want, p.Envv[0])
   443  	}
   444  	return nil
   445  }
   446  
   447  func checkSentryExitNotifyParent(msg test.Message) error {
   448  	p := pb.ExitNotifyParentInfo{}
   449  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   450  		return err
   451  	}
   452  	// cwd is empty because the task has already been destroyed when the point
   453  	// fires.
   454  	opts := contextDataOpts{skipCwd: true}
   455  	if err := checkContextDataOpts(p.ContextData, opts); err != nil {
   456  		return err
   457  	}
   458  	if p.ExitStatus != 0 {
   459  		return fmt.Errorf("wrong ExitStatus, want: 0, got: %d", p.ExitStatus)
   460  	}
   461  	return nil
   462  }
   463  
   464  func checkSyscallConnect(msg test.Message) error {
   465  	p := pb.Connect{}
   466  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   467  		return err
   468  	}
   469  	if err := checkContextData(p.ContextData); err != nil {
   470  		return err
   471  	}
   472  	if p.Fd < 3 {
   473  		return fmt.Errorf("invalid FD: %d", p.Fd)
   474  	}
   475  	if want := "socket:"; !strings.HasPrefix(p.FdPath, want) {
   476  		return fmt.Errorf("FdPath should start with %q, got: %q", want, p.FdPath)
   477  	}
   478  	if len(p.Address) == 0 {
   479  		return fmt.Errorf("empty address: %q", string(p.Address))
   480  	}
   481  
   482  	return nil
   483  }
   484  
   485  func checkSyscallSocket(msg test.Message) error {
   486  	p := pb.Socket{}
   487  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   488  		return err
   489  	}
   490  	if err := checkContextData(p.ContextData); err != nil {
   491  		return err
   492  	}
   493  	if want := unix.AF_UNIX; int32(want) != p.Domain {
   494  		return fmt.Errorf("wrong Domain, want: %v, got: %v", want, p.Domain)
   495  	}
   496  	if want := unix.SOCK_STREAM; int32(want) != p.Type {
   497  		return fmt.Errorf("wrong Type, want: %v, got: %v", want, p.Type)
   498  	}
   499  	if want := int32(0); want != p.Protocol {
   500  		return fmt.Errorf("wrong Protocol, want: %v, got: %v", want, p.Protocol)
   501  	}
   502  
   503  	return nil
   504  }
   505  
   506  func checkSyscallSetid(msg test.Message) error {
   507  	p := pb.Setid{}
   508  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   509  		return err
   510  	}
   511  	if err := checkContextData(p.ContextData); err != nil {
   512  		return err
   513  	}
   514  	if p.Id != 0 {
   515  		return fmt.Errorf("invalid id: %d", p.Id)
   516  	}
   517  
   518  	return nil
   519  }
   520  
   521  func checkSyscallSetresid(msg test.Message) error {
   522  	p := pb.Setresid{}
   523  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   524  		return err
   525  	}
   526  	if err := checkContextData(p.ContextData); err != nil {
   527  		return err
   528  	}
   529  	if p.GetRid() != 0 {
   530  		return fmt.Errorf("invalid rid: %d", p.Rid)
   531  	}
   532  	if p.GetEid() != 0 {
   533  		return fmt.Errorf("invalid eid: %d", p.Eid)
   534  	}
   535  	if p.GetSid() != 0 {
   536  		return fmt.Errorf("invalid sid: %d", p.Sid)
   537  	}
   538  
   539  	return nil
   540  }
   541  
   542  func checkSyscallChdir(msg test.Message) error {
   543  	p := pb.Chdir{}
   544  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   545  		return err
   546  	}
   547  	if err := checkContextData(p.ContextData); err != nil {
   548  		return err
   549  	}
   550  	if p.Fd < 3 && p.Fd != unix.AT_FDCWD { // Constant used for all file-related syscalls.
   551  		return fmt.Errorf("invalid FD: %d", p.Fd)
   552  	}
   553  	if want := "trace_test.abc"; !strings.Contains(p.Pathname, want) {
   554  		return fmt.Errorf("wrong Pathname, got: %q, want: %q", p.Pathname, want)
   555  	}
   556  
   557  	return nil
   558  }
   559  
   560  func checkSyscallDup(msg test.Message) error {
   561  	p := pb.Dup{}
   562  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   563  		return err
   564  	}
   565  	if err := checkContextData(p.ContextData); err != nil {
   566  		return err
   567  	}
   568  	if p.OldFd < 0 {
   569  		return fmt.Errorf("invalid fd: %d", p.OldFd)
   570  	}
   571  	if p.NewFd < 0 {
   572  		return fmt.Errorf("invalid fd: %d", p.NewFd)
   573  	}
   574  	if p.Flags != unix.O_CLOEXEC && p.Flags != 0 {
   575  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   576  	}
   577  
   578  	return nil
   579  }
   580  
   581  func checkSyscallPrlimit64(msg test.Message) error {
   582  	p := pb.Prlimit{}
   583  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   584  		return err
   585  	}
   586  	if err := checkContextData(p.ContextData); err != nil {
   587  		return err
   588  	}
   589  	if p.Pid < 0 {
   590  		return fmt.Errorf("invalid pid: %d", p.Pid)
   591  	}
   592  	return nil
   593  }
   594  
   595  func checkSyscallEventfd(msg test.Message) error {
   596  	p := pb.Eventfd{}
   597  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   598  		return err
   599  	}
   600  	if err := checkContextData(p.ContextData); err != nil {
   601  		return err
   602  	}
   603  	if p.Val < 0 {
   604  		return fmt.Errorf("invalid pid: %d", p.Val)
   605  	}
   606  	if p.Flags != unix.EFD_NONBLOCK && p.Flags != 0 {
   607  		return fmt.Errorf("invalid flag got: %d, ", p.Flags)
   608  	}
   609  
   610  	return nil
   611  }
   612  
   613  func checkSyscallBind(msg test.Message) error {
   614  	p := pb.Bind{}
   615  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   616  		return err
   617  	}
   618  	if err := checkContextData(p.ContextData); err != nil {
   619  		return err
   620  	}
   621  	if p.Fd < 0 {
   622  		return fmt.Errorf("invalid fd: %d", p.Fd)
   623  	}
   624  	if p.FdPath == " " {
   625  		return fmt.Errorf("invalid path: %v", p.FdPath)
   626  	}
   627  	if len(p.Address) == 0 {
   628  		return fmt.Errorf("invalid address: %d", p.Address)
   629  	}
   630  	return nil
   631  }
   632  
   633  func checkSyscallAccept(msg test.Message) error {
   634  	p := pb.Accept{}
   635  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   636  		return err
   637  	}
   638  	if err := checkContextData(p.ContextData); err != nil {
   639  		return err
   640  	}
   641  	if p.Fd < 0 {
   642  		return fmt.Errorf("invalid fd: %d", p.Fd)
   643  	}
   644  	if p.FdPath == "" {
   645  		return fmt.Errorf("invalid path: %v", p.FdPath)
   646  	}
   647  	if len(p.Address) != 0 {
   648  		return fmt.Errorf("invalid address: %d, %v", p.Address, p.Sysno)
   649  	}
   650  	if p.Flags != 0 && p.Flags != unix.SOCK_CLOEXEC {
   651  		return fmt.Errorf("invalid flag got: %d", p.Flags)
   652  	}
   653  	return nil
   654  }
   655  
   656  func checkSyscallChroot(msg test.Message) error {
   657  	p := pb.Chroot{}
   658  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   659  		return err
   660  	}
   661  	if err := checkContextData(p.ContextData); err != nil {
   662  		return err
   663  	}
   664  	if want := "trace_test.abc"; !strings.Contains(p.Pathname, want) {
   665  		return fmt.Errorf("wrong pathname, want: %q, got: %q", want, p.Pathname)
   666  	}
   667  
   668  	return nil
   669  }
   670  
   671  func checkSyscallFcntl(msg test.Message) error {
   672  	p := pb.Fcntl{}
   673  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   674  		return err
   675  	}
   676  	if err := checkContextData(p.ContextData); err != nil {
   677  		return err
   678  	}
   679  	if p.Fd < 0 {
   680  		return fmt.Errorf("invalid fd: %d", p.Fd)
   681  	}
   682  	if p.Cmd != unix.F_GETFL {
   683  		return fmt.Errorf("invalid cmd:  got: %v, want: F_GETFL", p.Cmd)
   684  	}
   685  	return nil
   686  }
   687  
   688  func checkSyscallPipe(msg test.Message) error {
   689  	p := pb.Pipe{}
   690  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   691  		return err
   692  	}
   693  	if err := checkContextData(p.ContextData); err != nil {
   694  		return err
   695  	}
   696  	if p.Reader < 0 {
   697  		return fmt.Errorf("invalid reader fd: %d", p.Reader)
   698  	}
   699  	if p.Writer < 0 {
   700  		return fmt.Errorf("invalid writer fd: %d", p.Writer)
   701  	}
   702  	if p.Flags != unix.O_CLOEXEC && p.Flags != 0 {
   703  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   704  	}
   705  	return nil
   706  }
   707  
   708  func checkSyscallSignalfd(msg test.Message) error {
   709  	p := pb.Signalfd{}
   710  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   711  		return err
   712  	}
   713  	if err := checkContextData(p.ContextData); err != nil {
   714  		return err
   715  	}
   716  	if p.Fd != -1 {
   717  		return fmt.Errorf("invalid fd: %d", p.Fd)
   718  	}
   719  	if p.Sigset != 0 && p.Sigset != uint64(unix.SIGILL) {
   720  		return fmt.Errorf("invalid signal got: %v", p.Sigset)
   721  	}
   722  	return checkSyscallSignalfdFlags(p.Flags)
   723  }
   724  
   725  func checkSyscallTimerfdCreate(msg test.Message) error {
   726  	p := pb.TimerfdCreate{}
   727  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   728  		return err
   729  	}
   730  	if err := checkContextData(p.ContextData); err != nil {
   731  		return err
   732  	}
   733  	if p.ClockId != unix.CLOCK_REALTIME {
   734  		return fmt.Errorf("invalid clockid: %d", p.ClockId)
   735  	}
   736  	if p.Flags != 0 {
   737  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   738  	}
   739  	return nil
   740  }
   741  
   742  func checkSyscallTimerfdSettime(msg test.Message) error {
   743  	p := pb.TimerfdSetTime{}
   744  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   745  		return err
   746  	}
   747  	if err := checkContextData(p.ContextData); err != nil {
   748  		return err
   749  	}
   750  	if p.Fd < 0 {
   751  		return fmt.Errorf("invalid clockid: %d", p.Fd)
   752  	}
   753  	if p.FdPath == "" {
   754  		return fmt.Errorf("invalid path: %q", p.FdPath)
   755  	}
   756  	if p.Flags != unix.TFD_TIMER_ABSTIME {
   757  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   758  	}
   759  	if p.OldValue != nil {
   760  		return fmt.Errorf("invalid oldvalue: %v", p.OldValue.String())
   761  	}
   762  	if p.NewValue == nil {
   763  		return fmt.Errorf("invalid oldvalue: %v", p.OldValue.String())
   764  	}
   765  	return nil
   766  }
   767  
   768  func checkSyscallTimerfdGettime(msg test.Message) error {
   769  	p := pb.TimerfdGetTime{}
   770  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   771  		return err
   772  	}
   773  	if err := checkContextData(p.ContextData); err != nil {
   774  		return err
   775  	}
   776  	if p.Fd < 0 {
   777  		return fmt.Errorf("invalid clockid: %d", p.Fd)
   778  	}
   779  	if p.FdPath == "" {
   780  		return fmt.Errorf("invalid path: %q", p.FdPath)
   781  	}
   782  	if p.CurValue == nil {
   783  		return fmt.Errorf("invalid oldvalue: %v", p.CurValue.String())
   784  	}
   785  	return nil
   786  }
   787  
   788  func checkSyscallClone(msg test.Message) error {
   789  	p := pb.Clone{}
   790  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   791  		return err
   792  	}
   793  	if err := checkContextData(p.ContextData); err != nil {
   794  		return err
   795  	}
   796  	// Flags used by default in system calls that use clone(2) in the underying.
   797  	rawFlags := unix.CLONE_CHILD_CLEARTID | unix.CLONE_CHILD_SETTID | uint64(unix.SIGCHLD)
   798  	// Flags used for clone(2) syscall in workload.cc
   799  	cloneFlags := uint64(unix.SIGCHLD) | unix.CLONE_VFORK | unix.CLONE_FILES
   800  	if p.Flags != uint64(rawFlags) && p.Flags != cloneFlags {
   801  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   802  	}
   803  	if (p.Flags == uint64(rawFlags) && p.Stack != 0) || (p.Flags == cloneFlags && p.Stack == 0) {
   804  		return fmt.Errorf("invalid stack got: %v", p.Stack)
   805  	}
   806  	return nil
   807  }
   808  
   809  func checkSyscallInotifyInit(msg test.Message) error {
   810  	p := pb.InotifyInit{}
   811  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   812  		return err
   813  	}
   814  	if err := checkContextData(p.ContextData); err != nil {
   815  		return err
   816  	}
   817  	if !(p.Flags == 0 || p.Flags == unix.IN_NONBLOCK) {
   818  		return fmt.Errorf("invalid flag got: %v", p.Flags)
   819  	}
   820  	return nil
   821  }
   822  
   823  func checkSyscallInotifyInitAddWatch(msg test.Message) error {
   824  	p := pb.InotifyAddWatch{}
   825  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   826  		return err
   827  	}
   828  	if err := checkContextData(p.ContextData); err != nil {
   829  		return err
   830  	}
   831  	if p.Fd < 0 {
   832  		return fmt.Errorf("invalid fd: %d", p.Fd)
   833  	}
   834  	if p.FdPath == "" {
   835  		return fmt.Errorf("invalid path: %v", p.FdPath)
   836  	}
   837  	if want := "timer_trace_test.abc"; !strings.Contains(p.Pathname, want) {
   838  		return fmt.Errorf("wrong pathname, got: %q, want: %q", p.Pathname, want)
   839  	}
   840  	if want := unix.IN_NONBLOCK; want != int(p.Mask) {
   841  		return fmt.Errorf("invalid mask: want: %v, got:%v", want, p.Mask)
   842  	}
   843  	return nil
   844  }
   845  
   846  func checkSyscallInotifyInitRmWatch(msg test.Message) error {
   847  	p := pb.InotifyRmWatch{}
   848  	if err := proto.Unmarshal(msg.Msg, &p); err != nil {
   849  		return err
   850  	}
   851  	if err := checkContextData(p.ContextData); err != nil {
   852  		return err
   853  	}
   854  	if p.Fd < 0 {
   855  		return fmt.Errorf("invalid fd: %d", p.Fd)
   856  	}
   857  	if p.FdPath == "" {
   858  		return fmt.Errorf("invalid path: %q", p.FdPath)
   859  	}
   860  	if p.Wd < 0 {
   861  		return fmt.Errorf("invalid wd: %d", p.Wd)
   862  	}
   863  	return nil
   864  }