github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/cmd.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 cmd holds implementations of the runsc commands.
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  	"runtime"
    21  	"strconv"
    22  
    23  	specs "github.com/opencontainers/runtime-spec/specs-go"
    24  	"golang.org/x/sys/unix"
    25  	"github.com/SagerNet/gvisor/pkg/log"
    26  	"github.com/SagerNet/gvisor/runsc/specutils"
    27  )
    28  
    29  // intFlags can be used with int flags that appear multiple times.
    30  type intFlags []int
    31  
    32  // String implements flag.Value.
    33  func (i *intFlags) String() string {
    34  	return fmt.Sprintf("%v", *i)
    35  }
    36  
    37  // Get implements flag.Value.
    38  func (i *intFlags) Get() interface{} {
    39  	return i
    40  }
    41  
    42  // GetArray returns array of FDs.
    43  func (i *intFlags) GetArray() []int {
    44  	return *i
    45  }
    46  
    47  // Set implements flag.Value.
    48  func (i *intFlags) Set(s string) error {
    49  	fd, err := strconv.Atoi(s)
    50  	if err != nil {
    51  		return fmt.Errorf("invalid flag value: %v", err)
    52  	}
    53  	if fd < 0 {
    54  		return fmt.Errorf("flag value must be greater than 0: %d", fd)
    55  	}
    56  	*i = append(*i, fd)
    57  	return nil
    58  }
    59  
    60  // setCapsAndCallSelf sets capabilities to the current thread and then execve's
    61  // itself again with the arguments specified in 'args' to restart the process
    62  // with the desired capabilities.
    63  func setCapsAndCallSelf(args []string, caps *specs.LinuxCapabilities) error {
    64  	// Keep thread locked while capabilities are changed.
    65  	runtime.LockOSThread()
    66  	defer runtime.UnlockOSThread()
    67  
    68  	if err := applyCaps(caps); err != nil {
    69  		return fmt.Errorf("applyCaps() failed: %v", err)
    70  	}
    71  	binPath := specutils.ExePath
    72  
    73  	log.Infof("Execve %q again, bye!", binPath)
    74  	err := unix.Exec(binPath, args, []string{})
    75  	return fmt.Errorf("error executing %s: %v", binPath, err)
    76  }
    77  
    78  // callSelfAsNobody sets UID and GID to nobody and then execve's itself again.
    79  func callSelfAsNobody(args []string) error {
    80  	// Keep thread locked while user/group are changed.
    81  	runtime.LockOSThread()
    82  	defer runtime.UnlockOSThread()
    83  
    84  	const nobody = 65534
    85  
    86  	if _, _, err := unix.RawSyscall(unix.SYS_SETGID, uintptr(nobody), 0, 0); err != 0 {
    87  		return fmt.Errorf("error setting uid: %v", err)
    88  	}
    89  	if _, _, err := unix.RawSyscall(unix.SYS_SETUID, uintptr(nobody), 0, 0); err != 0 {
    90  		return fmt.Errorf("error setting gid: %v", err)
    91  	}
    92  
    93  	binPath := specutils.ExePath
    94  
    95  	log.Infof("Execve %q again, bye!", binPath)
    96  	err := unix.Exec(binPath, args, []string{})
    97  	return fmt.Errorf("error executing %s: %v", binPath, err)
    98  }