github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/fuse/request_response.go (about)

     1  // Copyright 2020 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 fuse
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"golang.org/x/sys/unix"
    21  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    22  	"github.com/SagerNet/gvisor/pkg/hostarch"
    23  	"github.com/SagerNet/gvisor/pkg/marshal"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    26  )
    27  
    28  // fuseInitRes is a variable-length wrapper of linux.FUSEInitOut. The FUSE
    29  // server may implement an older version of FUSE protocol, which contains a
    30  // linux.FUSEInitOut with less attributes.
    31  //
    32  // Dynamically-sized objects cannot be marshalled.
    33  type fuseInitRes struct {
    34  	marshal.StubMarshallable
    35  
    36  	// initOut contains the response from the FUSE server.
    37  	initOut linux.FUSEInitOut
    38  
    39  	// initLen is the total length of bytes of the response.
    40  	initLen uint32
    41  }
    42  
    43  // UnmarshalBytes deserializes src to the initOut attribute in a fuseInitRes.
    44  func (r *fuseInitRes) UnmarshalBytes(src []byte) {
    45  	out := &r.initOut
    46  
    47  	// Introduced before FUSE kernel version 7.13.
    48  	out.Major = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    49  	src = src[4:]
    50  	out.Minor = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    51  	src = src[4:]
    52  	out.MaxReadahead = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    53  	src = src[4:]
    54  	out.Flags = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    55  	src = src[4:]
    56  	out.MaxBackground = uint16(hostarch.ByteOrder.Uint16(src[:2]))
    57  	src = src[2:]
    58  	out.CongestionThreshold = uint16(hostarch.ByteOrder.Uint16(src[:2]))
    59  	src = src[2:]
    60  	out.MaxWrite = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    61  	src = src[4:]
    62  
    63  	// Introduced in FUSE kernel version 7.23.
    64  	if len(src) >= 4 {
    65  		out.TimeGran = uint32(hostarch.ByteOrder.Uint32(src[:4]))
    66  		src = src[4:]
    67  	}
    68  	// Introduced in FUSE kernel version 7.28.
    69  	if len(src) >= 2 {
    70  		out.MaxPages = uint16(hostarch.ByteOrder.Uint16(src[:2]))
    71  		src = src[2:]
    72  	}
    73  	_ = src // Remove unused warning.
    74  }
    75  
    76  // SizeBytes is the size of the payload of the FUSE_INIT response.
    77  func (r *fuseInitRes) SizeBytes() int {
    78  	return int(r.initLen)
    79  }
    80  
    81  // Ordinary requests have even IDs, while interrupts IDs are odd.
    82  // Used to increment the unique ID for each FUSE request.
    83  var reqIDStep uint64 = 2
    84  
    85  // Request represents a FUSE operation request that hasn't been sent to the
    86  // server yet.
    87  //
    88  // +stateify savable
    89  type Request struct {
    90  	requestEntry
    91  
    92  	id   linux.FUSEOpID
    93  	hdr  *linux.FUSEHeaderIn
    94  	data []byte
    95  
    96  	// payload for this request: extra bytes to write after
    97  	// the data slice. Used by FUSE_WRITE.
    98  	payload []byte
    99  
   100  	// If this request is async.
   101  	async bool
   102  	// If we don't care its response.
   103  	// Manually set by the caller.
   104  	noReply bool
   105  }
   106  
   107  // NewRequest creates a new request that can be sent to the FUSE server.
   108  func (conn *connection) NewRequest(creds *auth.Credentials, pid uint32, ino uint64, opcode linux.FUSEOpcode, payload marshal.Marshallable) *Request {
   109  	conn.fd.mu.Lock()
   110  	defer conn.fd.mu.Unlock()
   111  	conn.fd.nextOpID += linux.FUSEOpID(reqIDStep)
   112  
   113  	hdrLen := (*linux.FUSEHeaderIn)(nil).SizeBytes()
   114  	hdr := linux.FUSEHeaderIn{
   115  		Len:    uint32(hdrLen + payload.SizeBytes()),
   116  		Opcode: opcode,
   117  		Unique: conn.fd.nextOpID,
   118  		NodeID: ino,
   119  		UID:    uint32(creds.EffectiveKUID),
   120  		GID:    uint32(creds.EffectiveKGID),
   121  		PID:    pid,
   122  	}
   123  
   124  	buf := make([]byte, hdr.Len)
   125  
   126  	// TODO(github.com/SagerNet/issue/3698): Use the unsafe version once go_marshal is safe to use again.
   127  	hdr.MarshalBytes(buf[:hdrLen])
   128  	payload.MarshalBytes(buf[hdrLen:])
   129  
   130  	return &Request{
   131  		id:   hdr.Unique,
   132  		hdr:  &hdr,
   133  		data: buf,
   134  	}
   135  }
   136  
   137  // futureResponse represents an in-flight request, that may or may not have
   138  // completed yet. Convert it to a resolved Response by calling Resolve, but note
   139  // that this may block.
   140  //
   141  // +stateify savable
   142  type futureResponse struct {
   143  	opcode linux.FUSEOpcode
   144  	ch     chan struct{}
   145  	hdr    *linux.FUSEHeaderOut
   146  	data   []byte
   147  
   148  	// If this request is async.
   149  	async bool
   150  }
   151  
   152  // newFutureResponse creates a future response to a FUSE request.
   153  func newFutureResponse(req *Request) *futureResponse {
   154  	return &futureResponse{
   155  		opcode: req.hdr.Opcode,
   156  		ch:     make(chan struct{}),
   157  		async:  req.async,
   158  	}
   159  }
   160  
   161  // resolve blocks the task until the server responds to its corresponding request,
   162  // then returns a resolved response.
   163  func (f *futureResponse) resolve(t *kernel.Task) (*Response, error) {
   164  	// Return directly for async requests.
   165  	if f.async {
   166  		return nil, nil
   167  	}
   168  
   169  	if err := t.Block(f.ch); err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	return f.getResponse(), nil
   174  }
   175  
   176  // getResponse creates a Response from the data the futureResponse has.
   177  func (f *futureResponse) getResponse() *Response {
   178  	return &Response{
   179  		opcode: f.opcode,
   180  		hdr:    *f.hdr,
   181  		data:   f.data,
   182  	}
   183  }
   184  
   185  // Response represents an actual response from the server, including the
   186  // response payload.
   187  //
   188  // +stateify savable
   189  type Response struct {
   190  	opcode linux.FUSEOpcode
   191  	hdr    linux.FUSEHeaderOut
   192  	data   []byte
   193  }
   194  
   195  // Error returns the error of the FUSE call.
   196  func (r *Response) Error() error {
   197  	errno := r.hdr.Error
   198  	if errno >= 0 {
   199  		return nil
   200  	}
   201  
   202  	sysErrNo := unix.Errno(-errno)
   203  	return error(sysErrNo)
   204  }
   205  
   206  // DataLen returns the size of the response without the header.
   207  func (r *Response) DataLen() uint32 {
   208  	return r.hdr.Len - uint32(r.hdr.SizeBytes())
   209  }
   210  
   211  // UnmarshalPayload unmarshals the response data into m.
   212  func (r *Response) UnmarshalPayload(m marshal.Marshallable) error {
   213  	hdrLen := r.hdr.SizeBytes()
   214  	haveDataLen := r.hdr.Len - uint32(hdrLen)
   215  	wantDataLen := uint32(m.SizeBytes())
   216  
   217  	if haveDataLen < wantDataLen {
   218  		return fmt.Errorf("payload too small. Minimum data lenth required: %d,  but got data length %d", wantDataLen, haveDataLen)
   219  	}
   220  
   221  	// The response data is empty unless there is some payload. And so, doesn't
   222  	// need to be unmarshalled.
   223  	if r.data == nil {
   224  		return nil
   225  	}
   226  
   227  	// TODO(github.com/SagerNet/issue/3698): Use the unsafe version once go_marshal is safe to use again.
   228  	m.UnmarshalBytes(r.data[hdrLen:])
   229  	return nil
   230  }