gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/socket/unix/io.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 package unix 16 17 import ( 18 "gvisor.dev/gvisor/pkg/context" 19 "gvisor.dev/gvisor/pkg/safemem" 20 "gvisor.dev/gvisor/pkg/sentry/socket/unix/transport" 21 ) 22 23 // EndpointWriter implements safemem.Writer that writes to a transport.Endpoint. 24 // 25 // EndpointWriter is not thread-safe. 26 type EndpointWriter struct { 27 Ctx context.Context 28 29 // Endpoint is the transport.Endpoint to write to. 30 Endpoint transport.Endpoint 31 32 // Control is the control messages to send. 33 Control transport.ControlMessages 34 35 // To is the endpoint to send to. May be nil. 36 To transport.BoundEndpoint 37 38 // Notify is the receiver.SendNotify notification callback that is set 39 // by WriteFromBlocks and should be called without mm.activeMu held 40 // (i.e. after CopyOut completes). 41 Notify func() 42 } 43 44 // WriteFromBlocks implements safemem.Writer.WriteFromBlocks. 45 func (w *EndpointWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) { 46 return safemem.FromVecWriterFunc{func(bufs [][]byte) (int64, error) { 47 n, notify, err := w.Endpoint.SendMsg(w.Ctx, bufs, w.Control, w.To) 48 w.Notify = notify 49 if err != nil { 50 return int64(n), err.ToError() 51 } 52 return int64(n), nil 53 }}.WriteFromBlocks(srcs) 54 } 55 56 // EndpointReader implements safemem.Reader that reads from a 57 // transport.Endpoint. 58 // 59 // EndpointReader is not thread-safe. 60 type EndpointReader struct { 61 Ctx context.Context 62 63 // Endpoint is the transport.Endpoint to read from. 64 Endpoint transport.Endpoint 65 66 // Creds indicates if credential control messages are requested. 67 Creds bool 68 69 // NumRights is the number of SCM_RIGHTS FDs requested. 70 NumRights int 71 72 // Peek indicates that the data should not be consumed from the 73 // endpoint. 74 Peek bool 75 76 // MsgSize is the size of the message that was read from. For stream 77 // sockets, it is the amount read. 78 MsgSize int64 79 80 // From will be set with the address read from. 81 From transport.Address 82 83 // Control contains the received control messages. 84 Control transport.ControlMessages 85 86 // UnusedRights is a slice of unused RightsControlMessage that must be 87 // Release()d before this EndpointReader is discarded. 88 UnusedRights []transport.RightsControlMessage 89 90 // ControlTrunc indicates that SCM_RIGHTS FDs were discarded based on 91 // the value of NumRights. 92 ControlTrunc bool 93 94 // Notify is the ConnectedEndpoint.RecvNotify callback that is set by 95 // ReadToBlocks and should be called without mm.activeMu held (i.e. 96 // after CopyIn completes). 97 Notify func() 98 } 99 100 // Truncate calls RecvMsg on the endpoint without writing to a destination. 101 func (r *EndpointReader) Truncate() error { 102 args := transport.RecvArgs{ 103 Creds: r.Creds, 104 NumRights: r.NumRights, 105 Peek: r.Peek, 106 } 107 out, notify, err := r.Endpoint.RecvMsg(r.Ctx, [][]byte{}, args) 108 r.MsgSize = out.MsgLen 109 r.Control = out.Control 110 r.ControlTrunc = out.ControlTrunc 111 r.UnusedRights = out.UnusedRights 112 r.From = out.Source 113 if notify != nil { 114 notify() 115 } 116 if err != nil { 117 return err.ToError() 118 } 119 return nil 120 } 121 122 // ReadToBlocks implements safemem.Reader.ReadToBlocks. 123 func (r *EndpointReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { 124 return safemem.FromVecReaderFunc{func(bufs [][]byte) (int64, error) { 125 args := transport.RecvArgs{ 126 Creds: r.Creds, 127 NumRights: r.NumRights, 128 Peek: r.Peek, 129 } 130 out, notify, err := r.Endpoint.RecvMsg(r.Ctx, bufs, args) 131 r.MsgSize = out.MsgLen 132 r.Control = out.Control 133 r.ControlTrunc = out.ControlTrunc 134 r.UnusedRights = out.UnusedRights 135 r.From = out.Source 136 r.Notify = notify 137 if err != nil { 138 return int64(out.RecvLen), err.ToError() 139 } 140 return int64(out.RecvLen), nil 141 }}.ReadToBlocks(dsts) 142 }