github.com/usbarmory/GoTEE@v0.0.0-20240405084336-c52770d9fcdb/syscall/rpc.go (about) 1 // Copyright (c) WithSecure Corporation 2 // https://foundry.withsecure.com 3 // 4 // Use of this source code is governed by the license 5 // that can be found in the LICENSE file. 6 7 package syscall 8 9 import ( 10 "io" 11 "net/rpc" 12 "net/rpc/jsonrpc" 13 "sync" 14 ) 15 16 var mux sync.Mutex 17 18 // Stream implements a data stream interface to exchange data buffers between 19 // the security monitor and a lower privilege execution context over syscalls. 20 // 21 // It is used by NewClient() to stream JSON-RPC calls from an applet and 22 // receive responses from the supervisor, over syscalls. 23 // 24 // The implementation is not safe against concurrent reads and writes, which 25 // should be avoided. 26 type Stream struct { 27 // ReadSyscall is the syscall number associated to Read() 28 ReadSyscall uint 29 // ReadSyscall is the syscall number associated to Write() 30 WriteSyscall uint 31 } 32 33 // Read reads up to len(p) bytes into p, it never returns an error. The read is 34 // requested, through the Stream ReadSyscall, to the supervisor. 35 func (s *Stream) Read(p []byte) (n int, err error) { 36 if n = Read(s.ReadSyscall, p, uint(len(p))); n <= 0 { 37 return 0, io.EOF 38 } 39 40 return 41 } 42 43 // Write writes len(p) bytes from p to the underlying data stream, it never 44 // returns an error. The write is issued, through the Stream WriteSyscall, to 45 // the supervisor. 46 func (s *Stream) Write(p []byte) (n int, err error) { 47 n = len(p) 48 Write(s.WriteSyscall, p, uint(n)) 49 return 50 } 51 52 // Close has no effect. 53 func (s *Stream) Close() error { 54 return nil 55 } 56 57 // NewClient returns a new client suitable for RPC calls to the supervisor. The 58 // client automatically closes after Call() is invoked on it the first time, 59 // therefore a new instance is needed for each call (also see Call()). 60 func NewClient() *rpc.Client { 61 return jsonrpc.NewClient(&Stream{ 62 ReadSyscall: SYS_RPC_RES, 63 WriteSyscall: SYS_RPC_REQ, 64 }) 65 } 66 67 // Call is a convenience method that issues an RPC call on a disposable client 68 // created with NewClient(), to avoid concurrent reads and writes a mutex is 69 // held to prevent interleaved invocations. 70 func Call(serviceMethod string, args interface{}, reply interface{}) error { 71 mux.Lock() 72 defer mux.Unlock() 73 74 return NewClient().Call(serviceMethod, args, reply) 75 }