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 }