github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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  	"os"
    21  	"runtime"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/MerlinKodo/gvisor/pkg/log"
    26  	"github.com/MerlinKodo/gvisor/runsc/specutils"
    27  	specs "github.com/opencontainers/runtime-spec/specs-go"
    28  	"golang.org/x/sys/unix"
    29  )
    30  
    31  // intFlags can be used with int flags that appear multiple times. It supports
    32  // comma-separated lists too.
    33  type intFlags []int
    34  
    35  // String implements flag.Value.
    36  func (i *intFlags) String() string {
    37  	sInts := make([]string, 0, len(*i))
    38  	for _, fd := range *i {
    39  		sInts = append(sInts, strconv.Itoa(fd))
    40  	}
    41  	return strings.Join(sInts, ",")
    42  }
    43  
    44  // Get implements flag.Value.
    45  func (i *intFlags) Get() any {
    46  	return i
    47  }
    48  
    49  // GetArray returns array of FDs.
    50  func (i *intFlags) GetArray() []int {
    51  	return *i
    52  }
    53  
    54  // Set implements flag.Value. Set(String()) should be idempotent.
    55  func (i *intFlags) Set(s string) error {
    56  	for _, sFD := range strings.Split(s, ",") {
    57  		fd, err := strconv.Atoi(sFD)
    58  		if err != nil {
    59  			return fmt.Errorf("invalid flag value: %v", err)
    60  		}
    61  		if fd < -1 {
    62  			return fmt.Errorf("flag value must be >= -1: %d", fd)
    63  		}
    64  		*i = append(*i, fd)
    65  	}
    66  	return nil
    67  }
    68  
    69  // setCapsAndCallSelf sets capabilities to the current thread and then execve's
    70  // itself again with the arguments specified in 'args' to restart the process
    71  // with the desired capabilities.
    72  func setCapsAndCallSelf(args []string, caps *specs.LinuxCapabilities) error {
    73  	// Keep thread locked while capabilities are changed.
    74  	runtime.LockOSThread()
    75  	defer runtime.UnlockOSThread()
    76  
    77  	if err := applyCaps(caps); err != nil {
    78  		return fmt.Errorf("applyCaps() failed: %v", err)
    79  	}
    80  	binPath := specutils.ExePath
    81  
    82  	log.Infof("Execve %q again, bye!", binPath)
    83  	err := unix.Exec(binPath, args, os.Environ())
    84  	return fmt.Errorf("error executing %s: %v", binPath, err)
    85  }
    86  
    87  // callSelfAsNobody sets UID and GID to nobody and then execve's itself again.
    88  func callSelfAsNobody(args []string) error {
    89  	// Keep thread locked while user/group are changed.
    90  	runtime.LockOSThread()
    91  	defer runtime.UnlockOSThread()
    92  
    93  	const nobody = 65534
    94  
    95  	if _, _, err := unix.RawSyscall(unix.SYS_SETGID, uintptr(nobody), 0, 0); err != 0 {
    96  		return fmt.Errorf("error setting uid: %v", err)
    97  	}
    98  	if _, _, err := unix.RawSyscall(unix.SYS_SETUID, uintptr(nobody), 0, 0); err != 0 {
    99  		return fmt.Errorf("error setting gid: %v", err)
   100  	}
   101  	// Drop all capabilities.
   102  	if err := applyCaps(&specs.LinuxCapabilities{}); err != nil {
   103  		return fmt.Errorf("error dropping capabilities: %w", err)
   104  	}
   105  
   106  	binPath := specutils.ExePath
   107  
   108  	log.Infof("Execve %q again, bye!", binPath)
   109  	err := unix.Exec(binPath, args, os.Environ())
   110  	return fmt.Errorf("error executing %s: %v", binPath, err)
   111  }