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