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 }