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  }