github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/platform/systrap/sysmsg_thread.go (about) 1 // Copyright 2020 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 systrap 16 17 import ( 18 "fmt" 19 20 "golang.org/x/sys/unix" 21 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 22 "github.com/nicocha30/gvisor-ligolo/pkg/log" 23 "github.com/nicocha30/gvisor-ligolo/pkg/seccomp" 24 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 25 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/memmap" 26 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/platform/systrap/sysmsg" 27 ) 28 29 // sysmsgThread describes a sysmsg stub thread which isn't traced 30 // and communicates with the Sentry via the sysmsg protocol. 31 // 32 // This type of thread is used to execute user processes. 33 type sysmsgThread struct { 34 // subproc is a link to the subprocess which is used to call native 35 // system calls. 36 subproc *subprocess 37 38 // thread is a thread identifier. 39 thread *thread 40 41 // msg is a pointer to a shared sysmsg structure in the Sentry address 42 // space which is used to communicate with the thread. 43 msg *sysmsg.Msg 44 45 // context is the last context that ran on this thread. 46 context *context 47 48 // stackRange is a sysmsg stack in the memory file. 49 stackRange memmap.FileRange 50 51 // fpuStateToMsgOffset is the offset of a thread fpu state relative to sysmsg. 52 fpuStateToMsgOffset uint64 53 } 54 55 // sysmsgPerThreadMemAddr returns a sysmsg stack address in the thread address 56 // space. 57 func (p *sysmsgThread) sysmsgPerThreadMemAddr() uintptr { 58 return stubSysmsgStack + sysmsg.PerThreadMemSize*uintptr(p.thread.sysmsgStackID) 59 } 60 61 // mapStack maps a sysmsg stack into the thread address space. 62 func (p *sysmsgThread) mapStack(addr uintptr, readOnly bool) error { 63 prot := uintptr(unix.PROT_READ) 64 if !readOnly { 65 prot |= unix.PROT_WRITE 66 } 67 _, err := p.thread.syscallIgnoreInterrupt(&p.thread.initRegs, unix.SYS_MMAP, 68 arch.SyscallArgument{Value: addr}, 69 arch.SyscallArgument{Value: uintptr(p.stackRange.Length())}, 70 arch.SyscallArgument{Value: prot}, 71 arch.SyscallArgument{Value: unix.MAP_SHARED | unix.MAP_FILE | unix.MAP_FIXED}, 72 arch.SyscallArgument{Value: uintptr(p.subproc.memoryFile.FD())}, 73 arch.SyscallArgument{Value: uintptr(p.stackRange.Start)}) 74 return err 75 } 76 77 // mapPrivateStack maps a private stack into the thread address space. 78 func (p *sysmsgThread) mapPrivateStack(addr uintptr, size uintptr) error { 79 prot := uintptr(unix.PROT_READ | unix.PROT_WRITE) 80 _, err := p.thread.syscallIgnoreInterrupt(&p.thread.initRegs, unix.SYS_MMAP, 81 arch.SyscallArgument{Value: addr}, 82 arch.SyscallArgument{Value: size}, 83 arch.SyscallArgument{Value: prot}, 84 arch.SyscallArgument{Value: unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_FIXED}, 85 arch.SyscallArgument{Value: 0}, 86 arch.SyscallArgument{Value: 0}) 87 return err 88 } 89 90 func (p *sysmsgThread) Debugf(format string, v ...any) { 91 if !log.IsLogging(log.Debug) { 92 return 93 } 94 msg := p.msg 95 postfix := fmt.Sprintf(": %s", msg) 96 p.thread.Debugf(format+postfix, v...) 97 } 98 99 func sysmsgThreadRules(stubStart uintptr) []linux.BPFInstruction { 100 rules := []seccomp.RuleSet{} 101 rules = appendSysThreadArchSeccompRules(rules) 102 rules = append(rules, []seccomp.RuleSet{ 103 // Allow instructions from the sysmsg code stub, which is limited by one page. 104 { 105 Rules: seccomp.SyscallRules{ 106 unix.SYS_FUTEX: { 107 { 108 seccomp.GreaterThan(stubStart), 109 seccomp.EqualTo(linux.FUTEX_WAKE), 110 seccomp.EqualTo(1), 111 seccomp.EqualTo(0), 112 seccomp.EqualTo(0), 113 seccomp.EqualTo(0), 114 seccomp.GreaterThan(stubStart), // rip 115 }, 116 { 117 seccomp.GreaterThan(stubStart), 118 seccomp.EqualTo(linux.FUTEX_WAIT), 119 seccomp.MatchAny{}, 120 seccomp.EqualTo(0), 121 seccomp.EqualTo(0), 122 seccomp.EqualTo(0), 123 seccomp.GreaterThan(stubStart), // rip 124 }, 125 }, 126 unix.SYS_RT_SIGRETURN: { 127 { 128 seccomp.MatchAny{}, 129 seccomp.MatchAny{}, 130 seccomp.MatchAny{}, 131 seccomp.MatchAny{}, 132 seccomp.MatchAny{}, 133 seccomp.MatchAny{}, 134 seccomp.GreaterThan(stubStart), // rip 135 }, 136 }, 137 unix.SYS_SCHED_YIELD: { 138 { 139 seccomp.MatchAny{}, 140 seccomp.MatchAny{}, 141 seccomp.MatchAny{}, 142 seccomp.MatchAny{}, 143 seccomp.MatchAny{}, 144 seccomp.MatchAny{}, 145 seccomp.GreaterThan(stubStart), // rip 146 }, 147 }, 148 }, 149 Action: linux.SECCOMP_RET_ALLOW, 150 }, 151 }...) 152 instrs, err := seccomp.BuildProgram(rules, linux.SECCOMP_RET_TRAP, linux.SECCOMP_RET_TRAP) 153 if err != nil { 154 panic(fmt.Sprintf("failed to build rules for sysmsg threads: %v", err)) 155 } 156 157 return instrs 158 }