github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/server.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 p9
    16  
    17  import (
    18  	"io"
    19  	"runtime/debug"
    20  	"sync/atomic"
    21  
    22  	"github.com/SagerNet/gvisor/pkg/abi/linux/errno"
    23  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    24  	"github.com/SagerNet/gvisor/pkg/fd"
    25  	"github.com/SagerNet/gvisor/pkg/fdchannel"
    26  	"github.com/SagerNet/gvisor/pkg/flipcall"
    27  	"github.com/SagerNet/gvisor/pkg/log"
    28  	"github.com/SagerNet/gvisor/pkg/sync"
    29  	"github.com/SagerNet/gvisor/pkg/unet"
    30  )
    31  
    32  // Server is a 9p2000.L server.
    33  type Server struct {
    34  	// attacher provides the attach function.
    35  	attacher Attacher
    36  
    37  	// pathTree is the full set of paths opened on this server.
    38  	//
    39  	// These may be across different connections, but rename operations
    40  	// must be serialized globally for safely. There is a single pathTree
    41  	// for the entire server, and not per connection.
    42  	pathTree *pathNode
    43  
    44  	// renameMu is a global lock protecting rename operations. With this
    45  	// lock, we can be certain that any given rename operation can safely
    46  	// acquire two path nodes in any order, as all other concurrent
    47  	// operations acquire at most a single node.
    48  	renameMu sync.RWMutex
    49  }
    50  
    51  // NewServer returns a new server.
    52  func NewServer(attacher Attacher) *Server {
    53  	return &Server{
    54  		attacher: attacher,
    55  		pathTree: newPathNode(),
    56  	}
    57  }
    58  
    59  // connState is the state for a single connection.
    60  type connState struct {
    61  	// server is the backing server.
    62  	server *Server
    63  
    64  	// fids is the set of active FIDs.
    65  	//
    66  	// This is used to find FIDs for files.
    67  	fidMu sync.Mutex
    68  	fids  map[FID]*fidRef
    69  
    70  	// tags is the set of active tags.
    71  	//
    72  	// The given channel is closed when the
    73  	// tag is finished with processing.
    74  	tagMu sync.Mutex
    75  	tags  map[Tag]chan struct{}
    76  
    77  	// messageSize is the maximum message size. The server does not
    78  	// do automatic splitting of messages.
    79  	messageSize uint32
    80  
    81  	// version is the agreed upon version X of 9P2000.L.Google.X.
    82  	// version 0 implies 9P2000.L.
    83  	version uint32
    84  
    85  	// reqGate counts requests that are still being handled.
    86  	reqGate sync.Gate
    87  
    88  	// -- below relates to the legacy handler --
    89  
    90  	// recvMu serializes receiving from conn.
    91  	recvMu sync.Mutex
    92  
    93  	// recvIdle is the number of goroutines in handleRequests() attempting to
    94  	// lock recvMu so that they can receive from conn. recvIdle is accessed
    95  	// using atomic memory operations.
    96  	recvIdle int32
    97  
    98  	// If recvShutdown is true, at least one goroutine has observed a
    99  	// connection error while receiving from conn, and all goroutines in
   100  	// handleRequests() should exit immediately. recvShutdown is protected by
   101  	// recvMu.
   102  	recvShutdown bool
   103  
   104  	// sendMu serializes sending to conn.
   105  	sendMu sync.Mutex
   106  
   107  	// conn is the connection used by the legacy transport.
   108  	conn *unet.Socket
   109  
   110  	// -- below relates to the flipcall handler --
   111  
   112  	// channelMu protects below.
   113  	channelMu sync.Mutex
   114  
   115  	// channelWg represents active workers.
   116  	channelWg sync.WaitGroup
   117  
   118  	// channelAlloc allocates channel memory.
   119  	channelAlloc *flipcall.PacketWindowAllocator
   120  
   121  	// channels are the set of initialized channels.
   122  	channels []*channel
   123  }
   124  
   125  // fidRef wraps a node and tracks references.
   126  type fidRef struct {
   127  	// server is the associated server.
   128  	server *Server
   129  
   130  	// file is the associated File.
   131  	file File
   132  
   133  	// refs is an active refence count.
   134  	//
   135  	// The node above will be closed only when refs reaches zero.
   136  	refs int64
   137  
   138  	// opened indicates whether this has been opened already.
   139  	//
   140  	// This is updated in handlers.go.
   141  	//
   142  	// opened is protected by pathNode.opMu or renameMu (for write).
   143  	opened bool
   144  
   145  	// mode is the fidRef's mode from the walk. Only the type bits are
   146  	// valid, the permissions may change. This is used to sanity check
   147  	// operations on this element, and prevent walks across
   148  	// non-directories.
   149  	mode FileMode
   150  
   151  	// openFlags is the mode used in the open.
   152  	//
   153  	// This is updated in handlers.go.
   154  	//
   155  	// openFlags is protected by pathNode.opMu or renameMu (for write).
   156  	openFlags OpenFlags
   157  
   158  	// pathNode is the current pathNode for this FID.
   159  	pathNode *pathNode
   160  
   161  	// parent is the parent fidRef. We hold on to a parent reference to
   162  	// ensure that hooks, such as Renamed, can be executed safely by the
   163  	// server code.
   164  	//
   165  	// Note that parent cannot be changed without holding both the global
   166  	// rename lock and a writable lock on the associated pathNode for this
   167  	// fidRef. Holding either of these locks is sufficient to examine
   168  	// parent safely.
   169  	//
   170  	// The parent will be nil for root fidRefs, and non-nil otherwise. The
   171  	// method maybeParent can be used to return a cyclical reference, and
   172  	// isRoot should be used to check for root over looking at parent
   173  	// directly.
   174  	parent *fidRef
   175  
   176  	// deleted indicates that the backing file has been deleted. We stop
   177  	// many operations at the API level if they are incompatible with a
   178  	// file that has already been unlinked.
   179  	deleted uint32
   180  }
   181  
   182  // IncRef increases the references on a fid.
   183  func (f *fidRef) IncRef() {
   184  	atomic.AddInt64(&f.refs, 1)
   185  }
   186  
   187  // DecRef should be called when you're finished with a fid.
   188  func (f *fidRef) DecRef() {
   189  	if atomic.AddInt64(&f.refs, -1) == 0 {
   190  		f.file.Close()
   191  
   192  		// Drop the parent reference.
   193  		//
   194  		// Since this fidRef is guaranteed to be non-discoverable when
   195  		// the references reach zero, we don't need to worry about
   196  		// clearing the parent.
   197  		if f.parent != nil {
   198  			// If we've been previously deleted, this removing this
   199  			// ref is a no-op. That's expected.
   200  			f.parent.pathNode.removeChild(f)
   201  			f.parent.DecRef()
   202  		}
   203  	}
   204  }
   205  
   206  // isDeleted returns true if this fidRef has been deleted.
   207  func (f *fidRef) isDeleted() bool {
   208  	return atomic.LoadUint32(&f.deleted) != 0
   209  }
   210  
   211  // isRoot indicates whether this is a root fid.
   212  func (f *fidRef) isRoot() bool {
   213  	return f.parent == nil
   214  }
   215  
   216  // maybeParent returns a cyclic reference for roots, and the parent otherwise.
   217  func (f *fidRef) maybeParent() *fidRef {
   218  	if f.parent != nil {
   219  		return f.parent
   220  	}
   221  	return f // Root has itself.
   222  }
   223  
   224  // notifyDelete marks all fidRefs as deleted.
   225  //
   226  // Precondition: this must be called via safelyWrite or safelyGlobal.
   227  func notifyDelete(pn *pathNode) {
   228  	// Call on all local references.
   229  	pn.forEachChildRef(func(ref *fidRef, _ string) {
   230  		atomic.StoreUint32(&ref.deleted, 1)
   231  	})
   232  
   233  	// Call on all subtrees.
   234  	pn.forEachChildNode(func(pn *pathNode) {
   235  		notifyDelete(pn)
   236  	})
   237  }
   238  
   239  // markChildDeleted marks all children below the given name as deleted.
   240  //
   241  // Precondition: this must be called via safelyWrite or safelyGlobal.
   242  func (f *fidRef) markChildDeleted(name string) {
   243  	origPathNode := f.pathNode.removeWithName(name, func(ref *fidRef) {
   244  		atomic.StoreUint32(&ref.deleted, 1)
   245  	})
   246  
   247  	if origPathNode != nil {
   248  		// Mark all children as deleted.
   249  		notifyDelete(origPathNode)
   250  	}
   251  }
   252  
   253  // notifyNameChange calls the relevant Renamed method on all nodes in the path,
   254  // recursively. Note that this applies only for subtrees, as these
   255  // notifications do not apply to the actual file whose name has changed.
   256  //
   257  // Precondition: this must be called via safelyGlobal.
   258  func notifyNameChange(pn *pathNode) {
   259  	// Call on all local references.
   260  	pn.forEachChildRef(func(ref *fidRef, name string) {
   261  		ref.file.Renamed(ref.parent.file, name)
   262  	})
   263  
   264  	// Call on all subtrees.
   265  	pn.forEachChildNode(func(pn *pathNode) {
   266  		notifyNameChange(pn)
   267  	})
   268  }
   269  
   270  // renameChildTo renames the given child to the target.
   271  //
   272  // Precondition: this must be called via safelyGlobal.
   273  func (f *fidRef) renameChildTo(oldName string, target *fidRef, newName string) {
   274  	target.markChildDeleted(newName)
   275  	origPathNode := f.pathNode.removeWithName(oldName, func(ref *fidRef) {
   276  		// N.B. DecRef can take f.pathNode's parent's childMu. This is
   277  		// allowed because renameMu is held for write via safelyGlobal.
   278  		ref.parent.DecRef() // Drop original reference.
   279  		ref.parent = target // Change parent.
   280  		ref.parent.IncRef() // Acquire new one.
   281  		if f.pathNode == target.pathNode {
   282  			target.pathNode.addChildLocked(ref, newName)
   283  		} else {
   284  			target.pathNode.addChild(ref, newName)
   285  		}
   286  		ref.file.Renamed(target.file, newName)
   287  	})
   288  
   289  	if origPathNode != nil {
   290  		// Replace the previous (now deleted) path node.
   291  		target.pathNode.addPathNodeFor(newName, origPathNode)
   292  		// Call Renamed on all children.
   293  		notifyNameChange(origPathNode)
   294  	}
   295  }
   296  
   297  // safelyRead executes the given operation with the local path node locked.
   298  // This implies that paths will not change during the operation.
   299  func (f *fidRef) safelyRead(fn func() error) (err error) {
   300  	f.server.renameMu.RLock()
   301  	defer f.server.renameMu.RUnlock()
   302  	f.pathNode.opMu.RLock()
   303  	defer f.pathNode.opMu.RUnlock()
   304  	return fn()
   305  }
   306  
   307  // safelyWrite executes the given operation with the local path node locked in
   308  // a writable fashion. This implies some paths may change.
   309  func (f *fidRef) safelyWrite(fn func() error) (err error) {
   310  	f.server.renameMu.RLock()
   311  	defer f.server.renameMu.RUnlock()
   312  	f.pathNode.opMu.Lock()
   313  	defer f.pathNode.opMu.Unlock()
   314  	return fn()
   315  }
   316  
   317  // safelyGlobal executes the given operation with the global path lock held.
   318  func (f *fidRef) safelyGlobal(fn func() error) (err error) {
   319  	f.server.renameMu.Lock()
   320  	defer f.server.renameMu.Unlock()
   321  	return fn()
   322  }
   323  
   324  // LookupFID finds the given FID.
   325  //
   326  // You should call fid.DecRef when you are finished using the fid.
   327  func (cs *connState) LookupFID(fid FID) (*fidRef, bool) {
   328  	cs.fidMu.Lock()
   329  	defer cs.fidMu.Unlock()
   330  	fidRef, ok := cs.fids[fid]
   331  	if ok {
   332  		fidRef.IncRef()
   333  		return fidRef, true
   334  	}
   335  	return nil, false
   336  }
   337  
   338  // InsertFID installs the given FID.
   339  //
   340  // This fid starts with a reference count of one. If a FID exists in
   341  // the slot already it is closed, per the specification.
   342  func (cs *connState) InsertFID(fid FID, newRef *fidRef) {
   343  	cs.fidMu.Lock()
   344  	defer cs.fidMu.Unlock()
   345  	origRef, ok := cs.fids[fid]
   346  	if ok {
   347  		defer origRef.DecRef()
   348  	}
   349  	newRef.IncRef()
   350  	cs.fids[fid] = newRef
   351  }
   352  
   353  // DeleteFID removes the given FID.
   354  //
   355  // This simply removes it from the map and drops a reference.
   356  func (cs *connState) DeleteFID(fid FID) bool {
   357  	cs.fidMu.Lock()
   358  	defer cs.fidMu.Unlock()
   359  	fidRef, ok := cs.fids[fid]
   360  	if !ok {
   361  		return false
   362  	}
   363  	delete(cs.fids, fid)
   364  	fidRef.DecRef()
   365  	return true
   366  }
   367  
   368  // StartTag starts handling the tag.
   369  //
   370  // False is returned if this tag is already active.
   371  func (cs *connState) StartTag(t Tag) bool {
   372  	cs.tagMu.Lock()
   373  	defer cs.tagMu.Unlock()
   374  	_, ok := cs.tags[t]
   375  	if ok {
   376  		return false
   377  	}
   378  	cs.tags[t] = make(chan struct{})
   379  	return true
   380  }
   381  
   382  // ClearTag finishes handling a tag.
   383  func (cs *connState) ClearTag(t Tag) {
   384  	cs.tagMu.Lock()
   385  	defer cs.tagMu.Unlock()
   386  	ch, ok := cs.tags[t]
   387  	if !ok {
   388  		// Should never happen.
   389  		panic("unused tag cleared")
   390  	}
   391  	delete(cs.tags, t)
   392  
   393  	// Notify.
   394  	close(ch)
   395  }
   396  
   397  // WaitTag waits for a tag to finish.
   398  func (cs *connState) WaitTag(t Tag) {
   399  	cs.tagMu.Lock()
   400  	ch, ok := cs.tags[t]
   401  	cs.tagMu.Unlock()
   402  	if !ok {
   403  		return
   404  	}
   405  
   406  	// Wait for close.
   407  	<-ch
   408  }
   409  
   410  // initializeChannels initializes all channels.
   411  //
   412  // This is a no-op if channels are already initialized.
   413  func (cs *connState) initializeChannels() (err error) {
   414  	cs.channelMu.Lock()
   415  	defer cs.channelMu.Unlock()
   416  
   417  	// Initialize our channel allocator.
   418  	if cs.channelAlloc == nil {
   419  		alloc, err := flipcall.NewPacketWindowAllocator()
   420  		if err != nil {
   421  			return err
   422  		}
   423  		cs.channelAlloc = alloc
   424  	}
   425  
   426  	// Create all the channels.
   427  	for len(cs.channels) < channelsPerClient {
   428  		res := &channel{
   429  			done: make(chan struct{}),
   430  		}
   431  
   432  		res.desc, err = cs.channelAlloc.Allocate(channelSize)
   433  		if err != nil {
   434  			return err
   435  		}
   436  		if err := res.data.Init(flipcall.ServerSide, res.desc); err != nil {
   437  			return err
   438  		}
   439  
   440  		socks, err := fdchannel.NewConnectedSockets()
   441  		if err != nil {
   442  			res.data.Destroy() // Cleanup.
   443  			return err
   444  		}
   445  		res.fds.Init(socks[0])
   446  		res.client = fd.New(socks[1])
   447  
   448  		cs.channels = append(cs.channels, res)
   449  
   450  		// Start servicing the channel.
   451  		//
   452  		// When we call stop, we will close all the channels and these
   453  		// routines should finish. We need the wait group to ensure
   454  		// that active handlers are actually finished before cleanup.
   455  		cs.channelWg.Add(1)
   456  		go func() { // S/R-SAFE: Server side.
   457  			defer cs.channelWg.Done()
   458  			if err := res.service(cs); err != nil {
   459  				// Don't log flipcall.ShutdownErrors, which we expect to be
   460  				// returned during server shutdown.
   461  				if _, ok := err.(flipcall.ShutdownError); !ok {
   462  					log.Warningf("p9.channel.service: %v", err)
   463  				}
   464  			}
   465  		}()
   466  	}
   467  
   468  	return nil
   469  }
   470  
   471  // lookupChannel looks up the channel with given id.
   472  //
   473  // The function returns nil if no such channel is available.
   474  func (cs *connState) lookupChannel(id uint32) *channel {
   475  	cs.channelMu.Lock()
   476  	defer cs.channelMu.Unlock()
   477  	if id >= uint32(len(cs.channels)) {
   478  		return nil
   479  	}
   480  	return cs.channels[id]
   481  }
   482  
   483  // handle handles a single message.
   484  func (cs *connState) handle(m message) (r message) {
   485  	if !cs.reqGate.Enter() {
   486  		// connState.stop() has been called; the connection is shutting down.
   487  		r = newErrFromLinuxerr(linuxerr.ECONNRESET)
   488  		return
   489  	}
   490  	defer func() {
   491  		cs.reqGate.Leave()
   492  		if r == nil {
   493  			// Don't allow a panic to propagate.
   494  			err := recover()
   495  
   496  			// Include a useful log message.
   497  			log.Warningf("panic in handler: %v\n%s", err, debug.Stack())
   498  
   499  			// Wrap in an EFAULT error; we don't really have a
   500  			// better way to describe this kind of error. It will
   501  			// usually manifest as a result of the test framework.
   502  			r = newErrFromLinuxerr(linuxerr.EFAULT)
   503  		}
   504  	}()
   505  	if handler, ok := m.(handler); ok {
   506  		// Call the message handler.
   507  		r = handler.handle(cs)
   508  		// TODO(b/34162363):This is only here to make sure the server works with
   509  		// only linuxerr Errors, as the handlers work with both client and server.
   510  		// It will be removed a followup, when all the unix.Errno errors are
   511  		// replaced with linuxerr.
   512  		if rlError, ok := r.(*Rlerror); ok {
   513  			e := linuxerr.ErrorFromErrno(errno.Errno(rlError.Error))
   514  			r = newErrFromLinuxerr(e)
   515  		}
   516  	} else {
   517  		// Produce an ENOSYS error.
   518  		r = newErrFromLinuxerr(linuxerr.ENOSYS)
   519  	}
   520  	return
   521  }
   522  
   523  // handleRequest handles a single request. It returns true if the caller should
   524  // continue handling requests and false if it should terminate.
   525  func (cs *connState) handleRequest() bool {
   526  	// Obtain the right to receive a message from cs.conn.
   527  	atomic.AddInt32(&cs.recvIdle, 1)
   528  	cs.recvMu.Lock()
   529  	atomic.AddInt32(&cs.recvIdle, -1)
   530  
   531  	if cs.recvShutdown {
   532  		// Another goroutine already detected a connection problem; exit
   533  		// immediately.
   534  		cs.recvMu.Unlock()
   535  		return false
   536  	}
   537  
   538  	messageSize := atomic.LoadUint32(&cs.messageSize)
   539  	if messageSize == 0 {
   540  		// Default or not yet negotiated.
   541  		messageSize = maximumLength
   542  	}
   543  
   544  	// Receive a message.
   545  	tag, m, err := recv(cs.conn, messageSize, msgRegistry.get)
   546  	if errSocket, ok := err.(ErrSocket); ok {
   547  		// Connection problem; stop serving.
   548  		log.Debugf("p9.recv: %v", errSocket.error)
   549  		cs.recvShutdown = true
   550  		cs.recvMu.Unlock()
   551  		return false
   552  	}
   553  
   554  	// Ensure that another goroutine is available to receive from cs.conn.
   555  	if atomic.LoadInt32(&cs.recvIdle) == 0 {
   556  		go cs.handleRequests() // S/R-SAFE: Irrelevant.
   557  	}
   558  	cs.recvMu.Unlock()
   559  
   560  	// Deal with other errors.
   561  	if err != nil && err != io.EOF {
   562  		// If it's not a connection error, but some other protocol error,
   563  		// we can send a response immediately.
   564  		cs.sendMu.Lock()
   565  		err := send(cs.conn, tag, newErrFromLinuxerr(err))
   566  		cs.sendMu.Unlock()
   567  		if err != nil {
   568  			log.Debugf("p9.send: %v", err)
   569  		}
   570  		return true
   571  	}
   572  
   573  	// Try to start the tag.
   574  	if !cs.StartTag(tag) {
   575  		// Nothing we can do at this point; client is bogus.
   576  		log.Debugf("no valid tag [%05d]", tag)
   577  		return true
   578  	}
   579  
   580  	// Handle the message.
   581  	r := cs.handle(m)
   582  
   583  	// Clear the tag before sending. That's because as soon as this hits
   584  	// the wire, the client can legally send the same tag.
   585  	cs.ClearTag(tag)
   586  
   587  	// Send back the result.
   588  	cs.sendMu.Lock()
   589  	err = send(cs.conn, tag, r)
   590  	cs.sendMu.Unlock()
   591  	if err != nil {
   592  		log.Debugf("p9.send: %v", err)
   593  	}
   594  
   595  	// Return the message to the cache.
   596  	msgRegistry.put(m)
   597  
   598  	return true
   599  }
   600  
   601  func (cs *connState) handleRequests() {
   602  	for {
   603  		if !cs.handleRequest() {
   604  			return
   605  		}
   606  	}
   607  }
   608  
   609  func (cs *connState) stop() {
   610  	// Stop new requests from proceeding, and wait for completion of all
   611  	// inflight requests. This is mostly so that if a request is stuck, the
   612  	// sandbox supervisor has the opportunity to kill us with SIGABRT to get a
   613  	// stack dump of the offending handler.
   614  	cs.reqGate.Close()
   615  
   616  	// Free the channels.
   617  	cs.channelMu.Lock()
   618  	for _, ch := range cs.channels {
   619  		ch.Shutdown()
   620  	}
   621  	cs.channelWg.Wait()
   622  	for _, ch := range cs.channels {
   623  		ch.Close()
   624  	}
   625  	cs.channels = nil // Clear.
   626  	cs.channelMu.Unlock()
   627  
   628  	// Free the channel memory.
   629  	if cs.channelAlloc != nil {
   630  		cs.channelAlloc.Destroy()
   631  	}
   632  
   633  	// Ensure the connection is closed.
   634  	cs.conn.Close()
   635  
   636  	// Close all remaining fids.
   637  	for fid, fidRef := range cs.fids {
   638  		delete(cs.fids, fid)
   639  
   640  		// Drop final reference in the FID table. Note this should
   641  		// always close the file, since we've ensured that there are no
   642  		// handlers running via the wait for Pending => 0 below.
   643  		fidRef.DecRef()
   644  	}
   645  }
   646  
   647  // Handle handles a single connection.
   648  func (s *Server) Handle(conn *unet.Socket) error {
   649  	cs := &connState{
   650  		server: s,
   651  		fids:   make(map[FID]*fidRef),
   652  		tags:   make(map[Tag]chan struct{}),
   653  		conn:   conn,
   654  	}
   655  	defer cs.stop()
   656  
   657  	// Serve requests from conn in the current goroutine; handleRequests() will
   658  	// create more goroutines as needed.
   659  	cs.handleRequests()
   660  
   661  	return nil
   662  }
   663  
   664  // Serve handles requests from the bound socket.
   665  //
   666  // The passed serverSocket _must_ be created in packet mode.
   667  func (s *Server) Serve(serverSocket *unet.ServerSocket) error {
   668  	var wg sync.WaitGroup
   669  	defer wg.Wait()
   670  
   671  	for {
   672  		conn, err := serverSocket.Accept()
   673  		if err != nil {
   674  			// Something went wrong.
   675  			//
   676  			// Socket closed?
   677  			return err
   678  		}
   679  
   680  		wg.Add(1)
   681  		go func(conn *unet.Socket) { // S/R-SAFE: Irrelevant.
   682  			s.Handle(conn)
   683  			wg.Done()
   684  		}(conn)
   685  	}
   686  }