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