gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/platform/systrap/subprocess_unsafe.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 //go:build go1.18 16 // +build go1.18 17 18 // //go:linkname directives type-checked by checklinkname. Any other 19 // non-linkname assumptions outside the Go 1 compatibility guarantee should 20 // have an accompanied vet check or version guard build tag. 21 22 package systrap 23 24 import ( 25 "fmt" 26 "unsafe" 27 28 "golang.org/x/sys/unix" 29 "gvisor.dev/gvisor/pkg/abi/linux" 30 "gvisor.dev/gvisor/pkg/log" 31 "gvisor.dev/gvisor/pkg/sentry/arch" 32 "gvisor.dev/gvisor/pkg/sentry/memmap" 33 "gvisor.dev/gvisor/pkg/sentry/pgalloc" 34 "gvisor.dev/gvisor/pkg/sentry/platform/systrap/sysmsg" 35 ) 36 37 //go:linkname beforeFork syscall.runtime_BeforeFork 38 func beforeFork() 39 40 //go:linkname afterFork syscall.runtime_AfterFork 41 func afterFork() 42 43 //go:linkname afterForkInChild syscall.runtime_AfterForkInChild 44 func afterForkInChild() 45 46 // cputicks is implemented in assembly. 47 func cputicks() int64 48 49 // spinloop is implemented in assembly. 50 func spinloop() 51 52 // getThreadContextFromID returns a ThreadContext struct that corresponds to the 53 // given ID. 54 // 55 // Precondition: cid must be a valid thread context ID that has a mapping for it 56 // that exists in s.contexts. 57 func (s *subprocess) getThreadContextFromID(cid uint64) *sysmsg.ThreadContext { 58 tcSlot := s.threadContextRegion + uintptr(cid)*sysmsg.AllocatedSizeofThreadContextStruct 59 return (*sysmsg.ThreadContext)(unsafe.Pointer(tcSlot)) 60 } 61 62 func mmapContextQueueForSentry(memoryFile *pgalloc.MemoryFile, opts pgalloc.AllocOpts) (memmap.FileRange, *contextQueue) { 63 fr, err := memoryFile.Allocate(uint64(stubContextQueueRegionLen), opts) 64 if err != nil { 65 panic(fmt.Sprintf("failed to allocate a new subprocess context memory region")) 66 } 67 addr, _, errno := unix.RawSyscall6( 68 unix.SYS_MMAP, 69 0, 70 uintptr(fr.Length()), 71 unix.PROT_WRITE|unix.PROT_READ, 72 unix.MAP_SHARED|unix.MAP_FILE, 73 uintptr(memoryFile.FD()), uintptr(fr.Start)) 74 if errno != 0 { 75 panic(fmt.Sprintf("mmap failed for subprocess context memory region: %v", errno)) 76 } 77 78 return fr, (*contextQueue)(unsafe.Pointer(addr)) 79 } 80 81 func saveFPState(ctx *sharedContext, ac *arch.Context64) { 82 fpState := ac.FloatingPointData().BytePointer() 83 dst := unsafeSlice(uintptr(unsafe.Pointer(fpState)), archState.FpLen()) 84 src := ctx.shared.FPState[:] 85 copy(dst, src) 86 } 87 88 // restoreFPStateDecoupledContext writes FPState from c to the thread context 89 // shared memory region if there is any need to do so. 90 func restoreFPState(ctx *sharedContext, c *platformContext, ac *arch.Context64) { 91 if !c.needRestoreFPState { 92 return 93 } 94 c.needRestoreFPState = false 95 ctx.setFPStateChanged() 96 97 fpState := ac.FloatingPointData().BytePointer() 98 src := unsafeSlice(uintptr(unsafe.Pointer(fpState)), archState.FpLen()) 99 dst := ctx.shared.FPState[:] 100 copy(dst, src) 101 } 102 103 // alive returns true if the subprocess is alive. 104 func (s *subprocess) alive() bool { 105 if s.dead.Load() { 106 return false 107 } 108 109 // Wait4 doesn't support WNOWAIT, but here is no other way to find out 110 // whether a process exited or was stopped by ptrace. 111 siginfo := linux.SignalInfo{} 112 _, _, errno := unix.Syscall6( 113 unix.SYS_WAITID, 114 unix.P_PID, 115 uintptr(s.syscallThread.thread.tid), 116 uintptr(unsafe.Pointer(&siginfo)), 117 uintptr(unix.WEXITED|unix.WNOHANG|unix.WNOWAIT), 118 0, 0) 119 if errno == 0 && siginfo.PID() == 0 { 120 return true 121 } 122 if errno == 0 && siginfo.Code != linux.CLD_EXITED && siginfo.Code != linux.CLD_KILLED { 123 return true 124 } 125 126 // The process is dead, let's collect its zombie. 127 wstatus := unix.WaitStatus(0) 128 pid, err := unix.Wait4(int(s.syscallThread.thread.tid), &wstatus, unix.WNOHANG, nil) 129 log.Warningf("the subprocess %d exited (status: %s, err %s)", pid, wstatus, err) 130 s.dead.Store(true) 131 return false 132 }