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  }