github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/syscalls/linux/sys_prctl.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 linux
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/marshal/primitive"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/mm"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs"
    28  )
    29  
    30  // Prctl implements linux syscall prctl(2).
    31  // It has a list of subfunctions which operate on the process. The arguments are
    32  // all based on each subfunction.
    33  func Prctl(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    34  	option := args[0].Int()
    35  
    36  	switch option {
    37  	case linux.PR_SET_PDEATHSIG:
    38  		sig := linux.Signal(args[1].Int())
    39  		if sig != 0 && !sig.IsValid() {
    40  			return 0, nil, linuxerr.EINVAL
    41  		}
    42  		t.SetParentDeathSignal(sig)
    43  		return 0, nil, nil
    44  
    45  	case linux.PR_GET_PDEATHSIG:
    46  		_, err := primitive.CopyInt32Out(t, args[1].Pointer(), int32(t.ParentDeathSignal()))
    47  		return 0, nil, err
    48  
    49  	case linux.PR_GET_DUMPABLE:
    50  		d := t.MemoryManager().Dumpability()
    51  		switch d {
    52  		case mm.NotDumpable:
    53  			return linux.SUID_DUMP_DISABLE, nil, nil
    54  		case mm.UserDumpable:
    55  			return linux.SUID_DUMP_USER, nil, nil
    56  		case mm.RootDumpable:
    57  			return linux.SUID_DUMP_ROOT, nil, nil
    58  		default:
    59  			panic(fmt.Sprintf("Unknown dumpability %v", d))
    60  		}
    61  
    62  	case linux.PR_SET_DUMPABLE:
    63  		var d mm.Dumpability
    64  		switch args[1].Int() {
    65  		case linux.SUID_DUMP_DISABLE:
    66  			d = mm.NotDumpable
    67  		case linux.SUID_DUMP_USER:
    68  			d = mm.UserDumpable
    69  		default:
    70  			// N.B. Userspace may not pass SUID_DUMP_ROOT.
    71  			return 0, nil, linuxerr.EINVAL
    72  		}
    73  		t.MemoryManager().SetDumpability(d)
    74  		return 0, nil, nil
    75  
    76  	case linux.PR_GET_KEEPCAPS:
    77  		if t.Credentials().KeepCaps {
    78  			return 1, nil, nil
    79  		}
    80  
    81  		return 0, nil, nil
    82  
    83  	case linux.PR_SET_KEEPCAPS:
    84  		val := args[1].Int()
    85  		// prctl(2): arg2 must be either 0 (permitted capabilities are cleared)
    86  		// or 1 (permitted capabilities are kept).
    87  		if val == 0 {
    88  			t.SetKeepCaps(false)
    89  		} else if val == 1 {
    90  			t.SetKeepCaps(true)
    91  		} else {
    92  			return 0, nil, linuxerr.EINVAL
    93  		}
    94  
    95  		return 0, nil, nil
    96  
    97  	case linux.PR_SET_NAME:
    98  		addr := args[1].Pointer()
    99  		name, err := t.CopyInString(addr, linux.TASK_COMM_LEN-1)
   100  		if err != nil && !linuxerr.Equals(linuxerr.ENAMETOOLONG, err) {
   101  			return 0, nil, err
   102  		}
   103  		t.SetName(name)
   104  
   105  	case linux.PR_GET_NAME:
   106  		addr := args[1].Pointer()
   107  		buf := t.CopyScratchBuffer(linux.TASK_COMM_LEN)
   108  		len := copy(buf, t.Name())
   109  		if len < linux.TASK_COMM_LEN {
   110  			buf[len] = 0
   111  			len++
   112  		}
   113  		_, err := t.CopyOutBytes(addr, buf[:len])
   114  		if err != nil {
   115  			return 0, nil, err
   116  		}
   117  
   118  	case linux.PR_SET_MM:
   119  		if !t.HasCapability(linux.CAP_SYS_RESOURCE) {
   120  			return 0, nil, linuxerr.EPERM
   121  		}
   122  
   123  		switch args[1].Int() {
   124  		case linux.PR_SET_MM_EXE_FILE:
   125  			fd := args[2].Int()
   126  
   127  			file := t.GetFile(fd)
   128  			if file == nil {
   129  				return 0, nil, linuxerr.EBADF
   130  			}
   131  			defer file.DecRef(t)
   132  
   133  			// They trying to set exe to a non-file?
   134  			stat, err := file.Stat(t, vfs.StatOptions{Mask: linux.STATX_TYPE})
   135  			if err != nil {
   136  				return 0, nil, err
   137  			}
   138  			if stat.Mask&linux.STATX_TYPE == 0 || stat.Mode&linux.FileTypeMask != linux.ModeRegular {
   139  				return 0, nil, linuxerr.EBADF
   140  			}
   141  
   142  			// Set the underlying executable.
   143  			t.MemoryManager().SetExecutable(t, file)
   144  
   145  		case linux.PR_SET_MM_AUXV,
   146  			linux.PR_SET_MM_START_CODE,
   147  			linux.PR_SET_MM_END_CODE,
   148  			linux.PR_SET_MM_START_DATA,
   149  			linux.PR_SET_MM_END_DATA,
   150  			linux.PR_SET_MM_START_STACK,
   151  			linux.PR_SET_MM_START_BRK,
   152  			linux.PR_SET_MM_BRK,
   153  			linux.PR_SET_MM_ARG_START,
   154  			linux.PR_SET_MM_ARG_END,
   155  			linux.PR_SET_MM_ENV_START,
   156  			linux.PR_SET_MM_ENV_END:
   157  
   158  			t.Kernel().EmitUnimplementedEvent(t, sysno)
   159  			fallthrough
   160  		default:
   161  			return 0, nil, linuxerr.EINVAL
   162  		}
   163  
   164  	case linux.PR_SET_NO_NEW_PRIVS:
   165  		if args[1].Int() != 1 || args[2].Int() != 0 || args[3].Int() != 0 || args[4].Int() != 0 {
   166  			return 0, nil, linuxerr.EINVAL
   167  		}
   168  		// PR_SET_NO_NEW_PRIVS is assumed to always be set.
   169  		// See kernel.Task.updateCredsForExecLocked.
   170  		return 0, nil, nil
   171  
   172  	case linux.PR_GET_NO_NEW_PRIVS:
   173  		if args[1].Int() != 0 || args[2].Int() != 0 || args[3].Int() != 0 || args[4].Int() != 0 {
   174  			return 0, nil, linuxerr.EINVAL
   175  		}
   176  		return 1, nil, nil
   177  
   178  	case linux.PR_SET_PTRACER:
   179  		pid := args[1].Int()
   180  		switch pid {
   181  		case 0:
   182  			t.ClearYAMAException()
   183  			return 0, nil, nil
   184  		case linux.PR_SET_PTRACER_ANY:
   185  			t.SetYAMAException(nil)
   186  			return 0, nil, nil
   187  		default:
   188  			tracer := t.PIDNamespace().TaskWithID(kernel.ThreadID(pid))
   189  			if tracer == nil {
   190  				return 0, nil, linuxerr.EINVAL
   191  			}
   192  			t.SetYAMAException(tracer)
   193  			return 0, nil, nil
   194  		}
   195  
   196  	case linux.PR_SET_SECCOMP:
   197  		if args[1].Int() != linux.SECCOMP_MODE_FILTER {
   198  			// Unsupported mode.
   199  			return 0, nil, linuxerr.EINVAL
   200  		}
   201  
   202  		return 0, nil, seccomp(t, linux.SECCOMP_SET_MODE_FILTER, 0, args[2].Pointer())
   203  
   204  	case linux.PR_GET_SECCOMP:
   205  		return uintptr(t.SeccompMode()), nil, nil
   206  
   207  	case linux.PR_CAPBSET_READ:
   208  		cp := linux.Capability(args[1].Uint64())
   209  		if !cp.Ok() {
   210  			return 0, nil, linuxerr.EINVAL
   211  		}
   212  		var rv uintptr
   213  		if auth.CapabilitySetOf(cp)&t.Credentials().BoundingCaps != 0 {
   214  			rv = 1
   215  		}
   216  		return rv, nil, nil
   217  
   218  	case linux.PR_CAPBSET_DROP:
   219  		cp := linux.Capability(args[1].Uint64())
   220  		if !cp.Ok() {
   221  			return 0, nil, linuxerr.EINVAL
   222  		}
   223  		return 0, nil, t.DropBoundingCapability(cp)
   224  
   225  	case linux.PR_SET_CHILD_SUBREAPER:
   226  		// "If arg2 is nonzero, set the "child subreaper" attribute of
   227  		// the calling process; if arg2 is zero, unset the attribute."
   228  		isSubreaper := args[1].Int() != 0
   229  		t.ThreadGroup().SetChildSubreaper(isSubreaper)
   230  		return 0, nil, nil
   231  
   232  	case linux.PR_GET_CHILD_SUBREAPER:
   233  		var isSubreaper int32
   234  		if t.ThreadGroup().IsChildSubreaper() {
   235  			isSubreaper = 1
   236  		}
   237  		_, err := primitive.CopyInt32Out(t, args[1].Pointer(), isSubreaper)
   238  		return 0, nil, err
   239  
   240  	case linux.PR_GET_TIMING,
   241  		linux.PR_SET_TIMING,
   242  		linux.PR_GET_TSC,
   243  		linux.PR_SET_TSC,
   244  		linux.PR_TASK_PERF_EVENTS_DISABLE,
   245  		linux.PR_TASK_PERF_EVENTS_ENABLE,
   246  		linux.PR_GET_TIMERSLACK,
   247  		linux.PR_SET_TIMERSLACK,
   248  		linux.PR_MCE_KILL,
   249  		linux.PR_MCE_KILL_GET,
   250  		linux.PR_GET_TID_ADDRESS,
   251  		linux.PR_GET_THP_DISABLE,
   252  		linux.PR_SET_THP_DISABLE,
   253  		linux.PR_MPX_ENABLE_MANAGEMENT,
   254  		linux.PR_MPX_DISABLE_MANAGEMENT:
   255  
   256  		t.Kernel().EmitUnimplementedEvent(t, sysno)
   257  		fallthrough
   258  	default:
   259  		return 0, nil, linuxerr.EINVAL
   260  	}
   261  
   262  	return 0, nil, nil
   263  }