github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/devices/nvproxy/frontend_unsafe.go (about) 1 // Copyright 2023 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 nvproxy 16 17 import ( 18 "runtime" 19 "unsafe" 20 21 "golang.org/x/sys/unix" 22 "github.com/nicocha30/gvisor-ligolo/pkg/abi/nvgpu" 23 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 24 "github.com/nicocha30/gvisor-ligolo/pkg/marshal/primitive" 25 ) 26 27 func frontendIoctlInvoke[Params any](fi *frontendIoctlState, sentryParams *Params) (uintptr, error) { 28 n, _, errno := unix.RawSyscall(unix.SYS_IOCTL, uintptr(fi.fd.hostFD), frontendIoctlCmd(fi.nr, fi.ioctlParamsSize), uintptr(unsafe.Pointer(sentryParams))) 29 if errno != 0 { 30 return n, errno 31 } 32 return n, nil 33 } 34 35 func rmControlInvoke[Params any](fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters, ctrlParams *Params) (uintptr, error) { 36 defer runtime.KeepAlive(ctrlParams) // since we convert to non-pointer-typed P64 37 sentryIoctlParams := *ioctlParams 38 sentryIoctlParams.Params = p64FromPtr(unsafe.Pointer(ctrlParams)) 39 n, err := frontendIoctlInvoke(fi, &sentryIoctlParams) 40 if err != nil { 41 return n, err 42 } 43 outIoctlParams := sentryIoctlParams 44 outIoctlParams.Params = ioctlParams.Params 45 if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil { 46 return n, err 47 } 48 return n, nil 49 } 50 51 func ctrlClientSystemGetBuildVersionInvoke(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters, ctrlParams *nvgpu.NV0000_CTRL_SYSTEM_GET_BUILD_VERSION_PARAMS, driverVersionBuf, versionBuf, titleBuf *byte) (uintptr, error) { 52 sentryCtrlParams := *ctrlParams 53 sentryCtrlParams.PDriverVersionBuffer = p64FromPtr(unsafe.Pointer(driverVersionBuf)) 54 sentryCtrlParams.PVersionBuffer = p64FromPtr(unsafe.Pointer(versionBuf)) 55 sentryCtrlParams.PTitleBuffer = p64FromPtr(unsafe.Pointer(titleBuf)) 56 n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams) 57 if err != nil { 58 return n, err 59 } 60 outCtrlParams := sentryCtrlParams 61 outCtrlParams.PDriverVersionBuffer = ctrlParams.PDriverVersionBuffer 62 outCtrlParams.PVersionBuffer = ctrlParams.PVersionBuffer 63 outCtrlParams.PTitleBuffer = ctrlParams.PTitleBuffer 64 if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil { 65 return n, err 66 } 67 return n, nil 68 } 69 70 func ctrlDevFIFOGetChannelList(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) { 71 var ctrlParams nvgpu.NV0080_CTRL_FIFO_GET_CHANNELLIST_PARAMS 72 if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) { 73 return 0, linuxerr.EINVAL 74 } 75 if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil { 76 return 0, err 77 } 78 if ctrlParams.NumChannels == 0 { 79 // Compare 80 // src/nvidia/src/kernel/gpu/fifo/kernel_fifo_ctrl.c:deviceCtrlCmdFifoGetChannelList_IMPL(). 81 return 0, linuxerr.EINVAL 82 } 83 channelHandleList := make([]uint32, ctrlParams.NumChannels) 84 if _, err := primitive.CopyUint32SliceIn(fi.t, addrFromP64(ctrlParams.PChannelHandleList), channelHandleList); err != nil { 85 return 0, err 86 } 87 channelList := make([]uint32, ctrlParams.NumChannels) 88 if _, err := primitive.CopyUint32SliceIn(fi.t, addrFromP64(ctrlParams.PChannelList), channelList); err != nil { 89 return 0, err 90 } 91 sentryCtrlParams := ctrlParams 92 sentryCtrlParams.PChannelHandleList = p64FromPtr(unsafe.Pointer(&channelHandleList[0])) 93 sentryCtrlParams.PChannelList = p64FromPtr(unsafe.Pointer(&channelList[0])) 94 95 n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams) 96 if err != nil { 97 return n, err 98 } 99 100 if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(ctrlParams.PChannelHandleList), channelHandleList); err != nil { 101 return 0, err 102 } 103 if _, err := primitive.CopyUint32SliceOut(fi.t, addrFromP64(ctrlParams.PChannelList), channelList); err != nil { 104 return 0, err 105 } 106 outCtrlParams := sentryCtrlParams 107 outCtrlParams.PChannelHandleList = ctrlParams.PChannelHandleList 108 outCtrlParams.PChannelList = ctrlParams.PChannelList 109 if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil { 110 return n, err 111 } 112 113 return n, nil 114 } 115 116 func ctrlSubdevGRGetInfo(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS54Parameters) (uintptr, error) { 117 var ctrlParams nvgpu.NV2080_CTRL_GR_GET_INFO_PARAMS 118 if ctrlParams.SizeBytes() != int(ioctlParams.ParamsSize) { 119 return 0, linuxerr.EINVAL 120 } 121 if _, err := ctrlParams.CopyIn(fi.t, addrFromP64(ioctlParams.Params)); err != nil { 122 return 0, err 123 } 124 if ctrlParams.GRInfoListSize == 0 { 125 // Compare 126 // src/nvidia/src/kernel/gpu/gr/kernel_graphics.c:_kgraphicsCtrlCmdGrGetInfoV2(). 127 return 0, linuxerr.EINVAL 128 } 129 infoList := make([]byte, int(ctrlParams.GRInfoListSize)*(*nvgpu.NVXXXX_CTRL_XXX_INFO)(nil).SizeBytes()) 130 if _, err := fi.t.CopyInBytes(addrFromP64(ctrlParams.GRInfoList), infoList); err != nil { 131 return 0, err 132 } 133 sentryCtrlParams := ctrlParams 134 sentryCtrlParams.GRInfoList = p64FromPtr(unsafe.Pointer(&infoList[0])) 135 136 n, err := rmControlInvoke(fi, ioctlParams, &sentryCtrlParams) 137 if err != nil { 138 return n, err 139 } 140 141 if _, err := fi.t.CopyOutBytes(addrFromP64(ctrlParams.GRInfoList), infoList); err != nil { 142 return n, err 143 } 144 outCtrlParams := sentryCtrlParams 145 outCtrlParams.GRInfoList = ctrlParams.GRInfoList 146 if _, err := outCtrlParams.CopyOut(fi.t, addrFromP64(ioctlParams.Params)); err != nil { 147 return n, err 148 } 149 150 return n, nil 151 } 152 153 func rmAllocInvoke[Params any](fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, allocParams *Params, isNVOS64 bool) (uintptr, error) { 154 defer runtime.KeepAlive(allocParams) // since we convert to non-pointer-typed P64 155 156 if isNVOS64 { 157 sentryIoctlParams := *ioctlParams 158 sentryIoctlParams.PAllocParms = p64FromPtr(unsafe.Pointer(allocParams)) 159 var rightsRequested nvgpu.RS_ACCESS_MASK 160 if ioctlParams.PRightsRequested != 0 { 161 if _, err := rightsRequested.CopyIn(fi.t, addrFromP64(ioctlParams.PRightsRequested)); err != nil { 162 return 0, err 163 } 164 sentryIoctlParams.PRightsRequested = p64FromPtr(unsafe.Pointer(&rightsRequested)) 165 } 166 n, err := frontendIoctlInvoke(fi, &sentryIoctlParams) 167 if err != nil { 168 return n, err 169 } 170 if ioctlParams.PRightsRequested != 0 { 171 if _, err := rightsRequested.CopyOut(fi.t, addrFromP64(ioctlParams.PRightsRequested)); err != nil { 172 return n, err 173 } 174 } 175 outIoctlParams := sentryIoctlParams 176 outIoctlParams.PAllocParms = ioctlParams.PAllocParms 177 outIoctlParams.PRightsRequested = ioctlParams.PRightsRequested 178 if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil { 179 return n, err 180 } 181 return n, nil 182 } 183 184 sentryIoctlParams := nvgpu.NVOS21Parameters{ 185 HRoot: ioctlParams.HRoot, 186 HObjectParent: ioctlParams.HObjectParent, 187 HObjectNew: ioctlParams.HObjectNew, 188 HClass: ioctlParams.HClass, 189 PAllocParms: p64FromPtr(unsafe.Pointer(allocParams)), 190 Status: ioctlParams.Status, 191 } 192 n, err := frontendIoctlInvoke(fi, &sentryIoctlParams) 193 if err != nil { 194 return n, err 195 } 196 outIoctlParams := nvgpu.NVOS21Parameters{ 197 HRoot: sentryIoctlParams.HRoot, 198 HObjectParent: sentryIoctlParams.HObjectParent, 199 HObjectNew: sentryIoctlParams.HObjectNew, 200 HClass: sentryIoctlParams.HClass, 201 PAllocParms: ioctlParams.PAllocParms, 202 Status: sentryIoctlParams.Status, 203 } 204 if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil { 205 return n, err 206 } 207 return n, nil 208 } 209 210 func rmVidHeapControlAllocSize(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS32Parameters) (uintptr, error) { 211 allocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&ioctlParams.Data)) 212 213 sentryIoctlParams := *ioctlParams 214 sentryAllocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&sentryIoctlParams.Data)) 215 var addr uint64 216 if allocSizeParams.Address != 0 { 217 if _, err := primitive.CopyUint64In(fi.t, addrFromP64(allocSizeParams.Address), &addr); err != nil { 218 return 0, err 219 } 220 sentryAllocSizeParams.Address = p64FromPtr(unsafe.Pointer(&addr)) 221 } 222 223 n, err := frontendIoctlInvoke(fi, &sentryIoctlParams) 224 if err != nil { 225 return n, err 226 } 227 228 outIoctlParams := sentryIoctlParams 229 outAllocSizeParams := (*nvgpu.NVOS32AllocSize)(unsafe.Pointer(&outIoctlParams.Data)) 230 if allocSizeParams.Address != 0 { 231 if _, err := primitive.CopyUint64Out(fi.t, addrFromP64(allocSizeParams.Address), addr); err != nil { 232 return n, err 233 } 234 outAllocSizeParams.Address = allocSizeParams.Address 235 } 236 if _, err := outIoctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil { 237 return n, err 238 } 239 240 return n, nil 241 }