github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/strace/strace.go (about)

     1  // Copyright 2018 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 strace implements the logic to print out the input and the return value
    16  // of each traced syscall.
    17  package strace
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/abi"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/bits"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/eventchannel"
    29  	"github.com/nicocha30/gvisor-ligolo/pkg/marshal/primitive"
    30  	"github.com/nicocha30/gvisor-ligolo/pkg/seccomp"
    31  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch"
    32  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    33  	pb "github.com/nicocha30/gvisor-ligolo/pkg/sentry/strace/strace_go_proto"
    34  	slinux "github.com/nicocha30/gvisor-ligolo/pkg/sentry/syscalls/linux"
    35  
    36  	"github.com/nicocha30/gvisor-ligolo/pkg/hostarch"
    37  )
    38  
    39  // DefaultLogMaximumSize is the default LogMaximumSize.
    40  const DefaultLogMaximumSize = 1024
    41  
    42  // LogMaximumSize determines the maximum display size for data blobs (read,
    43  // write, etc.).
    44  var LogMaximumSize uint = DefaultLogMaximumSize
    45  
    46  // EventMaximumSize determines the maximum size for data blobs (read, write,
    47  // etc.) sent over the event channel. Default is 0 because most clients cannot
    48  // do anything useful with binary text dump of byte array arguments.
    49  var EventMaximumSize uint
    50  
    51  // LogAppDataAllowed is set to true when printing application data in strace
    52  // logs is allowed.
    53  var LogAppDataAllowed = true
    54  
    55  // ItimerTypes are the possible itimer types.
    56  var ItimerTypes = abi.ValueSet{
    57  	linux.ITIMER_REAL:    "ITIMER_REAL",
    58  	linux.ITIMER_VIRTUAL: "ITIMER_VIRTUAL",
    59  	linux.ITIMER_PROF:    "ITIMER_PROF",
    60  }
    61  
    62  func hexNum(num uint64) string {
    63  	return "0x" + strconv.FormatUint(num, 16)
    64  }
    65  
    66  func hexArg(arg arch.SyscallArgument) string {
    67  	return hexNum(arg.Uint64())
    68  }
    69  
    70  func iovecs(t *kernel.Task, addr hostarch.Addr, iovcnt int, printContent bool, maxBytes uint64) string {
    71  	if iovcnt < 0 || iovcnt > linux.UIO_MAXIOV {
    72  		return fmt.Sprintf("%#x (error decoding iovecs: invalid iovcnt)", addr)
    73  	}
    74  	ars, err := t.CopyInIovecs(addr, iovcnt)
    75  	if err != nil {
    76  		return fmt.Sprintf("%#x (error decoding iovecs: %v)", addr, err)
    77  	}
    78  
    79  	var totalBytes uint64
    80  	var truncated bool
    81  	iovs := make([]string, iovcnt)
    82  	for i := 0; !ars.IsEmpty(); i, ars = i+1, ars.Tail() {
    83  		ar := ars.Head()
    84  		if ar.Length() == 0 || !printContent {
    85  			iovs[i] = fmt.Sprintf("{base=%#x, len=%d}", ar.Start, ar.Length())
    86  			continue
    87  		}
    88  
    89  		size := uint64(ar.Length())
    90  		if truncated || totalBytes+size > maxBytes {
    91  			truncated = true
    92  			size = maxBytes - totalBytes
    93  		} else {
    94  			totalBytes += uint64(ar.Length())
    95  		}
    96  
    97  		b := make([]byte, size)
    98  		amt, err := t.CopyInBytes(ar.Start, b)
    99  		if err != nil {
   100  			iovs[i] = fmt.Sprintf("{base=%#x, len=%d, %q..., error decoding string: %v}", ar.Start, ar.Length(), b[:amt], err)
   101  			continue
   102  		}
   103  
   104  		dot := ""
   105  		if truncated {
   106  			// Indicate truncation.
   107  			dot = "..."
   108  		}
   109  		iovs[i] = fmt.Sprintf("{base=%#x, len=%d, %q%s}", ar.Start, ar.Length(), b[:amt], dot)
   110  	}
   111  
   112  	return fmt.Sprintf("%#x %s", addr, strings.Join(iovs, ", "))
   113  }
   114  
   115  func dump(t *kernel.Task, addr hostarch.Addr, size uint, maximumBlobSize uint, printContent bool) string {
   116  	if !printContent {
   117  		return fmt.Sprintf("{base=%#x, len=%d}", addr, size)
   118  	}
   119  	origSize := size
   120  	if size > maximumBlobSize {
   121  		size = maximumBlobSize
   122  	}
   123  	if size == 0 {
   124  		return ""
   125  	}
   126  
   127  	b := make([]byte, size)
   128  	amt, err := t.CopyInBytes(addr, b)
   129  	if err != nil {
   130  		return fmt.Sprintf("%#x (error decoding string: %s)", addr, err)
   131  	}
   132  
   133  	dot := ""
   134  	if uint(amt) < origSize {
   135  		// ... if we truncated the dump.
   136  		dot = "..."
   137  	}
   138  
   139  	return fmt.Sprintf("%#x %q%s", addr, b[:amt], dot)
   140  }
   141  
   142  func path(t *kernel.Task, addr hostarch.Addr) string {
   143  	if addr == 0 {
   144  		return "<null>"
   145  	}
   146  	path, err := t.CopyInString(addr, linux.PATH_MAX)
   147  	if err != nil {
   148  		return fmt.Sprintf("%#x (error decoding path: %s)", addr, err)
   149  	}
   150  	return fmt.Sprintf("%#x %s", addr, path)
   151  }
   152  
   153  func fd(t *kernel.Task, fd int32) string {
   154  	root := t.FSContext().RootDirectory()
   155  	defer root.DecRef(t)
   156  
   157  	vfsObj := root.Mount().Filesystem().VirtualFilesystem()
   158  	if fd == linux.AT_FDCWD {
   159  		wd := t.FSContext().WorkingDirectory()
   160  		defer wd.DecRef(t)
   161  
   162  		name, _ := vfsObj.PathnameWithDeleted(t, root, wd)
   163  		return fmt.Sprintf("AT_FDCWD %s", name)
   164  	}
   165  
   166  	file := t.GetFile(fd)
   167  	if file == nil {
   168  		// Cast FD to uint64 to avoid printing negative hex.
   169  		return fmt.Sprintf("%#x (bad FD)", uint64(fd))
   170  	}
   171  	defer file.DecRef(t)
   172  
   173  	name, _ := vfsObj.PathnameWithDeleted(t, root, file.VirtualDentry())
   174  	return fmt.Sprintf("%#x %s", fd, name)
   175  }
   176  
   177  func fdpair(t *kernel.Task, addr hostarch.Addr) string {
   178  	var fds [2]int32
   179  	_, err := primitive.CopyInt32SliceIn(t, addr, fds[:])
   180  	if err != nil {
   181  		return fmt.Sprintf("%#x (error decoding fds: %s)", addr, err)
   182  	}
   183  
   184  	return fmt.Sprintf("%#x [%d %d]", addr, fds[0], fds[1])
   185  }
   186  
   187  func uname(t *kernel.Task, addr hostarch.Addr) string {
   188  	var u linux.UtsName
   189  	if _, err := u.CopyIn(t, addr); err != nil {
   190  		return fmt.Sprintf("%#x (error decoding utsname: %s)", addr, err)
   191  	}
   192  
   193  	return fmt.Sprintf("%#x %s", addr, u)
   194  }
   195  
   196  func utimensTimespec(t *kernel.Task, addr hostarch.Addr) string {
   197  	if addr == 0 {
   198  		return "null"
   199  	}
   200  
   201  	var tim linux.Timespec
   202  	if _, err := tim.CopyIn(t, addr); err != nil {
   203  		return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err)
   204  	}
   205  
   206  	var ns string
   207  	switch tim.Nsec {
   208  	case linux.UTIME_NOW:
   209  		ns = "UTIME_NOW"
   210  	case linux.UTIME_OMIT:
   211  		ns = "UTIME_OMIT"
   212  	default:
   213  		ns = fmt.Sprintf("%v", tim.Nsec)
   214  	}
   215  	return fmt.Sprintf("%#x {sec=%v nsec=%s}", addr, tim.Sec, ns)
   216  }
   217  
   218  func timespec(t *kernel.Task, addr hostarch.Addr) string {
   219  	if addr == 0 {
   220  		return "null"
   221  	}
   222  
   223  	var tim linux.Timespec
   224  	if _, err := tim.CopyIn(t, addr); err != nil {
   225  		return fmt.Sprintf("%#x (error decoding timespec: %s)", addr, err)
   226  	}
   227  	return fmt.Sprintf("%#x {sec=%v nsec=%v}", addr, tim.Sec, tim.Nsec)
   228  }
   229  
   230  func timeval(t *kernel.Task, addr hostarch.Addr) string {
   231  	if addr == 0 {
   232  		return "null"
   233  	}
   234  
   235  	var tim linux.Timeval
   236  	if _, err := tim.CopyIn(t, addr); err != nil {
   237  		return fmt.Sprintf("%#x (error decoding timeval: %s)", addr, err)
   238  	}
   239  
   240  	return fmt.Sprintf("%#x {sec=%v usec=%v}", addr, tim.Sec, tim.Usec)
   241  }
   242  
   243  func utimbuf(t *kernel.Task, addr hostarch.Addr) string {
   244  	if addr == 0 {
   245  		return "null"
   246  	}
   247  
   248  	var utim linux.Utime
   249  	if _, err := utim.CopyIn(t, addr); err != nil {
   250  		return fmt.Sprintf("%#x (error decoding utimbuf: %s)", addr, err)
   251  	}
   252  
   253  	return fmt.Sprintf("%#x {actime=%v, modtime=%v}", addr, utim.Actime, utim.Modtime)
   254  }
   255  
   256  func stat(t *kernel.Task, addr hostarch.Addr) string {
   257  	if addr == 0 {
   258  		return "null"
   259  	}
   260  
   261  	var stat linux.Stat
   262  	if _, err := stat.CopyIn(t, addr); err != nil {
   263  		return fmt.Sprintf("%#x (error decoding stat: %s)", addr, err)
   264  	}
   265  	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))
   266  }
   267  
   268  func itimerval(t *kernel.Task, addr hostarch.Addr) string {
   269  	if addr == 0 {
   270  		return "null"
   271  	}
   272  
   273  	interval := timeval(t, addr)
   274  	value := timeval(t, addr+hostarch.Addr((*linux.Timeval)(nil).SizeBytes()))
   275  	return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value)
   276  }
   277  
   278  func itimerspec(t *kernel.Task, addr hostarch.Addr) string {
   279  	if addr == 0 {
   280  		return "null"
   281  	}
   282  
   283  	interval := timespec(t, addr)
   284  	value := timespec(t, addr+hostarch.Addr((*linux.Timespec)(nil).SizeBytes()))
   285  	return fmt.Sprintf("%#x {interval=%s, value=%s}", addr, interval, value)
   286  }
   287  
   288  func stringVector(t *kernel.Task, addr hostarch.Addr) string {
   289  	vec, err := t.CopyInVector(addr, slinux.ExecMaxElemSize, slinux.ExecMaxTotalSize)
   290  	if err != nil {
   291  		return fmt.Sprintf("%#x {error copying vector: %v}", addr, err)
   292  	}
   293  	s := fmt.Sprintf("%#x [", addr)
   294  	for i, v := range vec {
   295  		if i != 0 {
   296  			s += ", "
   297  		}
   298  		s += fmt.Sprintf("%q", v)
   299  	}
   300  	s += "]"
   301  	return s
   302  }
   303  
   304  func rusage(t *kernel.Task, addr hostarch.Addr) string {
   305  	if addr == 0 {
   306  		return "null"
   307  	}
   308  
   309  	var ru linux.Rusage
   310  	if _, err := ru.CopyIn(t, addr); err != nil {
   311  		return fmt.Sprintf("%#x (error decoding rusage: %s)", addr, err)
   312  	}
   313  	return fmt.Sprintf("%#x %+v", addr, ru)
   314  }
   315  
   316  func capHeader(t *kernel.Task, addr hostarch.Addr) string {
   317  	if addr == 0 {
   318  		return "null"
   319  	}
   320  
   321  	var hdr linux.CapUserHeader
   322  	if _, err := hdr.CopyIn(t, addr); err != nil {
   323  		return fmt.Sprintf("%#x (error decoding header: %s)", addr, err)
   324  	}
   325  
   326  	var version string
   327  	switch hdr.Version {
   328  	case linux.LINUX_CAPABILITY_VERSION_1:
   329  		version = "1"
   330  	case linux.LINUX_CAPABILITY_VERSION_2:
   331  		version = "2"
   332  	case linux.LINUX_CAPABILITY_VERSION_3:
   333  		version = "3"
   334  	default:
   335  		version = strconv.FormatUint(uint64(hdr.Version), 16)
   336  	}
   337  
   338  	return fmt.Sprintf("%#x {Version: %s, Pid: %d}", addr, version, hdr.Pid)
   339  }
   340  
   341  func capData(t *kernel.Task, hdrAddr, dataAddr hostarch.Addr) string {
   342  	if dataAddr == 0 {
   343  		return "null"
   344  	}
   345  
   346  	var hdr linux.CapUserHeader
   347  	if _, err := hdr.CopyIn(t, hdrAddr); err != nil {
   348  		return fmt.Sprintf("%#x (error decoding header: %v)", dataAddr, err)
   349  	}
   350  
   351  	var p, i, e uint64
   352  
   353  	switch hdr.Version {
   354  	case linux.LINUX_CAPABILITY_VERSION_1:
   355  		var data linux.CapUserData
   356  		if _, err := data.CopyIn(t, dataAddr); err != nil {
   357  			return fmt.Sprintf("%#x (error decoding data: %v)", dataAddr, err)
   358  		}
   359  		p = uint64(data.Permitted)
   360  		i = uint64(data.Inheritable)
   361  		e = uint64(data.Effective)
   362  	case linux.LINUX_CAPABILITY_VERSION_2, linux.LINUX_CAPABILITY_VERSION_3:
   363  		var data [2]linux.CapUserData
   364  		if _, err := linux.CopyCapUserDataSliceIn(t, dataAddr, data[:]); err != nil {
   365  			return fmt.Sprintf("%#x (error decoding data: %v)", dataAddr, err)
   366  		}
   367  		p = uint64(data[0].Permitted) | (uint64(data[1].Permitted) << 32)
   368  		i = uint64(data[0].Inheritable) | (uint64(data[1].Inheritable) << 32)
   369  		e = uint64(data[0].Effective) | (uint64(data[1].Effective) << 32)
   370  	default:
   371  		return fmt.Sprintf("%#x (unknown version %d)", dataAddr, hdr.Version)
   372  	}
   373  
   374  	return fmt.Sprintf("%#x {Permitted: %s, Inheritable: %s, Effective: %s}", dataAddr, CapabilityBitset.Parse(p), CapabilityBitset.Parse(i), CapabilityBitset.Parse(e))
   375  }
   376  
   377  // pre fills in the pre-execution arguments for a system call. If an argument
   378  // cannot be interpreted before the system call is executed, then a hex value
   379  // will be used. Note that a full output slice will always be provided, that is
   380  // len(return) == len(args).
   381  func (i *SyscallInfo) pre(t *kernel.Task, args arch.SyscallArguments, maximumBlobSize uint) []string {
   382  	var output []string
   383  
   384  	for arg := range args {
   385  		if arg >= len(i.format) {
   386  			break
   387  		}
   388  		switch i.format[arg] {
   389  		case FD:
   390  			output = append(output, fd(t, args[arg].Int()))
   391  		case WriteBuffer:
   392  			output = append(output, dump(t, args[arg].Pointer(), args[arg+1].SizeT(), maximumBlobSize, LogAppDataAllowed /* content */))
   393  		case WriteIOVec:
   394  			output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), LogAppDataAllowed /* content */, uint64(maximumBlobSize)))
   395  		case IOVec:
   396  			output = append(output, iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), false /* content */, uint64(maximumBlobSize)))
   397  		case SendMsgHdr:
   398  			output = append(output, msghdr(t, args[arg].Pointer(), LogAppDataAllowed /* content */, uint64(maximumBlobSize)))
   399  		case RecvMsgHdr:
   400  			output = append(output, msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize)))
   401  		case Path:
   402  			output = append(output, path(t, args[arg].Pointer()))
   403  		case ExecveStringVector:
   404  			output = append(output, stringVector(t, args[arg].Pointer()))
   405  		case SetSockOptVal:
   406  			output = append(output, sockOptVal(t, args[arg-2].Uint64() /* level */, args[arg-1].Uint64() /* optName */, args[arg].Pointer() /* optVal */, args[arg+1].Uint64() /* optLen */, maximumBlobSize))
   407  		case SockOptLevel:
   408  			output = append(output, sockOptLevels.Parse(args[arg].Uint64()))
   409  		case SockOptName:
   410  			output = append(output, sockOptNames[args[arg-1].Uint64() /* level */].Parse(args[arg].Uint64()))
   411  		case SockAddr:
   412  			output = append(output, sockAddr(t, args[arg].Pointer(), uint32(args[arg+1].Uint64())))
   413  		case SockLen:
   414  			output = append(output, sockLenPointer(t, args[arg].Pointer()))
   415  		case SockFamily:
   416  			output = append(output, SocketFamily.Parse(uint64(args[arg].Int())))
   417  		case SockType:
   418  			output = append(output, sockType(args[arg].Int()))
   419  		case SockProtocol:
   420  			output = append(output, sockProtocol(args[arg-2].Int(), args[arg].Int()))
   421  		case SockFlags:
   422  			output = append(output, sockFlags(args[arg].Int()))
   423  		case Timespec:
   424  			output = append(output, timespec(t, args[arg].Pointer()))
   425  		case UTimeTimespec:
   426  			output = append(output, utimensTimespec(t, args[arg].Pointer()))
   427  		case ItimerVal:
   428  			output = append(output, itimerval(t, args[arg].Pointer()))
   429  		case ItimerSpec:
   430  			output = append(output, itimerspec(t, args[arg].Pointer()))
   431  		case Timeval:
   432  			output = append(output, timeval(t, args[arg].Pointer()))
   433  		case Utimbuf:
   434  			output = append(output, utimbuf(t, args[arg].Pointer()))
   435  		case CloneFlags:
   436  			output = append(output, CloneFlagSet.Parse(uint64(args[arg].Uint())))
   437  		case OpenFlags:
   438  			output = append(output, open(uint64(args[arg].Uint())))
   439  		case Mode:
   440  			output = append(output, linux.FileMode(args[arg].ModeT()).String())
   441  		case FutexOp:
   442  			output = append(output, futex(uint64(args[arg].Uint())))
   443  		case PtraceRequest:
   444  			output = append(output, PtraceRequestSet.Parse(args[arg].Uint64()))
   445  		case ItimerType:
   446  			output = append(output, ItimerTypes.Parse(uint64(args[arg].Int())))
   447  		case Signal:
   448  			output = append(output, signalNames.ParseDecimal(args[arg].Uint64()))
   449  		case SignalMaskAction:
   450  			output = append(output, signalMaskActions.Parse(uint64(args[arg].Int())))
   451  		case SigSet:
   452  			output = append(output, sigSet(t, args[arg].Pointer()))
   453  		case SigAction:
   454  			output = append(output, sigAction(t, args[arg].Pointer()))
   455  		case CapHeader:
   456  			output = append(output, capHeader(t, args[arg].Pointer()))
   457  		case CapData:
   458  			output = append(output, capData(t, args[arg-1].Pointer(), args[arg].Pointer()))
   459  		case PollFDs:
   460  			output = append(output, pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), false))
   461  		case EpollCtlOp:
   462  			output = append(output, epollCtlOps.Parse(uint64(args[arg].Int())))
   463  		case EpollEvent:
   464  			output = append(output, epollEvent(t, args[arg].Pointer()))
   465  		case EpollEvents:
   466  			output = append(output, epollEvents(t, args[arg].Pointer(), 0 /* numEvents */, uint64(maximumBlobSize)))
   467  		case SelectFDSet:
   468  			output = append(output, fdSet(t, int(args[0].Int()), args[arg].Pointer()))
   469  		case MmapProt:
   470  			output = append(output, ProtectionFlagSet.Parse(uint64(args[arg].Uint())))
   471  		case MmapFlags:
   472  			output = append(output, MmapFlagSet.Parse(uint64(args[arg].Uint())))
   473  		case CloseRangeFlags:
   474  			output = append(output, CloseRangeFlagSet.Parse(uint64(args[arg].Uint())))
   475  		case Oct:
   476  			output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8))
   477  		case Hex:
   478  			fallthrough
   479  		default:
   480  			output = append(output, hexArg(args[arg]))
   481  		}
   482  	}
   483  
   484  	return output
   485  }
   486  
   487  // post fills in the post-execution arguments for a system call. This modifies
   488  // the given output slice in place with arguments that may only be interpreted
   489  // after the system call has been executed.
   490  func (i *SyscallInfo) post(t *kernel.Task, args arch.SyscallArguments, rval uintptr, output []string, maximumBlobSize uint) {
   491  	for arg := range output {
   492  		if arg >= len(i.format) {
   493  			break
   494  		}
   495  		switch i.format[arg] {
   496  		case ReadBuffer:
   497  			output[arg] = dump(t, args[arg].Pointer(), uint(rval), maximumBlobSize, LogAppDataAllowed /* content */)
   498  		case ReadIOVec:
   499  			printLength := uint64(rval)
   500  			if printLength > uint64(maximumBlobSize) {
   501  				printLength = uint64(maximumBlobSize)
   502  			}
   503  			output[arg] = iovecs(t, args[arg].Pointer(), int(args[arg+1].Int()), LogAppDataAllowed /* content */, printLength)
   504  		case WriteIOVec, IOVec, WriteBuffer:
   505  			// We already have a big blast from write.
   506  			output[arg] = "..."
   507  		case SendMsgHdr:
   508  			output[arg] = msghdr(t, args[arg].Pointer(), false /* content */, uint64(maximumBlobSize))
   509  		case RecvMsgHdr:
   510  			output[arg] = msghdr(t, args[arg].Pointer(), LogAppDataAllowed /* content */, uint64(maximumBlobSize))
   511  		case PostPath:
   512  			output[arg] = path(t, args[arg].Pointer())
   513  		case PipeFDs:
   514  			output[arg] = fdpair(t, args[arg].Pointer())
   515  		case Uname:
   516  			output[arg] = uname(t, args[arg].Pointer())
   517  		case Stat:
   518  			output[arg] = stat(t, args[arg].Pointer())
   519  		case PostSockAddr:
   520  			output[arg] = postSockAddr(t, args[arg].Pointer(), args[arg+1].Pointer())
   521  		case SockLen:
   522  			output[arg] = sockLenPointer(t, args[arg].Pointer())
   523  		case PostTimespec:
   524  			output[arg] = timespec(t, args[arg].Pointer())
   525  		case PostItimerVal:
   526  			output[arg] = itimerval(t, args[arg].Pointer())
   527  		case PostItimerSpec:
   528  			output[arg] = itimerspec(t, args[arg].Pointer())
   529  		case Timeval:
   530  			output[arg] = timeval(t, args[arg].Pointer())
   531  		case Rusage:
   532  			output[arg] = rusage(t, args[arg].Pointer())
   533  		case PostSigSet:
   534  			output[arg] = sigSet(t, args[arg].Pointer())
   535  		case PostSigAction:
   536  			output[arg] = sigAction(t, args[arg].Pointer())
   537  		case PostCapData:
   538  			output[arg] = capData(t, args[arg-1].Pointer(), args[arg].Pointer())
   539  		case PollFDs:
   540  			output[arg] = pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), true)
   541  		case EpollEvents:
   542  			output[arg] = epollEvents(t, args[arg].Pointer(), uint64(rval), uint64(maximumBlobSize))
   543  		case GetSockOptVal:
   544  			output[arg] = getSockOptVal(t, args[arg-2].Uint64() /* level */, args[arg-1].Uint64() /* optName */, args[arg].Pointer() /* optVal */, args[arg+1].Pointer() /* optLen */, maximumBlobSize, rval)
   545  		case SetSockOptVal:
   546  			// No need to print the value again. While it usually
   547  			// isn't, the string version of this arg can be long.
   548  			output[arg] = hexArg(args[arg])
   549  		}
   550  	}
   551  }
   552  
   553  // printEntry prints the given system call entry.
   554  func (i *SyscallInfo) printEnter(t *kernel.Task, args arch.SyscallArguments) []string {
   555  	output := i.pre(t, args, LogMaximumSize)
   556  
   557  	switch len(output) {
   558  	case 0:
   559  		t.Infof("%s E %s()", t.Name(), i.name)
   560  	case 1:
   561  		t.Infof("%s E %s(%s)", t.Name(), i.name,
   562  			output[0])
   563  	case 2:
   564  		t.Infof("%s E %s(%s, %s)", t.Name(), i.name,
   565  			output[0], output[1])
   566  	case 3:
   567  		t.Infof("%s E %s(%s, %s, %s)", t.Name(), i.name,
   568  			output[0], output[1], output[2])
   569  	case 4:
   570  		t.Infof("%s E %s(%s, %s, %s, %s)", t.Name(), i.name,
   571  			output[0], output[1], output[2], output[3])
   572  	case 5:
   573  		t.Infof("%s E %s(%s, %s, %s, %s, %s)", t.Name(), i.name,
   574  			output[0], output[1], output[2], output[3], output[4])
   575  	case 6:
   576  		t.Infof("%s E %s(%s, %s, %s, %s, %s, %s)", t.Name(), i.name,
   577  			output[0], output[1], output[2], output[3], output[4], output[5])
   578  	}
   579  
   580  	return output
   581  }
   582  
   583  // printExit prints the given system call exit.
   584  func (i *SyscallInfo) printExit(t *kernel.Task, elapsed time.Duration, output []string, args arch.SyscallArguments, retval uintptr, err error, errno int) {
   585  	var rval string
   586  	if err == nil {
   587  		// Fill in the output after successful execution.
   588  		i.post(t, args, retval, output, LogMaximumSize)
   589  		rval = fmt.Sprintf("%d (%#x) (%v)", retval, retval, elapsed)
   590  	} else {
   591  		rval = fmt.Sprintf("%d (%#x) errno=%d (%s) (%v)", retval, retval, errno, err, elapsed)
   592  	}
   593  
   594  	switch len(output) {
   595  	case 0:
   596  		t.Infof("%s X %s() = %s", t.Name(), i.name,
   597  			rval)
   598  	case 1:
   599  		t.Infof("%s X %s(%s) = %s", t.Name(), i.name,
   600  			output[0], rval)
   601  	case 2:
   602  		t.Infof("%s X %s(%s, %s) = %s", t.Name(), i.name,
   603  			output[0], output[1], rval)
   604  	case 3:
   605  		t.Infof("%s X %s(%s, %s, %s) = %s", t.Name(), i.name,
   606  			output[0], output[1], output[2], rval)
   607  	case 4:
   608  		t.Infof("%s X %s(%s, %s, %s, %s) = %s", t.Name(), i.name,
   609  			output[0], output[1], output[2], output[3], rval)
   610  	case 5:
   611  		t.Infof("%s X %s(%s, %s, %s, %s, %s) = %s", t.Name(), i.name,
   612  			output[0], output[1], output[2], output[3], output[4], rval)
   613  	case 6:
   614  		t.Infof("%s X %s(%s, %s, %s, %s, %s, %s) = %s", t.Name(), i.name,
   615  			output[0], output[1], output[2], output[3], output[4], output[5], rval)
   616  	}
   617  }
   618  
   619  // sendEnter sends the syscall enter to event log.
   620  func (i *SyscallInfo) sendEnter(t *kernel.Task, args arch.SyscallArguments) []string {
   621  	output := i.pre(t, args, EventMaximumSize)
   622  
   623  	event := pb.Strace{
   624  		Process:  t.Name(),
   625  		Function: i.name,
   626  		Info: &pb.Strace_Enter{
   627  			Enter: &pb.StraceEnter{},
   628  		},
   629  	}
   630  	for _, arg := range output {
   631  		event.Args = append(event.Args, arg)
   632  	}
   633  	eventchannel.Emit(&event)
   634  
   635  	return output
   636  }
   637  
   638  // sendExit sends the syscall exit to event log.
   639  func (i *SyscallInfo) sendExit(t *kernel.Task, elapsed time.Duration, output []string, args arch.SyscallArguments, rval uintptr, err error, errno int) {
   640  	if err == nil {
   641  		// Fill in the output after successful execution.
   642  		i.post(t, args, rval, output, EventMaximumSize)
   643  	}
   644  
   645  	exit := &pb.StraceExit{
   646  		Return:    fmt.Sprintf("%#x", rval),
   647  		ElapsedNs: elapsed.Nanoseconds(),
   648  	}
   649  	if err != nil {
   650  		exit.Error = err.Error()
   651  		exit.ErrNo = int64(errno)
   652  	}
   653  	event := pb.Strace{
   654  		Process:  t.Name(),
   655  		Function: i.name,
   656  		Info:     &pb.Strace_Exit{Exit: exit},
   657  	}
   658  	for _, arg := range output {
   659  		event.Args = append(event.Args, arg)
   660  	}
   661  	eventchannel.Emit(&event)
   662  }
   663  
   664  type syscallContext struct {
   665  	info        SyscallInfo
   666  	args        arch.SyscallArguments
   667  	start       time.Time
   668  	logOutput   []string
   669  	eventOutput []string
   670  	flags       uint32
   671  }
   672  
   673  // SyscallEnter implements kernel.Stracer.SyscallEnter. It logs the syscall
   674  // entry trace.
   675  func (s SyscallMap) SyscallEnter(t *kernel.Task, sysno uintptr, args arch.SyscallArguments, flags uint32) any {
   676  	info, ok := s[sysno]
   677  	if !ok {
   678  		info = SyscallInfo{
   679  			name:   fmt.Sprintf("sys_%d", sysno),
   680  			format: defaultFormat,
   681  		}
   682  	}
   683  
   684  	var output, eventOutput []string
   685  	if bits.IsOn32(flags, kernel.StraceEnableLog) {
   686  		output = info.printEnter(t, args)
   687  	}
   688  	if bits.IsOn32(flags, kernel.StraceEnableEvent) {
   689  		eventOutput = info.sendEnter(t, args)
   690  	}
   691  
   692  	return &syscallContext{
   693  		info:        info,
   694  		args:        args,
   695  		start:       time.Now(),
   696  		logOutput:   output,
   697  		eventOutput: eventOutput,
   698  		flags:       flags,
   699  	}
   700  }
   701  
   702  // SyscallExit implements kernel.Stracer.SyscallExit. It logs the syscall
   703  // exit trace.
   704  func (s SyscallMap) SyscallExit(context any, t *kernel.Task, sysno, rval uintptr, err error) {
   705  	errno := kernel.ExtractErrno(err, int(sysno))
   706  	c := context.(*syscallContext)
   707  
   708  	elapsed := time.Since(c.start)
   709  	if bits.IsOn32(c.flags, kernel.StraceEnableLog) {
   710  		c.info.printExit(t, elapsed, c.logOutput, c.args, rval, err, errno)
   711  	}
   712  	if bits.IsOn32(c.flags, kernel.StraceEnableEvent) {
   713  		c.info.sendExit(t, elapsed, c.eventOutput, c.args, rval, err, errno)
   714  	}
   715  }
   716  
   717  // ConvertToSysnoMap converts the names to a map keyed on the syscall number
   718  // and value set to true.
   719  //
   720  // The map is in a convenient format to pass to SyscallFlagsTable.Enable().
   721  func (s SyscallMap) ConvertToSysnoMap(syscalls []string) (map[uintptr]bool, error) {
   722  	if syscalls == nil {
   723  		// Sentinel: no list.
   724  		return nil, nil
   725  	}
   726  
   727  	l := make(map[uintptr]bool)
   728  	for _, sc := range syscalls {
   729  		// Try to match this system call.
   730  		sysno, ok := s.ConvertToSysno(sc)
   731  		if !ok {
   732  			return nil, fmt.Errorf("syscall %q not found", sc)
   733  		}
   734  		l[sysno] = true
   735  	}
   736  
   737  	// Success.
   738  	return l, nil
   739  }
   740  
   741  // ConvertToSysno converts the name to system call number. Returns false
   742  // if syscall with same name is not found.
   743  func (s SyscallMap) ConvertToSysno(syscall string) (uintptr, bool) {
   744  	for sysno, info := range s {
   745  		if info.name != "" && info.name == syscall {
   746  			return sysno, true
   747  		}
   748  	}
   749  	return 0, false
   750  }
   751  
   752  // Name returns the syscall name.
   753  func (s SyscallMap) Name(sysno uintptr) string {
   754  	if info, ok := s[sysno]; ok {
   755  		return info.name
   756  	}
   757  	return fmt.Sprintf("sys_%d", sysno)
   758  }
   759  
   760  // Initialize prepares all syscall tables for use by this package.
   761  //
   762  // N.B. This is not in an init function because we can't be sure all syscall
   763  // tables are registered with the kernel when init runs.
   764  func Initialize() {
   765  	for _, table := range kernel.SyscallTables() {
   766  		// Is this known?
   767  		sys, ok := Lookup(table.OS, table.Arch)
   768  		if !ok {
   769  			continue
   770  		}
   771  
   772  		table.Stracer = sys
   773  	}
   774  }
   775  
   776  // SinkType defines where to send straces to.
   777  type SinkType uint32
   778  
   779  const (
   780  	// SinkTypeLog sends straces to text log
   781  	SinkTypeLog SinkType = 1 << iota
   782  
   783  	// SinkTypeEvent sends strace to event log
   784  	SinkTypeEvent
   785  )
   786  
   787  func convertToSyscallFlag(sinks SinkType) uint32 {
   788  	ret := uint32(0)
   789  	if bits.IsOn32(uint32(sinks), uint32(SinkTypeLog)) {
   790  		ret |= kernel.StraceEnableLog
   791  	}
   792  	if bits.IsOn32(uint32(sinks), uint32(SinkTypeEvent)) {
   793  		ret |= kernel.StraceEnableEvent
   794  	}
   795  	return ret
   796  }
   797  
   798  // Enable enables the syscalls in allowlist in all syscall tables.
   799  //
   800  // Preconditions: Initialize has been called.
   801  func Enable(allowlist []string, sinks SinkType) error {
   802  	flags := convertToSyscallFlag(sinks)
   803  	for _, table := range kernel.SyscallTables() {
   804  		// Is this known?
   805  		sys, ok := Lookup(table.OS, table.Arch)
   806  		if !ok {
   807  			continue
   808  		}
   809  
   810  		// Convert to a set of system calls numbers.
   811  		wl, err := sys.ConvertToSysnoMap(allowlist)
   812  		if err != nil {
   813  			return err
   814  		}
   815  
   816  		table.FeatureEnable.Enable(flags, wl, true)
   817  	}
   818  
   819  	// Done.
   820  	return nil
   821  }
   822  
   823  // Disable will disable Strace for all system calls and missing syscalls.
   824  //
   825  // Preconditions: Initialize has been called.
   826  func Disable(sinks SinkType) {
   827  	flags := convertToSyscallFlag(sinks)
   828  	for _, table := range kernel.SyscallTables() {
   829  		// Strace will be disabled for all syscalls including missing.
   830  		table.FeatureEnable.Enable(flags, nil, false)
   831  	}
   832  }
   833  
   834  // EnableAll enables all syscalls in all syscall tables.
   835  //
   836  // Preconditions: Initialize has been called.
   837  func EnableAll(sinks SinkType) {
   838  	flags := convertToSyscallFlag(sinks)
   839  	for _, table := range kernel.SyscallTables() {
   840  		// Is this known?
   841  		if _, ok := Lookup(table.OS, table.Arch); !ok {
   842  			continue
   843  		}
   844  
   845  		table.FeatureEnable.EnableAll(flags)
   846  	}
   847  }
   848  
   849  func init() {
   850  	t, ok := Lookup(abi.Host, arch.Host)
   851  	if ok {
   852  		// Provide the native table as the lookup for seccomp
   853  		// debugging. This is best-effort. This is provided this way to
   854  		// avoid dependencies from seccomp to this package.
   855  		seccomp.SyscallName = t.Name
   856  	}
   857  }