diff options
Diffstat (limited to 'pkg/sentry/strace')
-rw-r--r-- | pkg/sentry/strace/capability.go | 176 | ||||
-rw-r--r-- | pkg/sentry/strace/clone.go | 113 | ||||
-rw-r--r-- | pkg/sentry/strace/futex.go | 52 | ||||
-rw-r--r-- | pkg/sentry/strace/linux64.go | 338 | ||||
-rw-r--r-- | pkg/sentry/strace/open.go | 96 | ||||
-rw-r--r-- | pkg/sentry/strace/poll.go | 72 | ||||
-rw-r--r-- | pkg/sentry/strace/ptrace.go | 62 | ||||
-rw-r--r-- | pkg/sentry/strace/signal.go | 148 | ||||
-rw-r--r-- | pkg/sentry/strace/socket.go | 412 | ||||
-rw-r--r-- | pkg/sentry/strace/strace.go | 820 | ||||
-rwxr-xr-x | pkg/sentry/strace/strace_go_proto/strace.pb.go | 247 | ||||
-rwxr-xr-x | pkg/sentry/strace/strace_state_autogen.go | 4 | ||||
-rw-r--r-- | pkg/sentry/strace/syscalls.go | 267 |
13 files changed, 2807 insertions, 0 deletions
diff --git a/pkg/sentry/strace/capability.go b/pkg/sentry/strace/capability.go new file mode 100644 index 000000000..f85d6636e --- /dev/null +++ b/pkg/sentry/strace/capability.go @@ -0,0 +1,176 @@ +// Copyright 2019 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. + +package strace + +import ( + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" +) + +// CapabilityBitset is the set of capabilties in a bitset. +var CapabilityBitset = abi.FlagSet{ + { + Flag: 1 << uint32(linux.CAP_CHOWN), + Name: "CAP_CHOWN", + }, + { + Flag: 1 << uint32(linux.CAP_DAC_OVERRIDE), + Name: "CAP_DAC_OVERRIDE", + }, + { + Flag: 1 << uint32(linux.CAP_DAC_READ_SEARCH), + Name: "CAP_DAC_READ_SEARCH", + }, + { + Flag: 1 << uint32(linux.CAP_FOWNER), + Name: "CAP_FOWNER", + }, + { + Flag: 1 << uint32(linux.CAP_FSETID), + Name: "CAP_FSETID", + }, + { + Flag: 1 << uint32(linux.CAP_KILL), + Name: "CAP_KILL", + }, + { + Flag: 1 << uint32(linux.CAP_SETGID), + Name: "CAP_SETGID", + }, + { + Flag: 1 << uint32(linux.CAP_SETUID), + Name: "CAP_SETUID", + }, + { + Flag: 1 << uint32(linux.CAP_SETPCAP), + Name: "CAP_SETPCAP", + }, + { + Flag: 1 << uint32(linux.CAP_LINUX_IMMUTABLE), + Name: "CAP_LINUX_IMMUTABLE", + }, + { + Flag: 1 << uint32(linux.CAP_NET_BIND_SERVICE), + Name: "CAP_NET_BIND_SERVICE", + }, + { + Flag: 1 << uint32(linux.CAP_NET_BROADCAST), + Name: "CAP_NET_BROADCAST", + }, + { + Flag: 1 << uint32(linux.CAP_NET_ADMIN), + Name: "CAP_NET_ADMIN", + }, + { + Flag: 1 << uint32(linux.CAP_NET_RAW), + Name: "CAP_NET_RAW", + }, + { + Flag: 1 << uint32(linux.CAP_IPC_LOCK), + Name: "CAP_IPC_LOCK", + }, + { + Flag: 1 << uint32(linux.CAP_IPC_OWNER), + Name: "CAP_IPC_OWNER", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_MODULE), + Name: "CAP_SYS_MODULE", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_RAWIO), + Name: "CAP_SYS_RAWIO", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_CHROOT), + Name: "CAP_SYS_CHROOT", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_PTRACE), + Name: "CAP_SYS_PTRACE", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_PACCT), + Name: "CAP_SYS_PACCT", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_ADMIN), + Name: "CAP_SYS_ADMIN", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_BOOT), + Name: "CAP_SYS_BOOT", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_NICE), + Name: "CAP_SYS_NICE", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_RESOURCE), + Name: "CAP_SYS_RESOURCE", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_TIME), + Name: "CAP_SYS_TIME", + }, + { + Flag: 1 << uint32(linux.CAP_SYS_TTY_CONFIG), + Name: "CAP_SYS_TTY_CONFIG", + }, + { + Flag: 1 << uint32(linux.CAP_MKNOD), + Name: "CAP_MKNOD", + }, + { + Flag: 1 << uint32(linux.CAP_LEASE), + Name: "CAP_LEASE", + }, + { + Flag: 1 << uint32(linux.CAP_AUDIT_WRITE), + Name: "CAP_AUDIT_WRITE", + }, + { + Flag: 1 << uint32(linux.CAP_AUDIT_CONTROL), + Name: "CAP_AUDIT_CONTROL", + }, + { + Flag: 1 << uint32(linux.CAP_SETFCAP), + Name: "CAP_SETFCAP", + }, + { + Flag: 1 << uint32(linux.CAP_MAC_OVERRIDE), + Name: "CAP_MAC_OVERRIDE", + }, + { + Flag: 1 << uint32(linux.CAP_MAC_ADMIN), + Name: "CAP_MAC_ADMIN", + }, + { + Flag: 1 << uint32(linux.CAP_SYSLOG), + Name: "CAP_SYSLOG", + }, + { + Flag: 1 << uint32(linux.CAP_WAKE_ALARM), + Name: "CAP_WAKE_ALARM", + }, + { + Flag: 1 << uint32(linux.CAP_BLOCK_SUSPEND), + Name: "CAP_BLOCK_SUSPEND", + }, + { + Flag: 1 << uint32(linux.CAP_AUDIT_READ), + Name: "CAP_AUDIT_READ", + }, +} diff --git a/pkg/sentry/strace/clone.go b/pkg/sentry/strace/clone.go new file mode 100644 index 000000000..ff6a432c6 --- /dev/null +++ b/pkg/sentry/strace/clone.go @@ -0,0 +1,113 @@ +// Copyright 2018 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. + +package strace + +import ( + "syscall" + + "gvisor.googlesource.com/gvisor/pkg/abi" +) + +// CloneFlagSet is the set of clone(2) flags. +var CloneFlagSet = abi.FlagSet{ + { + Flag: syscall.CLONE_VM, + Name: "CLONE_VM", + }, + { + Flag: syscall.CLONE_FS, + Name: "CLONE_FS", + }, + { + Flag: syscall.CLONE_FILES, + Name: "CLONE_FILES", + }, + { + Flag: syscall.CLONE_SIGHAND, + Name: "CLONE_SIGHAND", + }, + { + Flag: syscall.CLONE_PTRACE, + Name: "CLONE_PTRACE", + }, + { + Flag: syscall.CLONE_VFORK, + Name: "CLONE_VFORK", + }, + { + Flag: syscall.CLONE_PARENT, + Name: "CLONE_PARENT", + }, + { + Flag: syscall.CLONE_THREAD, + Name: "CLONE_THREAD", + }, + { + Flag: syscall.CLONE_NEWNS, + Name: "CLONE_NEWNS", + }, + { + Flag: syscall.CLONE_SYSVSEM, + Name: "CLONE_SYSVSEM", + }, + { + Flag: syscall.CLONE_SETTLS, + Name: "CLONE_SETTLS", + }, + { + Flag: syscall.CLONE_PARENT_SETTID, + Name: "CLONE_PARENT_SETTID", + }, + { + Flag: syscall.CLONE_CHILD_CLEARTID, + Name: "CLONE_CHILD_CLEARTID", + }, + { + Flag: syscall.CLONE_DETACHED, + Name: "CLONE_DETACHED", + }, + { + Flag: syscall.CLONE_UNTRACED, + Name: "CLONE_UNTRACED", + }, + { + Flag: syscall.CLONE_CHILD_SETTID, + Name: "CLONE_CHILD_SETTID", + }, + { + Flag: syscall.CLONE_NEWUTS, + Name: "CLONE_NEWUTS", + }, + { + Flag: syscall.CLONE_NEWIPC, + Name: "CLONE_NEWIPC", + }, + { + Flag: syscall.CLONE_NEWUSER, + Name: "CLONE_NEWUSER", + }, + { + Flag: syscall.CLONE_NEWPID, + Name: "CLONE_NEWPID", + }, + { + Flag: syscall.CLONE_NEWNET, + Name: "CLONE_NEWNET", + }, + { + Flag: syscall.CLONE_IO, + Name: "CLONE_IO", + }, +} diff --git a/pkg/sentry/strace/futex.go b/pkg/sentry/strace/futex.go new file mode 100644 index 000000000..24301bda6 --- /dev/null +++ b/pkg/sentry/strace/futex.go @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +package strace + +import ( + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" +) + +// FutexCmd are the possible futex(2) commands. +var FutexCmd = abi.ValueSet{ + linux.FUTEX_WAIT: "FUTEX_WAIT", + linux.FUTEX_WAKE: "FUTEX_WAKE", + linux.FUTEX_FD: "FUTEX_FD", + linux.FUTEX_REQUEUE: "FUTEX_REQUEUE", + linux.FUTEX_CMP_REQUEUE: "FUTEX_CMP_REQUEUE", + linux.FUTEX_WAKE_OP: "FUTEX_WAKE_OP", + linux.FUTEX_LOCK_PI: "FUTEX_LOCK_PI", + linux.FUTEX_UNLOCK_PI: "FUTEX_UNLOCK_PI", + linux.FUTEX_TRYLOCK_PI: "FUTEX_TRYLOCK_PI", + linux.FUTEX_WAIT_BITSET: "FUTEX_WAIT_BITSET", + linux.FUTEX_WAKE_BITSET: "FUTEX_WAKE_BITSET", + linux.FUTEX_WAIT_REQUEUE_PI: "FUTEX_WAIT_REQUEUE_PI", + linux.FUTEX_CMP_REQUEUE_PI: "FUTEX_CMP_REQUEUE_PI", +} + +func futex(op uint64) string { + cmd := op &^ (linux.FUTEX_PRIVATE_FLAG | linux.FUTEX_CLOCK_REALTIME) + clockRealtime := (op & linux.FUTEX_CLOCK_REALTIME) == linux.FUTEX_CLOCK_REALTIME + private := (op & linux.FUTEX_PRIVATE_FLAG) == linux.FUTEX_PRIVATE_FLAG + + s := FutexCmd.Parse(cmd) + if clockRealtime { + s += "|FUTEX_CLOCK_REALTIME" + } + if private { + s += "|FUTEX_PRIVATE_FLAG" + } + return s +} diff --git a/pkg/sentry/strace/linux64.go b/pkg/sentry/strace/linux64.go new file mode 100644 index 000000000..3650fd6e1 --- /dev/null +++ b/pkg/sentry/strace/linux64.go @@ -0,0 +1,338 @@ +// Copyright 2018 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. + +package strace + +// linuxAMD64 provides a mapping of the Linux amd64 syscalls and their argument +// types for display / formatting. +var linuxAMD64 = SyscallMap{ + 0: makeSyscallInfo("read", FD, ReadBuffer, Hex), + 1: makeSyscallInfo("write", FD, WriteBuffer, Hex), + 2: makeSyscallInfo("open", Path, OpenFlags, Mode), + 3: makeSyscallInfo("close", FD), + 4: makeSyscallInfo("stat", Path, Stat), + 5: makeSyscallInfo("fstat", FD, Stat), + 6: makeSyscallInfo("lstat", Path, Stat), + 7: makeSyscallInfo("poll", PollFDs, Hex, Hex), + 8: makeSyscallInfo("lseek", Hex, Hex, Hex), + 9: makeSyscallInfo("mmap", Hex, Hex, Hex, Hex, FD, Hex), + 10: makeSyscallInfo("mprotect", Hex, Hex, Hex), + 11: makeSyscallInfo("munmap", Hex, Hex), + 12: makeSyscallInfo("brk", Hex), + 13: makeSyscallInfo("rt_sigaction", Signal, SigAction, PostSigAction), + 14: makeSyscallInfo("rt_sigprocmask", SignalMaskAction, SigSet, PostSigSet, Hex), + 15: makeSyscallInfo("rt_sigreturn"), + 16: makeSyscallInfo("ioctl", FD, Hex, Hex), + 17: makeSyscallInfo("pread64", FD, ReadBuffer, Hex, Hex), + 18: makeSyscallInfo("pwrite64", FD, WriteBuffer, Hex, Hex), + 19: makeSyscallInfo("readv", FD, ReadIOVec, Hex), + 20: makeSyscallInfo("writev", FD, WriteIOVec, Hex), + 21: makeSyscallInfo("access", Path, Oct), + 22: makeSyscallInfo("pipe", PipeFDs), + 23: makeSyscallInfo("select", Hex, Hex, Hex, Hex, Timeval), + 24: makeSyscallInfo("sched_yield"), + 25: makeSyscallInfo("mremap", Hex, Hex, Hex, Hex, Hex), + 26: makeSyscallInfo("msync", Hex, Hex, Hex), + 27: makeSyscallInfo("mincore", Hex, Hex, Hex), + 28: makeSyscallInfo("madvise", Hex, Hex, Hex), + 29: makeSyscallInfo("shmget", Hex, Hex, Hex), + 30: makeSyscallInfo("shmat", Hex, Hex, Hex), + 31: makeSyscallInfo("shmctl", Hex, Hex, Hex), + 32: makeSyscallInfo("dup", FD), + 33: makeSyscallInfo("dup2", FD, FD), + 34: makeSyscallInfo("pause"), + 35: makeSyscallInfo("nanosleep", Timespec, PostTimespec), + 36: makeSyscallInfo("getitimer", ItimerType, PostItimerVal), + 37: makeSyscallInfo("alarm", Hex), + 38: makeSyscallInfo("setitimer", ItimerType, ItimerVal, PostItimerVal), + 39: makeSyscallInfo("getpid"), + 40: makeSyscallInfo("sendfile", FD, FD, Hex, Hex), + 41: makeSyscallInfo("socket", SockFamily, SockType, SockProtocol), + 42: makeSyscallInfo("connect", FD, SockAddr, Hex), + 43: makeSyscallInfo("accept", FD, PostSockAddr, SockLen), + 44: makeSyscallInfo("sendto", FD, Hex, Hex, Hex, SockAddr, Hex), + 45: makeSyscallInfo("recvfrom", FD, Hex, Hex, Hex, PostSockAddr, SockLen), + 46: makeSyscallInfo("sendmsg", FD, SendMsgHdr, Hex), + 47: makeSyscallInfo("recvmsg", FD, RecvMsgHdr, Hex), + 48: makeSyscallInfo("shutdown", FD, Hex), + 49: makeSyscallInfo("bind", FD, SockAddr, Hex), + 50: makeSyscallInfo("listen", FD, Hex), + 51: makeSyscallInfo("getsockname", FD, PostSockAddr, SockLen), + 52: makeSyscallInfo("getpeername", FD, PostSockAddr, SockLen), + 53: makeSyscallInfo("socketpair", SockFamily, SockType, SockProtocol, Hex), + 54: makeSyscallInfo("setsockopt", FD, Hex, Hex, Hex, Hex), + 55: makeSyscallInfo("getsockopt", FD, Hex, Hex, Hex, Hex), + 56: makeSyscallInfo("clone", CloneFlags, Hex, Hex, Hex, Hex), + 57: makeSyscallInfo("fork"), + 58: makeSyscallInfo("vfork"), + 59: makeSyscallInfo("execve", Path, ExecveStringVector, ExecveStringVector), + 60: makeSyscallInfo("exit", Hex), + 61: makeSyscallInfo("wait4", Hex, Hex, Hex, Rusage), + 62: makeSyscallInfo("kill", Hex, Signal), + 63: makeSyscallInfo("uname", Uname), + 64: makeSyscallInfo("semget", Hex, Hex, Hex), + 65: makeSyscallInfo("semop", Hex, Hex, Hex), + 66: makeSyscallInfo("semctl", Hex, Hex, Hex, Hex), + 67: makeSyscallInfo("shmdt", Hex), + 68: makeSyscallInfo("msgget", Hex, Hex), + 69: makeSyscallInfo("msgsnd", Hex, Hex, Hex, Hex), + 70: makeSyscallInfo("msgrcv", Hex, Hex, Hex, Hex, Hex), + 71: makeSyscallInfo("msgctl", Hex, Hex, Hex), + 72: makeSyscallInfo("fcntl", FD, Hex, Hex), + 73: makeSyscallInfo("flock", FD, Hex), + 74: makeSyscallInfo("fsync", FD), + 75: makeSyscallInfo("fdatasync", FD), + 76: makeSyscallInfo("truncate", Path, Hex), + 77: makeSyscallInfo("ftruncate", FD, Hex), + 78: makeSyscallInfo("getdents", FD, Hex, Hex), + 79: makeSyscallInfo("getcwd", PostPath, Hex), + 80: makeSyscallInfo("chdir", Path), + 81: makeSyscallInfo("fchdir", FD), + 82: makeSyscallInfo("rename", Path, Path), + 83: makeSyscallInfo("mkdir", Path, Oct), + 84: makeSyscallInfo("rmdir", Path), + 85: makeSyscallInfo("creat", Path, Oct), + 86: makeSyscallInfo("link", Path, Path), + 87: makeSyscallInfo("unlink", Path), + 88: makeSyscallInfo("symlink", Path, Path), + 89: makeSyscallInfo("readlink", Path, ReadBuffer, Hex), + 90: makeSyscallInfo("chmod", Path, Mode), + 91: makeSyscallInfo("fchmod", FD, Mode), + 92: makeSyscallInfo("chown", Path, Hex, Hex), + 93: makeSyscallInfo("fchown", FD, Hex, Hex), + 94: makeSyscallInfo("lchown", Path, Hex, Hex), + 95: makeSyscallInfo("umask", Hex), + 96: makeSyscallInfo("gettimeofday", Timeval, Hex), + 97: makeSyscallInfo("getrlimit", Hex, Hex), + 98: makeSyscallInfo("getrusage", Hex, Rusage), + 99: makeSyscallInfo("sysinfo", Hex), + 100: makeSyscallInfo("times", Hex), + 101: makeSyscallInfo("ptrace", PtraceRequest, Hex, Hex, Hex), + 102: makeSyscallInfo("getuid"), + 103: makeSyscallInfo("syslog", Hex, Hex, Hex), + 104: makeSyscallInfo("getgid"), + 105: makeSyscallInfo("setuid", Hex), + 106: makeSyscallInfo("setgid", Hex), + 107: makeSyscallInfo("geteuid"), + 108: makeSyscallInfo("getegid"), + 109: makeSyscallInfo("setpgid", Hex, Hex), + 110: makeSyscallInfo("getppid"), + 111: makeSyscallInfo("getpgrp"), + 112: makeSyscallInfo("setsid"), + 113: makeSyscallInfo("setreuid", Hex, Hex), + 114: makeSyscallInfo("setregid", Hex, Hex), + 115: makeSyscallInfo("getgroups", Hex, Hex), + 116: makeSyscallInfo("setgroups", Hex, Hex), + 117: makeSyscallInfo("setresuid", Hex, Hex, Hex), + 118: makeSyscallInfo("getresuid", Hex, Hex, Hex), + 119: makeSyscallInfo("setresgid", Hex, Hex, Hex), + 120: makeSyscallInfo("getresgid", Hex, Hex, Hex), + 121: makeSyscallInfo("getpgid", Hex), + 122: makeSyscallInfo("setfsuid", Hex), + 123: makeSyscallInfo("setfsgid", Hex), + 124: makeSyscallInfo("getsid", Hex), + 125: makeSyscallInfo("capget", CapHeader, PostCapData), + 126: makeSyscallInfo("capset", CapHeader, CapData), + 127: makeSyscallInfo("rt_sigpending", Hex), + 128: makeSyscallInfo("rt_sigtimedwait", SigSet, Hex, Timespec, Hex), + 129: makeSyscallInfo("rt_sigqueueinfo", Hex, Signal, Hex), + 130: makeSyscallInfo("rt_sigsuspend", Hex), + 131: makeSyscallInfo("sigaltstack", Hex, Hex), + 132: makeSyscallInfo("utime", Path, Utimbuf), + 133: makeSyscallInfo("mknod", Path, Mode, Hex), + 134: makeSyscallInfo("uselib", Hex), + 135: makeSyscallInfo("personality", Hex), + 136: makeSyscallInfo("ustat", Hex, Hex), + 137: makeSyscallInfo("statfs", Path, Hex), + 138: makeSyscallInfo("fstatfs", FD, Hex), + 139: makeSyscallInfo("sysfs", Hex, Hex, Hex), + 140: makeSyscallInfo("getpriority", Hex, Hex), + 141: makeSyscallInfo("setpriority", Hex, Hex, Hex), + 142: makeSyscallInfo("sched_setparam", Hex, Hex), + 143: makeSyscallInfo("sched_getparam", Hex, Hex), + 144: makeSyscallInfo("sched_setscheduler", Hex, Hex, Hex), + 145: makeSyscallInfo("sched_getscheduler", Hex), + 146: makeSyscallInfo("sched_get_priority_max", Hex), + 147: makeSyscallInfo("sched_get_priority_min", Hex), + 148: makeSyscallInfo("sched_rr_get_interval", Hex, Hex), + 149: makeSyscallInfo("mlock", Hex, Hex), + 150: makeSyscallInfo("munlock", Hex, Hex), + 151: makeSyscallInfo("mlockall", Hex), + 152: makeSyscallInfo("munlockall"), + 153: makeSyscallInfo("vhangup"), + 154: makeSyscallInfo("modify_ldt", Hex, Hex, Hex), + 155: makeSyscallInfo("pivot_root", Path, Path), + 156: makeSyscallInfo("_sysctl", Hex), + 157: makeSyscallInfo("prctl", Hex, Hex, Hex, Hex, Hex), + 158: makeSyscallInfo("arch_prctl", Hex, Hex), + 159: makeSyscallInfo("adjtimex", Hex), + 160: makeSyscallInfo("setrlimit", Hex, Hex), + 161: makeSyscallInfo("chroot", Path), + 162: makeSyscallInfo("sync"), + 163: makeSyscallInfo("acct", Hex), + 164: makeSyscallInfo("settimeofday", Timeval, Hex), + 165: makeSyscallInfo("mount", Path, Path, Path, Hex, Path), + 166: makeSyscallInfo("umount2", Path, Hex), + 167: makeSyscallInfo("swapon", Hex, Hex), + 168: makeSyscallInfo("swapoff", Hex), + 169: makeSyscallInfo("reboot", Hex, Hex, Hex, Hex), + 170: makeSyscallInfo("sethostname", Hex, Hex), + 171: makeSyscallInfo("setdomainname", Hex, Hex), + 172: makeSyscallInfo("iopl", Hex), + 173: makeSyscallInfo("ioperm", Hex, Hex, Hex), + 174: makeSyscallInfo("create_module", Path, Hex), + 175: makeSyscallInfo("init_module", Hex, Hex, Hex), + 176: makeSyscallInfo("delete_module", Hex, Hex), + 177: makeSyscallInfo("get_kernel_syms", Hex), + // 178: query_module (only present in Linux < 2.6) + 179: makeSyscallInfo("quotactl", Hex, Hex, Hex, Hex), + 180: makeSyscallInfo("nfsservctl", Hex, Hex, Hex), + // 181: getpmsg (not implemented in the Linux kernel) + // 182: putpmsg (not implemented in the Linux kernel) + // 183: afs_syscall (not implemented in the Linux kernel) + // 184: tuxcall (not implemented in the Linux kernel) + // 185: security (not implemented in the Linux kernel) + 186: makeSyscallInfo("gettid"), + 187: makeSyscallInfo("readahead", Hex, Hex, Hex), + 188: makeSyscallInfo("setxattr", Path, Path, Hex, Hex, Hex), + 189: makeSyscallInfo("lsetxattr", Path, Path, Hex, Hex, Hex), + 190: makeSyscallInfo("fsetxattr", FD, Path, Hex, Hex, Hex), + 191: makeSyscallInfo("getxattr", Path, Path, Hex, Hex), + 192: makeSyscallInfo("lgetxattr", Path, Path, Hex, Hex), + 193: makeSyscallInfo("fgetxattr", FD, Path, Hex, Hex), + 194: makeSyscallInfo("listxattr", Path, Path, Hex), + 195: makeSyscallInfo("llistxattr", Path, Path, Hex), + 196: makeSyscallInfo("flistxattr", FD, Path, Hex), + 197: makeSyscallInfo("removexattr", Path, Path), + 198: makeSyscallInfo("lremovexattr", Path, Path), + 199: makeSyscallInfo("fremovexattr", FD, Path), + 200: makeSyscallInfo("tkill", Hex, Signal), + 201: makeSyscallInfo("time", Hex), + 202: makeSyscallInfo("futex", Hex, FutexOp, Hex, Timespec, Hex, Hex), + 203: makeSyscallInfo("sched_setaffinity", Hex, Hex, Hex), + 204: makeSyscallInfo("sched_getaffinity", Hex, Hex, Hex), + 205: makeSyscallInfo("set_thread_area", Hex), + 206: makeSyscallInfo("io_setup", Hex, Hex), + 207: makeSyscallInfo("io_destroy", Hex), + 208: makeSyscallInfo("io_getevents", Hex, Hex, Hex, Hex, Timespec), + 209: makeSyscallInfo("io_submit", Hex, Hex, Hex), + 210: makeSyscallInfo("io_cancel", Hex, Hex, Hex), + 211: makeSyscallInfo("get_thread_area", Hex), + 212: makeSyscallInfo("lookup_dcookie", Hex, Hex, Hex), + 213: makeSyscallInfo("epoll_create", Hex), + // 214: epoll_ctl_old (not implemented in the Linux kernel) + // 215: epoll_wait_old (not implemented in the Linux kernel) + 216: makeSyscallInfo("remap_file_pages", Hex, Hex, Hex, Hex, Hex), + 217: makeSyscallInfo("getdents64", FD, Hex, Hex), + 218: makeSyscallInfo("set_tid_address", Hex), + 219: makeSyscallInfo("restart_syscall"), + 220: makeSyscallInfo("semtimedop", Hex, Hex, Hex, Hex), + 221: makeSyscallInfo("fadvise64", FD, Hex, Hex, Hex), + 222: makeSyscallInfo("timer_create", Hex, Hex, Hex), + 223: makeSyscallInfo("timer_settime", Hex, Hex, ItimerSpec, PostItimerSpec), + 224: makeSyscallInfo("timer_gettime", Hex, PostItimerSpec), + 225: makeSyscallInfo("timer_getoverrun", Hex), + 226: makeSyscallInfo("timer_delete", Hex), + 227: makeSyscallInfo("clock_settime", Hex, Timespec), + 228: makeSyscallInfo("clock_gettime", Hex, PostTimespec), + 229: makeSyscallInfo("clock_getres", Hex, PostTimespec), + 230: makeSyscallInfo("clock_nanosleep", Hex, Hex, Timespec, PostTimespec), + 231: makeSyscallInfo("exit_group", Hex), + 232: makeSyscallInfo("epoll_wait", Hex, Hex, Hex, Hex), + 233: makeSyscallInfo("epoll_ctl", Hex, Hex, FD, Hex), + 234: makeSyscallInfo("tgkill", Hex, Hex, Signal), + 235: makeSyscallInfo("utimes", Path, Timeval), + // 236: vserver (not implemented in the Linux kernel) + 237: makeSyscallInfo("mbind", Hex, Hex, Hex, Hex, Hex, Hex), + 238: makeSyscallInfo("set_mempolicy", Hex, Hex, Hex), + 239: makeSyscallInfo("get_mempolicy", Hex, Hex, Hex, Hex, Hex), + 240: makeSyscallInfo("mq_open", Hex, Hex, Hex, Hex), + 241: makeSyscallInfo("mq_unlink", Hex), + 242: makeSyscallInfo("mq_timedsend", Hex, Hex, Hex, Hex, Hex), + 243: makeSyscallInfo("mq_timedreceive", Hex, Hex, Hex, Hex, Hex), + 244: makeSyscallInfo("mq_notify", Hex, Hex), + 245: makeSyscallInfo("mq_getsetattr", Hex, Hex, Hex), + 246: makeSyscallInfo("kexec_load", Hex, Hex, Hex, Hex), + 247: makeSyscallInfo("waitid", Hex, Hex, Hex, Hex, Rusage), + 248: makeSyscallInfo("add_key", Hex, Hex, Hex, Hex, Hex), + 249: makeSyscallInfo("request_key", Hex, Hex, Hex, Hex), + 250: makeSyscallInfo("keyctl", Hex, Hex, Hex, Hex, Hex), + 251: makeSyscallInfo("ioprio_set", Hex, Hex, Hex), + 252: makeSyscallInfo("ioprio_get", Hex, Hex), + 253: makeSyscallInfo("inotify_init"), + 254: makeSyscallInfo("inotify_add_watch", Hex, Path, Hex), + 255: makeSyscallInfo("inotify_rm_watch", Hex, Hex), + 256: makeSyscallInfo("migrate_pages", Hex, Hex, Hex, Hex), + 257: makeSyscallInfo("openat", FD, Path, OpenFlags, Mode), + 258: makeSyscallInfo("mkdirat", FD, Path, Hex), + 259: makeSyscallInfo("mknodat", FD, Path, Mode, Hex), + 260: makeSyscallInfo("fchownat", FD, Path, Hex, Hex, Hex), + 261: makeSyscallInfo("futimesat", FD, Path, Hex), + 262: makeSyscallInfo("newfstatat", FD, Path, Stat, Hex), + 263: makeSyscallInfo("unlinkat", FD, Path, Hex), + 264: makeSyscallInfo("renameat", FD, Path, Hex, Path), + 265: makeSyscallInfo("linkat", FD, Path, Hex, Path, Hex), + 266: makeSyscallInfo("symlinkat", Path, Hex, Path), + 267: makeSyscallInfo("readlinkat", FD, Path, ReadBuffer, Hex), + 268: makeSyscallInfo("fchmodat", FD, Path, Mode), + 269: makeSyscallInfo("faccessat", FD, Path, Oct, Hex), + 270: makeSyscallInfo("pselect6", Hex, Hex, Hex, Hex, Hex, Hex), + 271: makeSyscallInfo("ppoll", PollFDs, Hex, Timespec, SigSet, Hex), + 272: makeSyscallInfo("unshare", CloneFlags), + 273: makeSyscallInfo("set_robust_list", Hex, Hex), + 274: makeSyscallInfo("get_robust_list", Hex, Hex, Hex), + 275: makeSyscallInfo("splice", FD, Hex, FD, Hex, Hex, Hex), + 276: makeSyscallInfo("tee", FD, FD, Hex, Hex), + 277: makeSyscallInfo("sync_file_range", FD, Hex, Hex, Hex), + 278: makeSyscallInfo("vmsplice", FD, Hex, Hex, Hex), + 279: makeSyscallInfo("move_pages", Hex, Hex, Hex, Hex, Hex, Hex), + 280: makeSyscallInfo("utimensat", FD, Path, UTimeTimespec, Hex), + 281: makeSyscallInfo("epoll_pwait", Hex, Hex, Hex, Hex, SigSet, Hex), + 282: makeSyscallInfo("signalfd", Hex, Hex, Hex), + 283: makeSyscallInfo("timerfd_create", Hex, Hex), + 284: makeSyscallInfo("eventfd", Hex), + 285: makeSyscallInfo("fallocate", FD, Hex, Hex, Hex), + 286: makeSyscallInfo("timerfd_settime", FD, Hex, ItimerSpec, PostItimerSpec), + 287: makeSyscallInfo("timerfd_gettime", FD, PostItimerSpec), + 288: makeSyscallInfo("accept4", FD, PostSockAddr, SockLen, SockFlags), + 289: makeSyscallInfo("signalfd4", Hex, Hex, Hex, Hex), + 290: makeSyscallInfo("eventfd2", Hex, Hex), + 291: makeSyscallInfo("epoll_create1", Hex), + 292: makeSyscallInfo("dup3", FD, FD, Hex), + 293: makeSyscallInfo("pipe2", PipeFDs, Hex), + 294: makeSyscallInfo("inotify_init1", Hex), + 295: makeSyscallInfo("preadv", FD, ReadIOVec, Hex, Hex), + 296: makeSyscallInfo("pwritev", FD, WriteIOVec, Hex, Hex), + 297: makeSyscallInfo("rt_tgsigqueueinfo", Hex, Hex, Signal, Hex), + 298: makeSyscallInfo("perf_event_open", Hex, Hex, Hex, Hex, Hex), + 299: makeSyscallInfo("recvmmsg", FD, Hex, Hex, Hex, Hex), + 300: makeSyscallInfo("fanotify_init", Hex, Hex), + 301: makeSyscallInfo("fanotify_mark", Hex, Hex, Hex, Hex, Hex), + 302: makeSyscallInfo("prlimit64", Hex, Hex, Hex, Hex), + 303: makeSyscallInfo("name_to_handle_at", FD, Hex, Hex, Hex, Hex), + 304: makeSyscallInfo("open_by_handle_at", FD, Hex, Hex), + 305: makeSyscallInfo("clock_adjtime", Hex, Hex), + 306: makeSyscallInfo("syncfs", FD), + 307: makeSyscallInfo("sendmmsg", FD, Hex, Hex, Hex), + 308: makeSyscallInfo("setns", FD, Hex), + 309: makeSyscallInfo("getcpu", Hex, Hex, Hex), + 310: makeSyscallInfo("process_vm_readv", Hex, ReadIOVec, Hex, IOVec, Hex, Hex), + 311: makeSyscallInfo("process_vm_writev", Hex, IOVec, Hex, WriteIOVec, Hex, Hex), + 312: makeSyscallInfo("kcmp", Hex, Hex, Hex, Hex, Hex), + 313: makeSyscallInfo("finit_module", Hex, Hex, Hex), + 314: makeSyscallInfo("sched_setattr", Hex, Hex, Hex), + 315: makeSyscallInfo("sched_getattr", Hex, Hex, Hex), + 316: makeSyscallInfo("renameat2", FD, Path, Hex, Path, Hex), + 317: makeSyscallInfo("seccomp", Hex, Hex, Hex), +} diff --git a/pkg/sentry/strace/open.go b/pkg/sentry/strace/open.go new file mode 100644 index 000000000..140727b02 --- /dev/null +++ b/pkg/sentry/strace/open.go @@ -0,0 +1,96 @@ +// Copyright 2018 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. + +package strace + +import ( + "syscall" + + "gvisor.googlesource.com/gvisor/pkg/abi" +) + +// OpenMode represents the mode to open(2) a file. +var OpenMode = abi.ValueSet{ + syscall.O_RDWR: "O_RDWR", + syscall.O_WRONLY: "O_WRONLY", + syscall.O_RDONLY: "O_RDONLY", +} + +// OpenFlagSet is the set of open(2) flags. +var OpenFlagSet = abi.FlagSet{ + { + Flag: syscall.O_APPEND, + Name: "O_APPEND", + }, + { + Flag: syscall.O_ASYNC, + Name: "O_ASYNC", + }, + { + Flag: syscall.O_CLOEXEC, + Name: "O_CLOEXEC", + }, + { + Flag: syscall.O_CREAT, + Name: "O_CREAT", + }, + { + Flag: syscall.O_DIRECT, + Name: "O_DIRECT", + }, + { + Flag: syscall.O_DIRECTORY, + Name: "O_DIRECTORY", + }, + { + Flag: syscall.O_EXCL, + Name: "O_EXCL", + }, + { + Flag: syscall.O_NOATIME, + Name: "O_NOATIME", + }, + { + Flag: syscall.O_NOCTTY, + Name: "O_NOCTTY", + }, + { + Flag: syscall.O_NOFOLLOW, + Name: "O_NOFOLLOW", + }, + { + Flag: syscall.O_NONBLOCK, + Name: "O_NONBLOCK", + }, + { + Flag: 0x200000, // O_PATH + Name: "O_PATH", + }, + { + Flag: syscall.O_SYNC, + Name: "O_SYNC", + }, + { + Flag: syscall.O_TRUNC, + Name: "O_TRUNC", + }, +} + +func open(val uint64) string { + s := OpenMode.Parse(val & syscall.O_ACCMODE) + if flags := OpenFlagSet.Parse(val &^ syscall.O_ACCMODE); flags != "" { + s += "|" + flags + } + return s +} diff --git a/pkg/sentry/strace/poll.go b/pkg/sentry/strace/poll.go new file mode 100644 index 000000000..15605187d --- /dev/null +++ b/pkg/sentry/strace/poll.go @@ -0,0 +1,72 @@ +// Copyright 2019 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. + +package strace + +import ( + "fmt" + "strings" + + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" + slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// PollEventSet is the set of poll(2) event flags. +var PollEventSet = abi.FlagSet{ + {Flag: linux.POLLIN, Name: "POLLIN"}, + {Flag: linux.POLLPRI, Name: "POLLPRI"}, + {Flag: linux.POLLOUT, Name: "POLLOUT"}, + {Flag: linux.POLLERR, Name: "POLLERR"}, + {Flag: linux.POLLHUP, Name: "POLLHUP"}, + {Flag: linux.POLLNVAL, Name: "POLLNVAL"}, + {Flag: linux.POLLRDNORM, Name: "POLLRDNORM"}, + {Flag: linux.POLLRDBAND, Name: "POLLRDBAND"}, + {Flag: linux.POLLWRNORM, Name: "POLLWRNORM"}, + {Flag: linux.POLLWRBAND, Name: "POLLWRBAND"}, + {Flag: linux.POLLMSG, Name: "POLLMSG"}, + {Flag: linux.POLLREMOVE, Name: "POLLREMOVE"}, + {Flag: linux.POLLRDHUP, Name: "POLLRDHUP"}, + {Flag: linux.POLLFREE, Name: "POLLFREE"}, + {Flag: linux.POLL_BUSY_LOOP, Name: "POLL_BUSY_LOOP"}, +} + +func pollFD(t *kernel.Task, pfd *linux.PollFD, post bool) string { + revents := "..." + if post { + revents = PollEventSet.Parse(uint64(pfd.REvents)) + } + return fmt.Sprintf("{FD: %s, Events: %s, REvents: %s}", fd(t, kdefs.FD(pfd.FD)), PollEventSet.Parse(uint64(pfd.Events)), revents) +} + +func pollFDs(t *kernel.Task, addr usermem.Addr, nfds uint, post bool) string { + if addr == 0 { + return "null" + } + + pfds, err := slinux.CopyInPollFDs(t, addr, nfds) + if err != nil { + return fmt.Sprintf("%#x (error decoding pollfds: %s)", addr, err) + } + + s := make([]string, 0, len(pfds)) + for i := range pfds { + s = append(s, pollFD(t, &pfds[i], post)) + } + + return fmt.Sprintf("%#x [%s]", addr, strings.Join(s, ", ")) +} diff --git a/pkg/sentry/strace/ptrace.go b/pkg/sentry/strace/ptrace.go new file mode 100644 index 000000000..485aacb8a --- /dev/null +++ b/pkg/sentry/strace/ptrace.go @@ -0,0 +1,62 @@ +// Copyright 2018 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. + +package strace + +import ( + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" +) + +// PtraceRequestSet are the possible ptrace(2) requests. +var PtraceRequestSet = abi.ValueSet{ + linux.PTRACE_TRACEME: "PTRACE_TRACEME", + linux.PTRACE_PEEKTEXT: "PTRACE_PEEKTEXT", + linux.PTRACE_PEEKDATA: "PTRACE_PEEKDATA", + linux.PTRACE_PEEKUSR: "PTRACE_PEEKUSR", + linux.PTRACE_POKETEXT: "PTRACE_POKETEXT", + linux.PTRACE_POKEDATA: "PTRACE_POKEDATA", + linux.PTRACE_POKEUSR: "PTRACE_POKEUSR", + linux.PTRACE_CONT: "PTRACE_CONT", + linux.PTRACE_KILL: "PTRACE_KILL", + linux.PTRACE_SINGLESTEP: "PTRACE_SINGLESTEP", + linux.PTRACE_ATTACH: "PTRACE_ATTACH", + linux.PTRACE_DETACH: "PTRACE_DETACH", + linux.PTRACE_SYSCALL: "PTRACE_SYSCALL", + linux.PTRACE_SETOPTIONS: "PTRACE_SETOPTIONS", + linux.PTRACE_GETEVENTMSG: "PTRACE_GETEVENTMSG", + linux.PTRACE_GETSIGINFO: "PTRACE_GETSIGINFO", + linux.PTRACE_SETSIGINFO: "PTRACE_SETSIGINFO", + linux.PTRACE_GETREGSET: "PTRACE_GETREGSET", + linux.PTRACE_SETREGSET: "PTRACE_SETREGSET", + linux.PTRACE_SEIZE: "PTRACE_SEIZE", + linux.PTRACE_INTERRUPT: "PTRACE_INTERRUPT", + linux.PTRACE_LISTEN: "PTRACE_LISTEN", + linux.PTRACE_PEEKSIGINFO: "PTRACE_PEEKSIGINFO", + linux.PTRACE_GETSIGMASK: "PTRACE_GETSIGMASK", + linux.PTRACE_SETSIGMASK: "PTRACE_SETSIGMASK", + linux.PTRACE_GETREGS: "PTRACE_GETREGS", + linux.PTRACE_SETREGS: "PTRACE_SETREGS", + linux.PTRACE_GETFPREGS: "PTRACE_GETFPREGS", + linux.PTRACE_SETFPREGS: "PTRACE_SETFPREGS", + linux.PTRACE_GETFPXREGS: "PTRACE_GETFPXREGS", + linux.PTRACE_SETFPXREGS: "PTRACE_SETFPXREGS", + linux.PTRACE_OLDSETOPTIONS: "PTRACE_OLDSETOPTIONS", + linux.PTRACE_GET_THREAD_AREA: "PTRACE_GET_THREAD_AREA", + linux.PTRACE_SET_THREAD_AREA: "PTRACE_SET_THREAD_AREA", + linux.PTRACE_ARCH_PRCTL: "PTRACE_ARCH_PRCTL", + linux.PTRACE_SYSEMU: "PTRACE_SYSEMU", + linux.PTRACE_SYSEMU_SINGLESTEP: "PTRACE_SYSEMU_SINGLESTEP", + linux.PTRACE_SINGLEBLOCK: "PTRACE_SINGLEBLOCK", +} diff --git a/pkg/sentry/strace/signal.go b/pkg/sentry/strace/signal.go new file mode 100644 index 000000000..f82460e1c --- /dev/null +++ b/pkg/sentry/strace/signal.go @@ -0,0 +1,148 @@ +// Copyright 2018 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. + +package strace + +import ( + "fmt" + "strings" + + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// signalNames contains the names of all named signals. +var signalNames = abi.ValueSet{ + uint64(linux.SIGABRT): "SIGABRT", + uint64(linux.SIGALRM): "SIGALRM", + uint64(linux.SIGBUS): "SIGBUS", + uint64(linux.SIGCHLD): "SIGCHLD", + uint64(linux.SIGCONT): "SIGCONT", + uint64(linux.SIGFPE): "SIGFPE", + uint64(linux.SIGHUP): "SIGHUP", + uint64(linux.SIGILL): "SIGILL", + uint64(linux.SIGINT): "SIGINT", + uint64(linux.SIGIO): "SIGIO", + uint64(linux.SIGKILL): "SIGKILL", + uint64(linux.SIGPIPE): "SIGPIPE", + uint64(linux.SIGPROF): "SIGPROF", + uint64(linux.SIGPWR): "SIGPWR", + uint64(linux.SIGQUIT): "SIGQUIT", + uint64(linux.SIGSEGV): "SIGSEGV", + uint64(linux.SIGSTKFLT): "SIGSTKFLT", + uint64(linux.SIGSTOP): "SIGSTOP", + uint64(linux.SIGSYS): "SIGSYS", + uint64(linux.SIGTERM): "SIGTERM", + uint64(linux.SIGTRAP): "SIGTRAP", + uint64(linux.SIGTSTP): "SIGTSTP", + uint64(linux.SIGTTIN): "SIGTTIN", + uint64(linux.SIGTTOU): "SIGTTOU", + uint64(linux.SIGURG): "SIGURG", + uint64(linux.SIGUSR1): "SIGUSR1", + uint64(linux.SIGUSR2): "SIGUSR2", + uint64(linux.SIGVTALRM): "SIGVTALRM", + uint64(linux.SIGWINCH): "SIGWINCH", + uint64(linux.SIGXCPU): "SIGXCPU", + uint64(linux.SIGXFSZ): "SIGXFSZ", +} + +var signalMaskActions = abi.ValueSet{ + linux.SIG_BLOCK: "SIG_BLOCK", + linux.SIG_UNBLOCK: "SIG_UNBLOCK", + linux.SIG_SETMASK: "SIG_SETMASK", +} + +var sigActionFlags = abi.FlagSet{ + { + Flag: linux.SA_NOCLDSTOP, + Name: "SA_NOCLDSTOP", + }, + { + Flag: linux.SA_NOCLDWAIT, + Name: "SA_NOCLDWAIT", + }, + { + Flag: linux.SA_SIGINFO, + Name: "SA_SIGINFO", + }, + { + Flag: linux.SA_RESTORER, + Name: "SA_RESTORER", + }, + { + Flag: linux.SA_ONSTACK, + Name: "SA_ONSTACK", + }, + { + Flag: linux.SA_RESTART, + Name: "SA_RESTART", + }, + { + Flag: linux.SA_NODEFER, + Name: "SA_NODEFER", + }, + { + Flag: linux.SA_RESETHAND, + Name: "SA_RESETHAND", + }, +} + +func sigSet(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var b [linux.SignalSetSize]byte + if _, err := t.CopyInBytes(addr, b[:]); err != nil { + return fmt.Sprintf("%#x (error copying sigset: %v)", addr, err) + } + + set := linux.SignalSet(usermem.ByteOrder.Uint64(b[:])) + + return fmt.Sprintf("%#x %s", addr, formatSigSet(set)) +} + +func formatSigSet(set linux.SignalSet) string { + var signals []string + linux.ForEachSignal(set, func(sig linux.Signal) { + signals = append(signals, signalNames.ParseDecimal(uint64(sig))) + }) + + return fmt.Sprintf("[%v]", strings.Join(signals, " ")) +} + +func sigAction(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + sa, err := t.CopyInSignalAct(addr) + if err != nil { + return fmt.Sprintf("%#x (error copying sigaction: %v)", addr, err) + } + + var handler string + switch sa.Handler { + case linux.SIG_IGN: + handler = "SIG_IGN" + case linux.SIG_DFL: + handler = "SIG_DFL" + default: + handler = fmt.Sprintf("%#x", sa.Handler) + } + + return fmt.Sprintf("%#x {Handler: %s, Flags: %s, Restorer: %#x, Mask: %s}", addr, handler, sigActionFlags.Parse(sa.Flags), sa.Restorer, formatSigSet(sa.Mask)) +} diff --git a/pkg/sentry/strace/socket.go b/pkg/sentry/strace/socket.go new file mode 100644 index 000000000..dbe53b9a2 --- /dev/null +++ b/pkg/sentry/strace/socket.go @@ -0,0 +1,412 @@ +// Copyright 2018 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. + +package strace + +import ( + "fmt" + "strings" + + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/binary" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/socket/control" + "gvisor.googlesource.com/gvisor/pkg/sentry/socket/epsocket" + "gvisor.googlesource.com/gvisor/pkg/sentry/socket/netlink" + slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// SocketFamily are the possible socket(2) families. +var SocketFamily = abi.ValueSet{ + linux.AF_UNSPEC: "AF_UNSPEC", + linux.AF_UNIX: "AF_UNIX", + linux.AF_INET: "AF_INET", + linux.AF_AX25: "AF_AX25", + linux.AF_IPX: "AF_IPX", + linux.AF_APPLETALK: "AF_APPLETALK", + linux.AF_NETROM: "AF_NETROM", + linux.AF_BRIDGE: "AF_BRIDGE", + linux.AF_ATMPVC: "AF_ATMPVC", + linux.AF_X25: "AF_X25", + linux.AF_INET6: "AF_INET6", + linux.AF_ROSE: "AF_ROSE", + linux.AF_DECnet: "AF_DECnet", + linux.AF_NETBEUI: "AF_NETBEUI", + linux.AF_SECURITY: "AF_SECURITY", + linux.AF_KEY: "AF_KEY", + linux.AF_NETLINK: "AF_NETLINK", + linux.AF_PACKET: "AF_PACKET", + linux.AF_ASH: "AF_ASH", + linux.AF_ECONET: "AF_ECONET", + linux.AF_ATMSVC: "AF_ATMSVC", + linux.AF_RDS: "AF_RDS", + linux.AF_SNA: "AF_SNA", + linux.AF_IRDA: "AF_IRDA", + linux.AF_PPPOX: "AF_PPPOX", + linux.AF_WANPIPE: "AF_WANPIPE", + linux.AF_LLC: "AF_LLC", + linux.AF_IB: "AF_IB", + linux.AF_MPLS: "AF_MPLS", + linux.AF_CAN: "AF_CAN", + linux.AF_TIPC: "AF_TIPC", + linux.AF_BLUETOOTH: "AF_BLUETOOTH", + linux.AF_IUCV: "AF_IUCV", + linux.AF_RXRPC: "AF_RXRPC", + linux.AF_ISDN: "AF_ISDN", + linux.AF_PHONET: "AF_PHONET", + linux.AF_IEEE802154: "AF_IEEE802154", + linux.AF_CAIF: "AF_CAIF", + linux.AF_ALG: "AF_ALG", + linux.AF_NFC: "AF_NFC", + linux.AF_VSOCK: "AF_VSOCK", +} + +// SocketType are the possible socket(2) types. +var SocketType = abi.ValueSet{ + linux.SOCK_STREAM: "SOCK_STREAM", + linux.SOCK_DGRAM: "SOCK_DGRAM", + linux.SOCK_RAW: "SOCK_RAW", + linux.SOCK_RDM: "SOCK_RDM", + linux.SOCK_SEQPACKET: "SOCK_SEQPACKET", + linux.SOCK_DCCP: "SOCK_DCCP", + linux.SOCK_PACKET: "SOCK_PACKET", +} + +// SocketFlagSet are the possible socket(2) flags. +var SocketFlagSet = abi.FlagSet{ + { + Flag: linux.SOCK_CLOEXEC, + Name: "SOCK_CLOEXEC", + }, + { + Flag: linux.SOCK_NONBLOCK, + Name: "SOCK_NONBLOCK", + }, +} + +// ipProtocol are the possible socket(2) types for INET and INET6 sockets. +var ipProtocol = abi.ValueSet{ + linux.IPPROTO_IP: "IPPROTO_IP", + linux.IPPROTO_ICMP: "IPPROTO_ICMP", + linux.IPPROTO_IGMP: "IPPROTO_IGMP", + linux.IPPROTO_IPIP: "IPPROTO_IPIP", + linux.IPPROTO_TCP: "IPPROTO_TCP", + linux.IPPROTO_EGP: "IPPROTO_EGP", + linux.IPPROTO_PUP: "IPPROTO_PUP", + linux.IPPROTO_UDP: "IPPROTO_UDP", + linux.IPPROTO_IDP: "IPPROTO_IDP", + linux.IPPROTO_TP: "IPPROTO_TP", + linux.IPPROTO_DCCP: "IPPROTO_DCCP", + linux.IPPROTO_IPV6: "IPPROTO_IPV6", + linux.IPPROTO_RSVP: "IPPROTO_RSVP", + linux.IPPROTO_GRE: "IPPROTO_GRE", + linux.IPPROTO_ESP: "IPPROTO_ESP", + linux.IPPROTO_AH: "IPPROTO_AH", + linux.IPPROTO_MTP: "IPPROTO_MTP", + linux.IPPROTO_BEETPH: "IPPROTO_BEETPH", + linux.IPPROTO_ENCAP: "IPPROTO_ENCAP", + linux.IPPROTO_PIM: "IPPROTO_PIM", + linux.IPPROTO_COMP: "IPPROTO_COMP", + linux.IPPROTO_SCTP: "IPPROTO_SCTP", + linux.IPPROTO_UDPLITE: "IPPROTO_UDPLITE", + linux.IPPROTO_MPLS: "IPPROTO_MPLS", + linux.IPPROTO_RAW: "IPPROTO_RAW", +} + +// SocketProtocol are the possible socket(2) protocols for each protocol family. +var SocketProtocol = map[int32]abi.ValueSet{ + linux.AF_INET: ipProtocol, + linux.AF_INET6: ipProtocol, + linux.AF_NETLINK: { + linux.NETLINK_ROUTE: "NETLINK_ROUTE", + linux.NETLINK_UNUSED: "NETLINK_UNUSED", + linux.NETLINK_USERSOCK: "NETLINK_USERSOCK", + linux.NETLINK_FIREWALL: "NETLINK_FIREWALL", + linux.NETLINK_SOCK_DIAG: "NETLINK_SOCK_DIAG", + linux.NETLINK_NFLOG: "NETLINK_NFLOG", + linux.NETLINK_XFRM: "NETLINK_XFRM", + linux.NETLINK_SELINUX: "NETLINK_SELINUX", + linux.NETLINK_ISCSI: "NETLINK_ISCSI", + linux.NETLINK_AUDIT: "NETLINK_AUDIT", + linux.NETLINK_FIB_LOOKUP: "NETLINK_FIB_LOOKUP", + linux.NETLINK_CONNECTOR: "NETLINK_CONNECTOR", + linux.NETLINK_NETFILTER: "NETLINK_NETFILTER", + linux.NETLINK_IP6_FW: "NETLINK_IP6_FW", + linux.NETLINK_DNRTMSG: "NETLINK_DNRTMSG", + linux.NETLINK_KOBJECT_UEVENT: "NETLINK_KOBJECT_UEVENT", + linux.NETLINK_GENERIC: "NETLINK_GENERIC", + linux.NETLINK_SCSITRANSPORT: "NETLINK_SCSITRANSPORT", + linux.NETLINK_ECRYPTFS: "NETLINK_ECRYPTFS", + linux.NETLINK_RDMA: "NETLINK_RDMA", + linux.NETLINK_CRYPTO: "NETLINK_CRYPTO", + }, +} + +var controlMessageType = map[int32]string{ + linux.SCM_RIGHTS: "SCM_RIGHTS", + linux.SCM_CREDENTIALS: "SCM_CREDENTIALS", + linux.SO_TIMESTAMP: "SO_TIMESTAMP", +} + +func cmsghdr(t *kernel.Task, addr usermem.Addr, length uint64, maxBytes uint64) string { + if length > maxBytes { + return fmt.Sprintf("%#x (error decoding control: invalid length (%d))", addr, length) + } + + buf := make([]byte, length) + if _, err := t.CopyIn(addr, &buf); err != nil { + return fmt.Sprintf("%#x (error decoding control: %v)", addr, err) + } + + var strs []string + + for i := 0; i < len(buf); { + if i+linux.SizeOfControlMessageHeader > len(buf) { + strs = append(strs, "{invalid control message (too short)}") + break + } + + var h linux.ControlMessageHeader + binary.Unmarshal(buf[i:i+linux.SizeOfControlMessageHeader], usermem.ByteOrder, &h) + + var skipData bool + level := "SOL_SOCKET" + if h.Level != linux.SOL_SOCKET { + skipData = true + level = fmt.Sprint(h.Level) + } + + typ, ok := controlMessageType[h.Type] + if !ok { + skipData = true + typ = fmt.Sprint(h.Type) + } + + if h.Length > uint64(len(buf)-i) { + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, content extends beyond buffer}", + level, + typ, + h.Length, + )) + break + } + + i += linux.SizeOfControlMessageHeader + width := t.Arch().Width() + length := int(h.Length) - linux.SizeOfControlMessageHeader + + if skipData { + strs = append(strs, fmt.Sprintf("{level=%s, type=%s, length=%d}", level, typ, h.Length)) + i += control.AlignUp(length, width) + continue + } + + switch h.Type { + case linux.SCM_RIGHTS: + rightsSize := control.AlignDown(length, linux.SizeOfControlMessageRight) + + numRights := rightsSize / linux.SizeOfControlMessageRight + fds := make(linux.ControlMessageRights, numRights) + binary.Unmarshal(buf[i:i+rightsSize], usermem.ByteOrder, &fds) + + rights := make([]string, 0, len(fds)) + for _, fd := range fds { + rights = append(rights, fmt.Sprint(fd)) + } + + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, content: %s}", + level, + typ, + h.Length, + strings.Join(rights, ","), + )) + + case linux.SCM_CREDENTIALS: + if length < linux.SizeOfControlMessageCredentials { + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, content too short}", + level, + typ, + h.Length, + )) + break + } + + var creds linux.ControlMessageCredentials + binary.Unmarshal(buf[i:i+linux.SizeOfControlMessageCredentials], usermem.ByteOrder, &creds) + + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, pid: %d, uid: %d, gid: %d}", + level, + typ, + h.Length, + creds.PID, + creds.UID, + creds.GID, + )) + + case linux.SO_TIMESTAMP: + if length < linux.SizeOfTimeval { + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, content too short}", + level, + typ, + h.Length, + )) + break + } + + var tv linux.Timeval + binary.Unmarshal(buf[i:i+linux.SizeOfTimeval], usermem.ByteOrder, &tv) + + strs = append(strs, fmt.Sprintf( + "{level=%s, type=%s, length=%d, Sec: %d, Usec: %d}", + level, + typ, + h.Length, + tv.Sec, + tv.Usec, + )) + + default: + panic("unreachable") + } + i += control.AlignUp(length, width) + } + + return fmt.Sprintf("%#x %s", addr, strings.Join(strs, ", ")) +} + +func msghdr(t *kernel.Task, addr usermem.Addr, printContent bool, maxBytes uint64) string { + var msg slinux.MessageHeader64 + if err := slinux.CopyInMessageHeader64(t, addr, &msg); err != nil { + return fmt.Sprintf("%#x (error decoding msghdr: %v)", addr, err) + } + s := fmt.Sprintf( + "%#x {name=%#x, namelen=%d, iovecs=%s", + addr, + msg.Name, + msg.NameLen, + iovecs(t, usermem.Addr(msg.Iov), int(msg.IovLen), printContent, maxBytes), + ) + if printContent { + s = fmt.Sprintf("%s, control={%s}", s, cmsghdr(t, usermem.Addr(msg.Control), msg.ControlLen, maxBytes)) + } else { + s = fmt.Sprintf("%s, control=%#x, control_len=%d", s, msg.Control, msg.ControlLen) + } + return fmt.Sprintf("%s, flags=%d}", s, msg.Flags) +} + +func sockAddr(t *kernel.Task, addr usermem.Addr, length uint32) string { + if addr == 0 { + return "null" + } + + b, err := slinux.CaptureAddress(t, addr, length) + if err != nil { + return fmt.Sprintf("%#x {error reading address: %v}", addr, err) + } + + // Extract address family. + if len(b) < 2 { + return fmt.Sprintf("%#x {address too short: %d bytes}", addr, len(b)) + } + family := usermem.ByteOrder.Uint16(b) + + familyStr := SocketFamily.Parse(uint64(family)) + + switch family { + case linux.AF_INET, linux.AF_INET6, linux.AF_UNIX: + fa, err := epsocket.GetAddress(int(family), b) + if err != nil { + return fmt.Sprintf("%#x {Family: %s, error extracting address: %v}", addr, familyStr, err) + } + + if family == linux.AF_UNIX { + return fmt.Sprintf("%#x {Family: %s, Addr: %q}", addr, familyStr, string(fa.Addr)) + } + + return fmt.Sprintf("%#x {Family: %s, Addr: %v, Port: %d}", addr, familyStr, fa.Addr, fa.Port) + case linux.AF_NETLINK: + sa, err := netlink.ExtractSockAddr(b) + if err != nil { + return fmt.Sprintf("%#x {Family: %s, error extracting address: %v}", addr, familyStr, err) + } + return fmt.Sprintf("%#x {Family: %s, PortID: %d, Groups: %d}", addr, familyStr, sa.PortID, sa.Groups) + default: + return fmt.Sprintf("%#x {Family: %s, family addr format unknown}", addr, familyStr) + } +} + +func postSockAddr(t *kernel.Task, addr usermem.Addr, lengthPtr usermem.Addr) string { + if addr == 0 { + return "null" + } + + if lengthPtr == 0 { + return fmt.Sprintf("%#x {length null}", addr) + } + + l, err := copySockLen(t, lengthPtr) + if err != nil { + return fmt.Sprintf("%#x {error reading length: %v}", addr, err) + } + + return sockAddr(t, addr, l) +} + +func copySockLen(t *kernel.Task, addr usermem.Addr) (uint32, error) { + // socklen_t is 32-bits. + var l uint32 + _, err := t.CopyIn(addr, &l) + return l, err +} + +func sockLenPointer(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + l, err := copySockLen(t, addr) + if err != nil { + return fmt.Sprintf("%#x {error reading length: %v}", addr, err) + } + return fmt.Sprintf("%#x {length=%v}", addr, l) +} + +func sockType(stype int32) string { + s := SocketType.Parse(uint64(stype & linux.SOCK_TYPE_MASK)) + if flags := SocketFlagSet.Parse(uint64(stype &^ linux.SOCK_TYPE_MASK)); flags != "" { + s += "|" + flags + } + return s +} + +func sockProtocol(family, protocol int32) string { + protocols, ok := SocketProtocol[family] + if !ok { + return fmt.Sprintf("%#x", protocol) + } + return protocols.Parse(uint64(protocol)) +} + +func sockFlags(flags int32) string { + if flags == 0 { + return "0" + } + return SocketFlagSet.Parse(uint64(flags)) +} diff --git a/pkg/sentry/strace/strace.go b/pkg/sentry/strace/strace.go new file mode 100644 index 000000000..f4c1be4ce --- /dev/null +++ b/pkg/sentry/strace/strace.go @@ -0,0 +1,820 @@ +// Copyright 2018 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. + +// Package strace implements the logic to print out the input and the return value +// of each traced syscall. +package strace + +import ( + "encoding/binary" + "fmt" + "strconv" + "strings" + "syscall" + "time" + + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/abi/linux" + "gvisor.googlesource.com/gvisor/pkg/bits" + "gvisor.googlesource.com/gvisor/pkg/eventchannel" + "gvisor.googlesource.com/gvisor/pkg/seccomp" + "gvisor.googlesource.com/gvisor/pkg/sentry/arch" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs" + pb "gvisor.googlesource.com/gvisor/pkg/sentry/strace/strace_go_proto" + slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// DefaultLogMaximumSize is the default LogMaximumSize. +const DefaultLogMaximumSize = 1024 + +// LogMaximumSize determines the maximum display size for data blobs (read, +// write, etc.). +var LogMaximumSize uint = DefaultLogMaximumSize + +// EventMaximumSize determines the maximum size for data blobs (read, write, +// etc.) sent over the event channel. Default is 0 because most clients cannot +// do anything useful with binary text dump of byte array arguments. +var EventMaximumSize uint + +// ItimerTypes are the possible itimer types. +var ItimerTypes = abi.ValueSet{ + linux.ITIMER_REAL: "ITIMER_REAL", + linux.ITIMER_VIRTUAL: "ITIMER_VIRTUAL", + linux.ITIMER_PROF: "ITIMER_PROF", +} + +func iovecs(t *kernel.Task, addr usermem.Addr, iovcnt int, printContent bool, maxBytes uint64) string { + if iovcnt < 0 || iovcnt > linux.UIO_MAXIOV { + return fmt.Sprintf("%#x (error decoding iovecs: invalid iovcnt)", addr) + } + ars, err := t.CopyInIovecs(addr, iovcnt) + if err != nil { + return fmt.Sprintf("%#x (error decoding iovecs: %v)", addr, err) + } + + var totalBytes uint64 + var truncated bool + iovs := make([]string, iovcnt) + for i := 0; !ars.IsEmpty(); i, ars = i+1, ars.Tail() { + ar := ars.Head() + if ar.Length() == 0 || !printContent { + iovs[i] = fmt.Sprintf("{base=%#x, len=%d}", ar.Start, ar.Length()) + continue + } + + size := uint64(ar.Length()) + if truncated || totalBytes+size > maxBytes { + truncated = true + size = maxBytes - totalBytes + } else { + totalBytes += uint64(ar.Length()) + } + + b := make([]byte, size) + amt, err := t.CopyIn(ar.Start, b) + if err != nil { + iovs[i] = fmt.Sprintf("{base=%#x, len=%d, %q..., error decoding string: %v}", ar.Start, ar.Length(), b[:amt], err) + continue + } + + dot := "" + if truncated { + // Indicate truncation. + dot = "..." + } + iovs[i] = fmt.Sprintf("{base=%#x, len=%d, %q%s}", ar.Start, ar.Length(), b[:amt], dot) + } + + return fmt.Sprintf("%#x %s", addr, strings.Join(iovs, ", ")) +} + +func dump(t *kernel.Task, addr usermem.Addr, size uint, maximumBlobSize uint) string { + origSize := size + if size > maximumBlobSize { + size = maximumBlobSize + } + if size == 0 { + return "" + } + + b := make([]byte, size) + amt, err := t.CopyIn(addr, b) + if err != nil { + return fmt.Sprintf("%#x (error decoding string: %s)", addr, err) + } + + dot := "" + if uint(amt) < origSize { + // ... if we truncated the dump. + dot = "..." + } + + return fmt.Sprintf("%#x %q%s", addr, b[:amt], dot) +} + +func path(t *kernel.Task, addr usermem.Addr) string { + path, err := t.CopyInString(addr, linux.PATH_MAX) + if err != nil { + return fmt.Sprintf("%#x (error decoding path: %s)", addr, err) + } + return fmt.Sprintf("%#x %s", addr, path) +} + +func fd(t *kernel.Task, fd kdefs.FD) string { + root := t.FSContext().RootDirectory() + if root != nil { + defer root.DecRef() + } + + if fd == linux.AT_FDCWD { + wd := t.FSContext().WorkingDirectory() + var name string + if wd != nil { + defer wd.DecRef() + name, _ = wd.FullName(root) + } else { + name = "(unknown cwd)" + } + return fmt.Sprintf("AT_FDCWD %s", name) + } + + file := t.FDMap().GetFile(fd) + if file == nil { + // Cast FD to uint64 to avoid printing negative hex. + return fmt.Sprintf("%#x (bad FD)", uint64(fd)) + } + defer file.DecRef() + + name, _ := file.Dirent.FullName(root) + return fmt.Sprintf("%#x %s", fd, name) +} + +func fdpair(t *kernel.Task, addr usermem.Addr) string { + var fds [2]int32 + _, err := t.CopyIn(addr, &fds) + if err != nil { + return fmt.Sprintf("%#x (error decoding fds: %s)", addr, err) + } + + return fmt.Sprintf("%#x [%d %d]", addr, fds[0], fds[1]) +} + +func uname(t *kernel.Task, addr usermem.Addr) string { + var u linux.UtsName + if _, err := t.CopyIn(addr, &u); err != nil { + return fmt.Sprintf("%#x (error decoding utsname: %s)", addr, err) + } + + return fmt.Sprintf("%#x %s", addr, u) +} + +func utimensTimespec(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var tim linux.Timespec + if _, err := t.CopyIn(addr, &tim); err != nil { + return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) + } + + var ns string + switch tim.Nsec { + case linux.UTIME_NOW: + ns = "UTIME_NOW" + case linux.UTIME_OMIT: + ns = "UTIME_OMIT" + default: + ns = fmt.Sprintf("%v", tim.Nsec) + } + return fmt.Sprintf("%#x {sec=%v nsec=%s}", addr, tim.Sec, ns) +} + +func timespec(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var tim linux.Timespec + if _, err := t.CopyIn(addr, &tim); err != nil { + return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err) + } + return fmt.Sprintf("%#x {sec=%v nsec=%v}", addr, tim.Sec, tim.Nsec) +} + +func timeval(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var tim linux.Timeval + if _, err := t.CopyIn(addr, &tim); err != nil { + return fmt.Sprintf("%#x (error decoding timeval: %s)", addr, err) + } + + return fmt.Sprintf("%#x {sec=%v usec=%v}", addr, tim.Sec, tim.Usec) +} + +func utimbuf(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var utim syscall.Utimbuf + if _, err := t.CopyIn(addr, &utim); err != nil { + return fmt.Sprintf("%#x (error decoding utimbuf: %s)", addr, err) + } + + return fmt.Sprintf("%#x {actime=%v, modtime=%v}", addr, utim.Actime, utim.Modtime) +} + +func stat(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var stat linux.Stat + if _, err := t.CopyIn(addr, &stat); err != nil { + return fmt.Sprintf("%#x (error decoding stat: %s)", addr, err) + } + return fmt.Sprintf("%#x {dev=%d, ino=%d, mode=%s, nlink=%d, uid=%d, gid=%d, rdev=%d, size=%d, blksize=%d, blocks=%d, atime=%s, mtime=%s, ctime=%s}", addr, stat.Dev, stat.Ino, linux.FileMode(stat.Mode), stat.Nlink, stat.UID, stat.GID, stat.Rdev, stat.Size, stat.Blksize, stat.Blocks, time.Unix(stat.ATime.Sec, stat.ATime.Nsec), time.Unix(stat.MTime.Sec, stat.MTime.Nsec), time.Unix(stat.CTime.Sec, stat.CTime.Nsec)) +} + +func itimerval(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + interval := timeval(t, addr) + value := timeval(t, addr+usermem.Addr(binary.Size(linux.Timeval{}))) + return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) +} + +func itimerspec(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + interval := timespec(t, addr) + value := timespec(t, addr+usermem.Addr(binary.Size(linux.Timespec{}))) + return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value) +} + +func stringVector(t *kernel.Task, addr usermem.Addr) string { + vec, err := t.CopyInVector(addr, slinux.ExecMaxElemSize, slinux.ExecMaxTotalSize) + if err != nil { + return fmt.Sprintf("%#x {error copying vector: %v}", addr, err) + } + s := fmt.Sprintf("%#x [", addr) + for i, v := range vec { + if i != 0 { + s += ", " + } + s += fmt.Sprintf("%q", v) + } + s += "]" + return s +} + +func rusage(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var ru linux.Rusage + if _, err := t.CopyIn(addr, &ru); err != nil { + return fmt.Sprintf("%#x (error decoding rusage: %s)", addr, err) + } + return fmt.Sprintf("%#x %+v", addr, ru) +} + +func capHeader(t *kernel.Task, addr usermem.Addr) string { + if addr == 0 { + return "null" + } + + var hdr linux.CapUserHeader + if _, err := t.CopyIn(addr, &hdr); err != nil { + return fmt.Sprintf("%#x (error decoding header: %s)", addr, err) + } + + var version string + switch hdr.Version { + case linux.LINUX_CAPABILITY_VERSION_1: + version = "1" + case linux.LINUX_CAPABILITY_VERSION_2: + version = "2" + case linux.LINUX_CAPABILITY_VERSION_3: + version = "3" + default: + version = strconv.FormatUint(uint64(hdr.Version), 16) + } + + return fmt.Sprintf("%#x {Version: %s, Pid: %d}", addr, version, hdr.Pid) +} + +func capData(t *kernel.Task, hdrAddr, dataAddr usermem.Addr) string { + if dataAddr == 0 { + return "null" + } + + var hdr linux.CapUserHeader + if _, err := t.CopyIn(hdrAddr, &hdr); err != nil { + return fmt.Sprintf("%#x (error decoding header: %v)", dataAddr, err) + } + + var p, i, e uint64 + + switch hdr.Version { + case linux.LINUX_CAPABILITY_VERSION_1: + var data linux.CapUserData + if _, err := t.CopyIn(dataAddr, &data); err != nil { + return fmt.Sprintf("%#x (error decoding data: %v)", dataAddr, err) + } + p = uint64(data.Permitted) + i = uint64(data.Inheritable) + e = uint64(data.Effective) + case linux.LINUX_CAPABILITY_VERSION_2, linux.LINUX_CAPABILITY_VERSION_3: + var data [2]linux.CapUserData + if _, err := t.CopyIn(dataAddr, &data); err != nil { + return fmt.Sprintf("%#x (error decoding data: %v)", dataAddr, err) + } + p = uint64(data[0].Permitted) | (uint64(data[1].Permitted) << 32) + i = uint64(data[0].Inheritable) | (uint64(data[1].Inheritable) << 32) + e = uint64(data[0].Effective) | (uint64(data[1].Effective) << 32) + default: + return fmt.Sprintf("%#x (unknown version %d)", dataAddr, hdr.Version) + } + + return fmt.Sprintf("%#x {Permitted: %s, Inheritable: %s, Effective: %s}", dataAddr, CapabilityBitset.Parse(p), CapabilityBitset.Parse(i), CapabilityBitset.Parse(e)) +} + +// pre fills in the pre-execution arguments for a system call. If an argument +// cannot be interpreted before the system call is executed, then a hex value +// will be used. Note that a full output slice will always be provided, that is +// len(return) == len(args). +func (i *SyscallInfo) pre(t *kernel.Task, args arch.SyscallArguments, maximumBlobSize uint) []string { + var output []string + + for arg := range args { + if arg >= len(i.format) { + break + } + switch i.format[arg] { + case FD: + output = append(output, fd(t, kdefs.FD(args[arg].Int()))) + case WriteBuffer: + output = append(output, dump(t, args[arg].Pointer(), args[arg+1].SizeT(), maximumBlobSize)) + case WriteIOVec: + output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, uint64(maximumBlobSize))) + case IOVec: + output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), false /* content */, uint64(maximumBlobSize))) + case SendMsgHdr: + output = append(output, msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize))) + case RecvMsgHdr: + output = append(output, msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize))) + case Path: + output = append(output, path(t, args[arg].Pointer())) + case ExecveStringVector: + output = append(output, stringVector(t, args[arg].Pointer())) + case SockAddr: + output = append(output, sockAddr(t, args[arg].Pointer(), uint32(args[arg+1].Uint64()))) + case SockLen: + output = append(output, sockLenPointer(t, args[arg].Pointer())) + case SockFamily: + output = append(output, SocketFamily.Parse(uint64(args[arg].Int()))) + case SockType: + output = append(output, sockType(args[arg].Int())) + case SockProtocol: + output = append(output, sockProtocol(args[arg-2].Int(), args[arg].Int())) + case SockFlags: + output = append(output, sockFlags(args[arg].Int())) + case Timespec: + output = append(output, timespec(t, args[arg].Pointer())) + case UTimeTimespec: + output = append(output, utimensTimespec(t, args[arg].Pointer())) + case ItimerVal: + output = append(output, itimerval(t, args[arg].Pointer())) + case ItimerSpec: + output = append(output, itimerspec(t, args[arg].Pointer())) + case Timeval: + output = append(output, timeval(t, args[arg].Pointer())) + case Utimbuf: + output = append(output, utimbuf(t, args[arg].Pointer())) + case CloneFlags: + output = append(output, CloneFlagSet.Parse(uint64(args[arg].Uint()))) + case OpenFlags: + output = append(output, open(uint64(args[arg].Uint()))) + case Mode: + output = append(output, linux.FileMode(args[arg].ModeT()).String()) + case FutexOp: + output = append(output, futex(uint64(args[arg].Uint()))) + case PtraceRequest: + output = append(output, PtraceRequestSet.Parse(args[arg].Uint64())) + case ItimerType: + output = append(output, ItimerTypes.Parse(uint64(args[arg].Int()))) + case Signal: + output = append(output, signalNames.ParseDecimal(args[arg].Uint64())) + case SignalMaskAction: + output = append(output, signalMaskActions.Parse(uint64(args[arg].Int()))) + case SigSet: + output = append(output, sigSet(t, args[arg].Pointer())) + case SigAction: + output = append(output, sigAction(t, args[arg].Pointer())) + case CapHeader: + output = append(output, capHeader(t, args[arg].Pointer())) + case CapData: + output = append(output, capData(t, args[arg-1].Pointer(), args[arg].Pointer())) + case PollFDs: + output = append(output, pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), false)) + case Oct: + output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8)) + case Hex: + fallthrough + default: + output = append(output, "0x"+strconv.FormatUint(args[arg].Uint64(), 16)) + } + } + + return output +} + +// post fills in the post-execution arguments for a system call. This modifies +// the given output slice in place with arguments that may only be interpreted +// after the system call has been executed. +func (i *SyscallInfo) post(t *kernel.Task, args arch.SyscallArguments, rval uintptr, output []string, maximumBlobSize uint) { + for arg := range output { + if arg >= len(i.format) { + break + } + switch i.format[arg] { + case ReadBuffer: + output[arg] = dump(t, args[arg].Pointer(), uint(rval), maximumBlobSize) + case ReadIOVec: + printLength := uint64(rval) + if printLength > uint64(maximumBlobSize) { + printLength = uint64(maximumBlobSize) + } + output[arg] = iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), true /* content */, printLength) + case WriteIOVec, IOVec, WriteBuffer: + // We already have a big blast from write. + output[arg] = "..." + case SendMsgHdr: + output[arg] = msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize)) + case RecvMsgHdr: + output[arg] = msghdr(t, args[arg].Pointer(), true /* content */, uint64(maximumBlobSize)) + case PostPath: + output[arg] = path(t, args[arg].Pointer()) + case PipeFDs: + output[arg] = fdpair(t, args[arg].Pointer()) + case Uname: + output[arg] = uname(t, args[arg].Pointer()) + case Stat: + output[arg] = stat(t, args[arg].Pointer()) + case PostSockAddr: + output[arg] = postSockAddr(t, args[arg].Pointer(), args[arg+1].Pointer()) + case SockLen: + output[arg] = sockLenPointer(t, args[arg].Pointer()) + case PostTimespec: + output[arg] = timespec(t, args[arg].Pointer()) + case PostItimerVal: + output[arg] = itimerval(t, args[arg].Pointer()) + case PostItimerSpec: + output[arg] = itimerspec(t, args[arg].Pointer()) + case Timeval: + output[arg] = timeval(t, args[arg].Pointer()) + case Rusage: + output[arg] = rusage(t, args[arg].Pointer()) + case PostSigSet: + output[arg] = sigSet(t, args[arg].Pointer()) + case PostSigAction: + output[arg] = sigAction(t, args[arg].Pointer()) + case PostCapData: + output[arg] = capData(t, args[arg-1].Pointer(), args[arg].Pointer()) + case PollFDs: + output[arg] = pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), true) + } + } +} + +// printEntry prints the given system call entry. +func (i *SyscallInfo) printEnter(t *kernel.Task, args arch.SyscallArguments) []string { + output := i.pre(t, args, LogMaximumSize) + + switch len(output) { + case 0: + t.Infof("%s E %s()", t.Name(), i.name) + case 1: + t.Infof("%s E %s(%s)", t.Name(), i.name, + output[0]) + case 2: + t.Infof("%s E %s(%s, %s)", t.Name(), i.name, + output[0], output[1]) + case 3: + t.Infof("%s E %s(%s, %s, %s)", t.Name(), i.name, + output[0], output[1], output[2]) + case 4: + t.Infof("%s E %s(%s, %s, %s, %s)", t.Name(), i.name, + output[0], output[1], output[2], output[3]) + case 5: + t.Infof("%s E %s(%s, %s, %s, %s, %s)", t.Name(), i.name, + output[0], output[1], output[2], output[3], output[4]) + case 6: + t.Infof("%s E %s(%s, %s, %s, %s, %s, %s)", t.Name(), i.name, + output[0], output[1], output[2], output[3], output[4], output[5]) + } + + return output +} + +// printExit prints the given system call exit. +func (i *SyscallInfo) printExit(t *kernel.Task, elapsed time.Duration, output []string, args arch.SyscallArguments, retval uintptr, err error, errno int) { + var rval string + if err == nil { + // Fill in the output after successful execution. + i.post(t, args, retval, output, LogMaximumSize) + rval = fmt.Sprintf("%#x (%v)", retval, elapsed) + } else { + rval = fmt.Sprintf("%#x errno=%d (%s) (%v)", retval, errno, err, elapsed) + } + + switch len(output) { + case 0: + t.Infof("%s X %s() = %s", t.Name(), i.name, + rval) + case 1: + t.Infof("%s X %s(%s) = %s", t.Name(), i.name, + output[0], rval) + case 2: + t.Infof("%s X %s(%s, %s) = %s", t.Name(), i.name, + output[0], output[1], rval) + case 3: + t.Infof("%s X %s(%s, %s, %s) = %s", t.Name(), i.name, + output[0], output[1], output[2], rval) + case 4: + t.Infof("%s X %s(%s, %s, %s, %s) = %s", t.Name(), i.name, + output[0], output[1], output[2], output[3], rval) + case 5: + t.Infof("%s X %s(%s, %s, %s, %s, %s) = %s", t.Name(), i.name, + output[0], output[1], output[2], output[3], output[4], rval) + case 6: + t.Infof("%s X %s(%s, %s, %s, %s, %s, %s) = %s", t.Name(), i.name, + output[0], output[1], output[2], output[3], output[4], output[5], rval) + } +} + +// sendEnter sends the syscall enter to event log. +func (i *SyscallInfo) sendEnter(t *kernel.Task, args arch.SyscallArguments) []string { + output := i.pre(t, args, EventMaximumSize) + + event := pb.Strace{ + Process: t.Name(), + Function: i.name, + Info: &pb.Strace_Enter{ + Enter: &pb.StraceEnter{}, + }, + } + for _, arg := range output { + event.Args = append(event.Args, arg) + } + eventchannel.Emit(&event) + + return output +} + +// sendExit sends the syscall exit to event log. +func (i *SyscallInfo) sendExit(t *kernel.Task, elapsed time.Duration, output []string, args arch.SyscallArguments, rval uintptr, err error, errno int) { + if err == nil { + // Fill in the output after successful execution. + i.post(t, args, rval, output, EventMaximumSize) + } + + exit := &pb.StraceExit{ + Return: fmt.Sprintf("%#x", rval), + ElapsedNs: elapsed.Nanoseconds(), + } + if err != nil { + exit.Error = err.Error() + exit.ErrNo = int64(errno) + } + event := pb.Strace{ + Process: t.Name(), + Function: i.name, + Info: &pb.Strace_Exit{Exit: exit}, + } + for _, arg := range output { + event.Args = append(event.Args, arg) + } + eventchannel.Emit(&event) +} + +type syscallContext struct { + info SyscallInfo + args arch.SyscallArguments + start time.Time + logOutput []string + eventOutput []string + flags uint32 +} + +// SyscallEnter implements kernel.Stracer.SyscallEnter. It logs the syscall +// entry trace. +func (s SyscallMap) SyscallEnter(t *kernel.Task, sysno uintptr, args arch.SyscallArguments, flags uint32) interface{} { + info, ok := s[sysno] + if !ok { + info = SyscallInfo{ + name: fmt.Sprintf("sys_%d", sysno), + format: defaultFormat, + } + } + + var output, eventOutput []string + if bits.IsOn32(flags, kernel.StraceEnableLog) { + output = info.printEnter(t, args) + } + if bits.IsOn32(flags, kernel.StraceEnableEvent) { + eventOutput = info.sendEnter(t, args) + } + + return &syscallContext{ + info: info, + args: args, + start: time.Now(), + logOutput: output, + eventOutput: eventOutput, + flags: flags, + } +} + +// SyscallExit implements kernel.Stracer.SyscallExit. It logs the syscall +// exit trace. +func (s SyscallMap) SyscallExit(context interface{}, t *kernel.Task, sysno, rval uintptr, err error) { + errno := t.ExtractErrno(err, int(sysno)) + c := context.(*syscallContext) + + elapsed := time.Since(c.start) + if bits.IsOn32(c.flags, kernel.StraceEnableLog) { + c.info.printExit(t, elapsed, c.logOutput, c.args, rval, err, errno) + } + if bits.IsOn32(c.flags, kernel.StraceEnableEvent) { + c.info.sendExit(t, elapsed, c.eventOutput, c.args, rval, err, errno) + } +} + +// ConvertToSysnoMap converts the names to a map keyed on the syscall number +// and value set to true. +// +// The map is in a convenient format to pass to SyscallFlagsTable.Enable(). +func (s SyscallMap) ConvertToSysnoMap(syscalls []string) (map[uintptr]bool, error) { + if syscalls == nil { + // Sentinel: no list. + return nil, nil + } + + l := make(map[uintptr]bool) + for _, sc := range syscalls { + // Try to match this system call. + sysno, ok := s.ConvertToSysno(sc) + if !ok { + return nil, fmt.Errorf("syscall %q not found", sc) + } + l[sysno] = true + } + + // Success. + return l, nil +} + +// ConvertToSysno converts the name to system call number. Returns false +// if syscall with same name is not found. +func (s SyscallMap) ConvertToSysno(syscall string) (uintptr, bool) { + for sysno, info := range s { + if info.name != "" && info.name == syscall { + return sysno, true + } + } + return 0, false +} + +// Name returns the syscall name. +func (s SyscallMap) Name(sysno uintptr) string { + if info, ok := s[sysno]; ok { + return info.name + } + return fmt.Sprintf("sys_%d", sysno) +} + +// Initialize prepares all syscall tables for use by this package. +// +// N.B. This is not in an init function because we can't be sure all syscall +// tables are registered with the kernel when init runs. +// +// TODO(gvisor.dev/issue/155): remove kernel package dependencies from this +// package and have the kernel package self-initialize all syscall tables. +func Initialize() { + for _, table := range kernel.SyscallTables() { + // Is this known? + sys, ok := Lookup(table.OS, table.Arch) + if !ok { + continue + } + + table.Stracer = sys + } +} + +// SinkType defines where to send straces to. +type SinkType uint32 + +const ( + // SinkTypeLog sends straces to text log + SinkTypeLog SinkType = 1 << iota + + // SinkTypeEvent sends strace to event log + SinkTypeEvent +) + +func convertToSyscallFlag(sinks SinkType) uint32 { + ret := uint32(0) + if bits.IsOn32(uint32(sinks), uint32(SinkTypeLog)) { + ret |= kernel.StraceEnableLog + } + if bits.IsOn32(uint32(sinks), uint32(SinkTypeEvent)) { + ret |= kernel.StraceEnableEvent + } + return ret +} + +// Enable enables the syscalls in whitelist in all syscall tables. +// +// Preconditions: Initialize has been called. +func Enable(whitelist []string, sinks SinkType) error { + flags := convertToSyscallFlag(sinks) + for _, table := range kernel.SyscallTables() { + // Is this known? + sys, ok := Lookup(table.OS, table.Arch) + if !ok { + continue + } + + // Convert to a set of system calls numbers. + wl, err := sys.ConvertToSysnoMap(whitelist) + if err != nil { + return err + } + + table.FeatureEnable.Enable(flags, wl, true) + } + + // Done. + return nil +} + +// Disable will disable Strace for all system calls and missing syscalls. +// +// Preconditions: Initialize has been called. +func Disable(sinks SinkType) { + flags := convertToSyscallFlag(sinks) + for _, table := range kernel.SyscallTables() { + // Strace will be disabled for all syscalls including missing. + table.FeatureEnable.Enable(flags, nil, false) + } +} + +// EnableAll enables all syscalls in all syscall tables. +// +// Preconditions: Initialize has been called. +func EnableAll(sinks SinkType) { + flags := convertToSyscallFlag(sinks) + for _, table := range kernel.SyscallTables() { + // Is this known? + if _, ok := Lookup(table.OS, table.Arch); !ok { + continue + } + + table.FeatureEnable.EnableAll(flags) + } +} + +func init() { + t, ok := Lookup(abi.Host, arch.Host) + if ok { + // Provide the native table as the lookup for seccomp + // debugging. This is best-effort. This is provided this way to + // avoid dependencies from seccomp to this package. + seccomp.SyscallName = t.Name + } +} diff --git a/pkg/sentry/strace/strace_go_proto/strace.pb.go b/pkg/sentry/strace/strace_go_proto/strace.pb.go new file mode 100755 index 000000000..ef45661bc --- /dev/null +++ b/pkg/sentry/strace/strace_go_proto/strace.pb.go @@ -0,0 +1,247 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: pkg/sentry/strace/strace.proto + +package gvisor + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Strace struct { + Process string `protobuf:"bytes,1,opt,name=process,proto3" json:"process,omitempty"` + Function string `protobuf:"bytes,2,opt,name=function,proto3" json:"function,omitempty"` + Args []string `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty"` + // Types that are valid to be assigned to Info: + // *Strace_Enter + // *Strace_Exit + Info isStrace_Info `protobuf_oneof:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Strace) Reset() { *m = Strace{} } +func (m *Strace) String() string { return proto.CompactTextString(m) } +func (*Strace) ProtoMessage() {} +func (*Strace) Descriptor() ([]byte, []int) { + return fileDescriptor_50c4b43677c82b5f, []int{0} +} + +func (m *Strace) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Strace.Unmarshal(m, b) +} +func (m *Strace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Strace.Marshal(b, m, deterministic) +} +func (m *Strace) XXX_Merge(src proto.Message) { + xxx_messageInfo_Strace.Merge(m, src) +} +func (m *Strace) XXX_Size() int { + return xxx_messageInfo_Strace.Size(m) +} +func (m *Strace) XXX_DiscardUnknown() { + xxx_messageInfo_Strace.DiscardUnknown(m) +} + +var xxx_messageInfo_Strace proto.InternalMessageInfo + +func (m *Strace) GetProcess() string { + if m != nil { + return m.Process + } + return "" +} + +func (m *Strace) GetFunction() string { + if m != nil { + return m.Function + } + return "" +} + +func (m *Strace) GetArgs() []string { + if m != nil { + return m.Args + } + return nil +} + +type isStrace_Info interface { + isStrace_Info() +} + +type Strace_Enter struct { + Enter *StraceEnter `protobuf:"bytes,4,opt,name=enter,proto3,oneof"` +} + +type Strace_Exit struct { + Exit *StraceExit `protobuf:"bytes,5,opt,name=exit,proto3,oneof"` +} + +func (*Strace_Enter) isStrace_Info() {} + +func (*Strace_Exit) isStrace_Info() {} + +func (m *Strace) GetInfo() isStrace_Info { + if m != nil { + return m.Info + } + return nil +} + +func (m *Strace) GetEnter() *StraceEnter { + if x, ok := m.GetInfo().(*Strace_Enter); ok { + return x.Enter + } + return nil +} + +func (m *Strace) GetExit() *StraceExit { + if x, ok := m.GetInfo().(*Strace_Exit); ok { + return x.Exit + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Strace) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Strace_Enter)(nil), + (*Strace_Exit)(nil), + } +} + +type StraceEnter struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StraceEnter) Reset() { *m = StraceEnter{} } +func (m *StraceEnter) String() string { return proto.CompactTextString(m) } +func (*StraceEnter) ProtoMessage() {} +func (*StraceEnter) Descriptor() ([]byte, []int) { + return fileDescriptor_50c4b43677c82b5f, []int{1} +} + +func (m *StraceEnter) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StraceEnter.Unmarshal(m, b) +} +func (m *StraceEnter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StraceEnter.Marshal(b, m, deterministic) +} +func (m *StraceEnter) XXX_Merge(src proto.Message) { + xxx_messageInfo_StraceEnter.Merge(m, src) +} +func (m *StraceEnter) XXX_Size() int { + return xxx_messageInfo_StraceEnter.Size(m) +} +func (m *StraceEnter) XXX_DiscardUnknown() { + xxx_messageInfo_StraceEnter.DiscardUnknown(m) +} + +var xxx_messageInfo_StraceEnter proto.InternalMessageInfo + +type StraceExit struct { + Return string `protobuf:"bytes,1,opt,name=return,proto3" json:"return,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + ErrNo int64 `protobuf:"varint,3,opt,name=err_no,json=errNo,proto3" json:"err_no,omitempty"` + ElapsedNs int64 `protobuf:"varint,4,opt,name=elapsed_ns,json=elapsedNs,proto3" json:"elapsed_ns,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StraceExit) Reset() { *m = StraceExit{} } +func (m *StraceExit) String() string { return proto.CompactTextString(m) } +func (*StraceExit) ProtoMessage() {} +func (*StraceExit) Descriptor() ([]byte, []int) { + return fileDescriptor_50c4b43677c82b5f, []int{2} +} + +func (m *StraceExit) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StraceExit.Unmarshal(m, b) +} +func (m *StraceExit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StraceExit.Marshal(b, m, deterministic) +} +func (m *StraceExit) XXX_Merge(src proto.Message) { + xxx_messageInfo_StraceExit.Merge(m, src) +} +func (m *StraceExit) XXX_Size() int { + return xxx_messageInfo_StraceExit.Size(m) +} +func (m *StraceExit) XXX_DiscardUnknown() { + xxx_messageInfo_StraceExit.DiscardUnknown(m) +} + +var xxx_messageInfo_StraceExit proto.InternalMessageInfo + +func (m *StraceExit) GetReturn() string { + if m != nil { + return m.Return + } + return "" +} + +func (m *StraceExit) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +func (m *StraceExit) GetErrNo() int64 { + if m != nil { + return m.ErrNo + } + return 0 +} + +func (m *StraceExit) GetElapsedNs() int64 { + if m != nil { + return m.ElapsedNs + } + return 0 +} + +func init() { + proto.RegisterType((*Strace)(nil), "gvisor.Strace") + proto.RegisterType((*StraceEnter)(nil), "gvisor.StraceEnter") + proto.RegisterType((*StraceExit)(nil), "gvisor.StraceExit") +} + +func init() { proto.RegisterFile("pkg/sentry/strace/strace.proto", fileDescriptor_50c4b43677c82b5f) } + +var fileDescriptor_50c4b43677c82b5f = []byte{ + // 255 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0xdd, 0x4a, 0xf4, 0x30, + 0x10, 0x86, 0xb7, 0x5f, 0xdb, 0x7c, 0x76, 0x16, 0x4f, 0xc6, 0x1f, 0x82, 0xa0, 0x94, 0x1e, 0x05, + 0x84, 0x2e, 0xe8, 0x1d, 0x08, 0xc2, 0x1e, 0xed, 0x41, 0xbc, 0x80, 0xa5, 0xd6, 0xd9, 0x12, 0x94, + 0x24, 0x4c, 0xb2, 0xb2, 0x5e, 0x96, 0x77, 0x28, 0xa6, 0xf1, 0x07, 0x8f, 0x92, 0x67, 0xde, 0x87, + 0x0c, 0x6f, 0xe0, 0xca, 0x3f, 0x4f, 0xab, 0x40, 0x36, 0xf2, 0xdb, 0x2a, 0x44, 0x1e, 0x46, 0xca, + 0x47, 0xef, 0xd9, 0x45, 0x87, 0x62, 0x7a, 0x35, 0xc1, 0x71, 0xf7, 0x5e, 0x80, 0x78, 0x48, 0x01, + 0x4a, 0xf8, 0xef, 0xd9, 0x8d, 0x14, 0x82, 0x2c, 0xda, 0x42, 0x35, 0xfa, 0x0b, 0xf1, 0x02, 0x8e, + 0x76, 0x7b, 0x3b, 0x46, 0xe3, 0xac, 0xfc, 0x97, 0xa2, 0x6f, 0x46, 0x84, 0x6a, 0xe0, 0x29, 0xc8, + 0xb2, 0x2d, 0x55, 0xa3, 0xd3, 0x1d, 0xaf, 0xa1, 0x26, 0x1b, 0x89, 0x65, 0xd5, 0x16, 0x6a, 0x79, + 0x73, 0xd2, 0xcf, 0xcb, 0xfa, 0x79, 0xd1, 0xfd, 0x67, 0xb4, 0x5e, 0xe8, 0xd9, 0x41, 0x05, 0x15, + 0x1d, 0x4c, 0x94, 0x75, 0x72, 0xf1, 0x8f, 0x7b, 0x30, 0x71, 0xbd, 0xd0, 0xc9, 0xb8, 0x13, 0x50, + 0x19, 0xbb, 0x73, 0xdd, 0x31, 0x2c, 0x7f, 0xbd, 0xd4, 0x79, 0x80, 0x1f, 0x19, 0xcf, 0x41, 0x30, + 0xc5, 0x3d, 0xdb, 0x5c, 0x22, 0x13, 0x9e, 0x42, 0x4d, 0xcc, 0x8e, 0x73, 0x81, 0x19, 0xf0, 0x0c, + 0x04, 0x31, 0x6f, 0xad, 0x93, 0x65, 0x5b, 0xa8, 0x32, 0x8d, 0x37, 0x0e, 0x2f, 0x01, 0xe8, 0x65, + 0xf0, 0x81, 0x9e, 0xb6, 0x36, 0xa4, 0x16, 0xa5, 0x6e, 0xf2, 0x64, 0x13, 0x1e, 0x45, 0xfa, 0xc3, + 0xdb, 0x8f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x42, 0x9a, 0xbc, 0x81, 0x65, 0x01, 0x00, 0x00, +} diff --git a/pkg/sentry/strace/strace_state_autogen.go b/pkg/sentry/strace/strace_state_autogen.go new file mode 100755 index 000000000..9dc697ed6 --- /dev/null +++ b/pkg/sentry/strace/strace_state_autogen.go @@ -0,0 +1,4 @@ +// automatically generated by stateify. + +package strace + diff --git a/pkg/sentry/strace/syscalls.go b/pkg/sentry/strace/syscalls.go new file mode 100644 index 000000000..eae2d6c12 --- /dev/null +++ b/pkg/sentry/strace/syscalls.go @@ -0,0 +1,267 @@ +// Copyright 2018 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. + +package strace + +import ( + "gvisor.googlesource.com/gvisor/pkg/abi" + "gvisor.googlesource.com/gvisor/pkg/sentry/arch" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" +) + +// FormatSpecifier values describe how an individual syscall argument should be +// formatted. +type FormatSpecifier int + +// Valid FormatSpecifiers. +// +// Unless otherwise specified, values are formatted before syscall execution +// and not updated after syscall execution (the same value is output). +const ( + // Hex is just a hexadecimal number. + Hex FormatSpecifier = iota + + // Oct is just an octal number. + Oct + + // FD is a file descriptor. + FD + + // ReadBuffer is a buffer for a read-style call. The syscall return + // value is used for the length. + // + // Formatted after syscall execution. + ReadBuffer + + // WriteBuffer is a buffer for a write-style call. The following arg is + // used for the length. + // + // Contents omitted after syscall execution. + WriteBuffer + + // ReadIOVec is a pointer to a struct iovec for a writev-style call. + // The following arg is used for the length. The return value is used + // for the total length. + // + // Complete contents only formatted after syscall execution. + ReadIOVec + + // WriteIOVec is a pointer to a struct iovec for a writev-style call. + // The following arg is used for the length. + // + // Complete contents only formatted before syscall execution, omitted + // after. + WriteIOVec + + // IOVec is a generic pointer to a struct iovec. Contents are not dumped. + IOVec + + // SendMsgHdr is a pointer to a struct msghdr for a sendmsg-style call. + // Contents formatted only before syscall execution, omitted after. + SendMsgHdr + + // RecvMsgHdr is a pointer to a struct msghdr for a recvmsg-style call. + // Contents formatted only after syscall execution. + RecvMsgHdr + + // Path is a pointer to a char* path. + Path + + // PostPath is a pointer to a char* path, formatted after syscall + // execution. + PostPath + + // ExecveStringVector is a NULL-terminated array of strings. Enforces + // the maximum execve array length. + ExecveStringVector + + // PipeFDs is an array of two FDs, formatted after syscall execution. + PipeFDs + + // Uname is a pointer to a struct uname, formatted after syscall execution. + Uname + + // Stat is a pointer to a struct stat, formatted after syscall execution. + Stat + + // SockAddr is a pointer to a struct sockaddr. The following arg is + // used for length. + SockAddr + + // PostSockAddr is a pointer to a struct sockaddr, formatted after + // syscall execution. The following arg is a pointer to the socklen_t + // length. + PostSockAddr + + // SockLen is a pointer to a socklen_t, formatted before and after + // syscall execution. + SockLen + + // SockFamily is a socket protocol family value. + SockFamily + + // SockType is a socket type and flags value. + SockType + + // SockProtocol is a socket protocol value. Argument n-2 is the socket + // protocol family. + SockProtocol + + // SockFlags are socket flags. + SockFlags + + // Timespec is a pointer to a struct timespec. + Timespec + + // PostTimespec is a pointer to a struct timespec, formatted after + // syscall execution. + PostTimespec + + // UTimeTimespec is a pointer to a struct timespec. Formatting includes + // UTIME_NOW and UTIME_OMIT. + UTimeTimespec + + // ItimerVal is a pointer to a struct itimerval. + ItimerVal + + // PostItimerVal is a pointer to a struct itimerval, formatted after + // syscall execution. + PostItimerVal + + // ItimerSpec is a pointer to a struct itimerspec. + ItimerSpec + + // PostItimerSpec is a pointer to a struct itimerspec, formatted after + // syscall execution. + PostItimerSpec + + // Timeval is a pointer to a struct timeval, formatted before and after + // syscall execution. + Timeval + + // Utimbuf is a pointer to a struct utimbuf. + Utimbuf + + // Rusage is a struct rusage, formatted after syscall execution. + Rusage + + // CloneFlags are clone(2) flags. + CloneFlags + + // OpenFlags are open(2) flags. + OpenFlags + + // Mode is a mode_t. + Mode + + // FutexOp is the futex(2) operation. + FutexOp + + // PtraceRequest is the ptrace(2) request. + PtraceRequest + + // ItimerType is an itimer type (ITIMER_REAL, etc). + ItimerType + + // Signal is a signal number. + Signal + + // SignalMaskAction is a signal mask action passed to rt_sigprocmask(2). + SignalMaskAction + + // SigSet is a signal set. + SigSet + + // PostSigSet is a signal set, formatted after syscall execution. + PostSigSet + + // SigAction is a struct sigaction. + SigAction + + // PostSigAction is a struct sigaction, formatted after syscall execution. + PostSigAction + + // CapHeader is a cap_user_header_t. + CapHeader + + // CapData is the data argument to capget(2)/capset(2). The previous + // argument must be CapHeader. + CapData + + // PostCapData is the data argument to capget(2)/capset(2), formatted + // after syscall execution. The previous argument must be CapHeader. + PostCapData + + // PollFDs is an array of struct pollfd. The number of entries in the + // array is in the next argument. + PollFDs +) + +// defaultFormat is the syscall argument format to use if the actual format is +// not known. It formats all six arguments as hex. +var defaultFormat = []FormatSpecifier{Hex, Hex, Hex, Hex, Hex, Hex} + +// SyscallInfo captures the name and printing format of a syscall. +type SyscallInfo struct { + // name is the name of the syscall. + name string + + // format contains the format specifiers for each argument. + // + // Syscall calls can have up to six arguments. Arguments without a + // corresponding entry in format will not be printed. + format []FormatSpecifier +} + +// makeSyscallInfo returns a SyscallInfo for a syscall. +func makeSyscallInfo(name string, f ...FormatSpecifier) SyscallInfo { + return SyscallInfo{name: name, format: f} +} + +// SyscallMap maps syscalls into names and printing formats. +type SyscallMap map[uintptr]SyscallInfo + +var _ kernel.Stracer = (SyscallMap)(nil) + +// syscallTable contains the syscalls for a specific OS/Arch. +type syscallTable struct { + // os is the operating system this table targets. + os abi.OS + + // arch is the architecture this table targets. + arch arch.Arch + + // syscalls contains the syscall mappings. + syscalls SyscallMap +} + +// syscallTables contains all syscall tables. +var syscallTables = []syscallTable{ + { + os: abi.Linux, + arch: arch.AMD64, + syscalls: linuxAMD64, + }, +} + +// Lookup returns the SyscallMap for the OS/Arch combination. The returned map +// must not be changed. +func Lookup(os abi.OS, a arch.Arch) (SyscallMap, bool) { + for _, s := range syscallTables { + if s.os == os && s.arch == a { + return s.syscalls, true + } + } + return nil, false +} |