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 }