github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/p9/handlers.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 "fmt" 19 "io" 20 "os" 21 "path" 22 "strings" 23 "sync/atomic" 24 25 "golang.org/x/sys/unix" 26 "github.com/SagerNet/gvisor/pkg/abi/linux/errno" 27 "github.com/SagerNet/gvisor/pkg/errors" 28 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 29 "github.com/SagerNet/gvisor/pkg/fd" 30 "github.com/SagerNet/gvisor/pkg/log" 31 ) 32 33 // ExtractErrno extracts a unix.Errno from a error, best effort. 34 func ExtractErrno(err error) unix.Errno { 35 switch err { 36 case os.ErrNotExist: 37 return unix.ENOENT 38 case os.ErrExist: 39 return unix.EEXIST 40 case os.ErrPermission: 41 return unix.EACCES 42 case os.ErrInvalid: 43 return unix.EINVAL 44 } 45 46 // Attempt to unwrap. 47 switch e := err.(type) { 48 case unix.Errno: 49 return e 50 case *os.PathError: 51 return ExtractErrno(e.Err) 52 case *os.SyscallError: 53 return ExtractErrno(e.Err) 54 case *os.LinkError: 55 return ExtractErrno(e.Err) 56 } 57 58 // Default case. 59 log.Warningf("unknown error: %v", err) 60 return unix.EIO 61 } 62 63 // newErr returns a new error message from an error. 64 func newErr(err error) *Rlerror { 65 return &Rlerror{Error: uint32(ExtractErrno(err))} 66 } 67 68 // ExtractLinuxerrErrno extracts a *errors.Error from a error, best effort. 69 // TODO(b/34162363): Merge this with ExtractErrno. 70 func ExtractLinuxerrErrno(err error) *errors.Error { 71 switch err { 72 case os.ErrNotExist: 73 return linuxerr.ENOENT 74 case os.ErrExist: 75 return linuxerr.EEXIST 76 case os.ErrPermission: 77 return linuxerr.EACCES 78 case os.ErrInvalid: 79 return linuxerr.EINVAL 80 } 81 82 // Attempt to unwrap. 83 switch e := err.(type) { 84 case *errors.Error: 85 return e 86 case unix.Errno: 87 return linuxerr.ErrorFromErrno(errno.Errno(e)) 88 case *os.PathError: 89 return ExtractLinuxerrErrno(e.Err) 90 case *os.SyscallError: 91 return ExtractLinuxerrErrno(e.Err) 92 case *os.LinkError: 93 return ExtractLinuxerrErrno(e.Err) 94 } 95 96 // Default case. 97 log.Warningf("unknown error: %v", err) 98 return linuxerr.EIO 99 } 100 101 // newErrFromLinuxerr returns an Rlerror from the linuxerr list. 102 // TODO(b/34162363): Merge this with newErr. 103 func newErrFromLinuxerr(err error) *Rlerror { 104 return &Rlerror{Error: uint32(ExtractLinuxerrErrno(err).Errno())} 105 } 106 107 // handler is implemented for server-handled messages. 108 // 109 // See server.go for call information. 110 type handler interface { 111 // Handle handles the given message. 112 // 113 // This may modify the server state. The handle function must return a 114 // message which will be sent back to the client. It may be useful to 115 // use newErr to automatically extract an error message. 116 handle(cs *connState) message 117 } 118 119 // handle implements handler.handle. 120 func (t *Tversion) handle(cs *connState) message { 121 if t.MSize == 0 { 122 return newErr(unix.EINVAL) 123 } 124 if t.MSize > maximumLength { 125 return newErr(unix.EINVAL) 126 } 127 atomic.StoreUint32(&cs.messageSize, t.MSize) 128 requested, ok := parseVersion(t.Version) 129 if !ok { 130 return newErr(unix.EINVAL) 131 } 132 // The server cannot support newer versions that it doesn't know about. In this 133 // case we return EAGAIN to tell the client to try again with a lower version. 134 if requested > highestSupportedVersion { 135 return newErr(unix.EAGAIN) 136 } 137 // From Tversion(9P): "The server may respond with the client’s version 138 // string, or a version string identifying an earlier defined protocol version". 139 atomic.StoreUint32(&cs.version, requested) 140 return &Rversion{ 141 MSize: t.MSize, 142 Version: t.Version, 143 } 144 } 145 146 // handle implements handler.handle. 147 func (t *Tflush) handle(cs *connState) message { 148 cs.WaitTag(t.OldTag) 149 return &Rflush{} 150 } 151 152 // checkSafeName validates the name and returns nil or returns an error. 153 func checkSafeName(name string) error { 154 if name != "" && !strings.Contains(name, "/") && name != "." && name != ".." { 155 return nil 156 } 157 return unix.EINVAL 158 } 159 160 // handle implements handler.handle. 161 func (t *Tclunk) handle(cs *connState) message { 162 if !cs.DeleteFID(t.FID) { 163 return newErr(unix.EBADF) 164 } 165 return &Rclunk{} 166 } 167 168 func (t *Tsetattrclunk) handle(cs *connState) message { 169 ref, ok := cs.LookupFID(t.FID) 170 if !ok { 171 return newErr(unix.EBADF) 172 } 173 defer ref.DecRef() 174 175 setAttrErr := ref.safelyWrite(func() error { 176 // We don't allow setattr on files that have been deleted. 177 // This might be technically incorrect, as it's possible that 178 // there were multiple links and you can still change the 179 // corresponding inode information. 180 if ref.isDeleted() { 181 return unix.EINVAL 182 } 183 184 // Set the attributes. 185 return ref.file.SetAttr(t.Valid, t.SetAttr) 186 }) 187 188 // Try to delete FID even in case of failure above. Since the state of the 189 // file is unknown to the caller, it will not attempt to close the file again. 190 if !cs.DeleteFID(t.FID) { 191 return newErr(unix.EBADF) 192 } 193 if setAttrErr != nil { 194 return newErr(setAttrErr) 195 } 196 return &Rsetattrclunk{} 197 } 198 199 // handle implements handler.handle. 200 func (t *Tremove) handle(cs *connState) message { 201 ref, ok := cs.LookupFID(t.FID) 202 if !ok { 203 return newErr(unix.EBADF) 204 } 205 defer ref.DecRef() 206 207 // Frustratingly, because we can't be guaranteed that a rename is not 208 // occurring simultaneously with this removal, we need to acquire the 209 // global rename lock for this kind of remove operation to ensure that 210 // ref.parent does not change out from underneath us. 211 // 212 // This is why Tremove is a bad idea, and clients should generally use 213 // Tunlinkat. All p9 clients will use Tunlinkat. 214 err := ref.safelyGlobal(func() error { 215 // Is this a root? Can't remove that. 216 if ref.isRoot() { 217 return unix.EINVAL 218 } 219 220 // N.B. this remove operation is permitted, even if the file is open. 221 // See also rename below for reasoning. 222 223 // Is this file already deleted? 224 if ref.isDeleted() { 225 return unix.EINVAL 226 } 227 228 // Retrieve the file's proper name. 229 name := ref.parent.pathNode.nameFor(ref) 230 231 // Attempt the removal. 232 if err := ref.parent.file.UnlinkAt(name, 0); err != nil { 233 return err 234 } 235 236 // Mark all relevant fids as deleted. We don't need to lock any 237 // individual nodes because we already hold the global lock. 238 ref.parent.markChildDeleted(name) 239 return nil 240 }) 241 242 // "The remove request asks the file server both to remove the file 243 // represented by fid and to clunk the fid, even if the remove fails." 244 // 245 // "It is correct to consider remove to be a clunk with the side effect 246 // of removing the file if permissions allow." 247 // https://swtch.com/plan9port/man/man9/remove.html 248 if !cs.DeleteFID(t.FID) { 249 return newErr(unix.EBADF) 250 } 251 if err != nil { 252 return newErr(err) 253 } 254 255 return &Rremove{} 256 } 257 258 // handle implements handler.handle. 259 // 260 // We don't support authentication, so this just returns ENOSYS. 261 func (t *Tauth) handle(cs *connState) message { 262 return newErr(unix.ENOSYS) 263 } 264 265 // handle implements handler.handle. 266 func (t *Tattach) handle(cs *connState) message { 267 // Ensure no authentication FID is provided. 268 if t.Auth.AuthenticationFID != NoFID { 269 return newErr(unix.EINVAL) 270 } 271 272 // Must provide an absolute path. 273 if path.IsAbs(t.Auth.AttachName) { 274 // Trim off the leading / if the path is absolute. We always 275 // treat attach paths as absolute and call attach with the root 276 // argument on the server file for clarity. 277 t.Auth.AttachName = t.Auth.AttachName[1:] 278 } 279 280 // Do the attach on the root. 281 sf, err := cs.server.attacher.Attach() 282 if err != nil { 283 return newErr(err) 284 } 285 qid, valid, attr, err := sf.GetAttr(AttrMaskAll()) 286 if err != nil { 287 sf.Close() // Drop file. 288 return newErr(err) 289 } 290 if !valid.Mode { 291 sf.Close() // Drop file. 292 return newErr(unix.EINVAL) 293 } 294 295 // Build a transient reference. 296 root := &fidRef{ 297 server: cs.server, 298 parent: nil, 299 file: sf, 300 refs: 1, 301 mode: attr.Mode.FileType(), 302 pathNode: cs.server.pathTree, 303 } 304 defer root.DecRef() 305 306 // Attach the root? 307 if len(t.Auth.AttachName) == 0 { 308 cs.InsertFID(t.FID, root) 309 return &Rattach{QID: qid} 310 } 311 312 // We want the same traversal checks to apply on attach, so always 313 // attach at the root and use the regular walk paths. 314 names := strings.Split(t.Auth.AttachName, "/") 315 _, newRef, _, _, err := doWalk(cs, root, names, false) 316 if err != nil { 317 return newErr(err) 318 } 319 defer newRef.DecRef() 320 321 // Insert the FID. 322 cs.InsertFID(t.FID, newRef) 323 return &Rattach{QID: qid} 324 } 325 326 // CanOpen returns whether this file open can be opened, read and written to. 327 // 328 // This includes everything except symlinks and sockets. 329 func CanOpen(mode FileMode) bool { 330 return mode.IsRegular() || mode.IsDir() || mode.IsNamedPipe() || mode.IsBlockDevice() || mode.IsCharacterDevice() 331 } 332 333 // handle implements handler.handle. 334 func (t *Tlopen) handle(cs *connState) message { 335 ref, ok := cs.LookupFID(t.FID) 336 if !ok { 337 return newErr(unix.EBADF) 338 } 339 defer ref.DecRef() 340 341 var ( 342 qid QID 343 ioUnit uint32 344 osFile *fd.FD 345 ) 346 if err := ref.safelyRead(func() (err error) { 347 // Has it been deleted already? 348 if ref.isDeleted() { 349 return unix.EINVAL 350 } 351 352 // Has it been opened already? 353 if ref.opened || !CanOpen(ref.mode) { 354 return unix.EINVAL 355 } 356 357 if ref.mode.IsDir() { 358 // Directory must be opened ReadOnly. 359 if t.Flags&OpenFlagsModeMask != ReadOnly { 360 return unix.EISDIR 361 } 362 // Directory not truncatable. 363 if t.Flags&OpenTruncate != 0 { 364 return unix.EISDIR 365 } 366 } 367 368 osFile, qid, ioUnit, err = ref.file.Open(t.Flags) 369 return err 370 }); err != nil { 371 return newErr(err) 372 } 373 374 // Mark file as opened and set open mode. 375 ref.opened = true 376 ref.openFlags = t.Flags 377 378 rlopen := &Rlopen{QID: qid, IoUnit: ioUnit} 379 rlopen.SetFilePayload(osFile) 380 return rlopen 381 } 382 383 func (t *Tlcreate) do(cs *connState, uid UID) (*Rlcreate, error) { 384 if err := checkSafeName(t.Name); err != nil { 385 return nil, err 386 } 387 388 ref, ok := cs.LookupFID(t.FID) 389 if !ok { 390 return nil, unix.EBADF 391 } 392 defer ref.DecRef() 393 394 var ( 395 osFile *fd.FD 396 nsf File 397 qid QID 398 ioUnit uint32 399 newRef *fidRef 400 ) 401 if err := ref.safelyWrite(func() (err error) { 402 // Don't allow creation from non-directories or deleted directories. 403 if ref.isDeleted() || !ref.mode.IsDir() { 404 return unix.EINVAL 405 } 406 407 // Not allowed on open directories. 408 if ref.opened { 409 return unix.EINVAL 410 } 411 412 // Do the create. 413 osFile, nsf, qid, ioUnit, err = ref.file.Create(t.Name, t.OpenFlags, t.Permissions, uid, t.GID) 414 if err != nil { 415 return err 416 } 417 418 newRef = &fidRef{ 419 server: cs.server, 420 parent: ref, 421 file: nsf, 422 opened: true, 423 openFlags: t.OpenFlags, 424 mode: ModeRegular, 425 pathNode: ref.pathNode.pathNodeFor(t.Name), 426 } 427 ref.pathNode.addChild(newRef, t.Name) 428 ref.IncRef() // Acquire parent reference. 429 return nil 430 }); err != nil { 431 return nil, err 432 } 433 434 // Replace the FID reference. 435 cs.InsertFID(t.FID, newRef) 436 437 rlcreate := &Rlcreate{Rlopen: Rlopen{QID: qid, IoUnit: ioUnit}} 438 rlcreate.SetFilePayload(osFile) 439 return rlcreate, nil 440 } 441 442 // handle implements handler.handle. 443 func (t *Tlcreate) handle(cs *connState) message { 444 rlcreate, err := t.do(cs, NoUID) 445 if err != nil { 446 return newErr(err) 447 } 448 return rlcreate 449 } 450 451 // handle implements handler.handle. 452 func (t *Tsymlink) handle(cs *connState) message { 453 rsymlink, err := t.do(cs, NoUID) 454 if err != nil { 455 return newErr(err) 456 } 457 return rsymlink 458 } 459 460 func (t *Tsymlink) do(cs *connState, uid UID) (*Rsymlink, error) { 461 if err := checkSafeName(t.Name); err != nil { 462 return nil, err 463 } 464 465 ref, ok := cs.LookupFID(t.Directory) 466 if !ok { 467 return nil, unix.EBADF 468 } 469 defer ref.DecRef() 470 471 var qid QID 472 if err := ref.safelyWrite(func() (err error) { 473 // Don't allow symlinks from non-directories or deleted directories. 474 if ref.isDeleted() || !ref.mode.IsDir() { 475 return unix.EINVAL 476 } 477 478 // Not allowed on open directories. 479 if ref.opened { 480 return unix.EINVAL 481 } 482 483 // Do the symlink. 484 qid, err = ref.file.Symlink(t.Target, t.Name, uid, t.GID) 485 return err 486 }); err != nil { 487 return nil, err 488 } 489 490 return &Rsymlink{QID: qid}, nil 491 } 492 493 // handle implements handler.handle. 494 func (t *Tlink) handle(cs *connState) message { 495 if err := checkSafeName(t.Name); err != nil { 496 return newErr(err) 497 } 498 499 ref, ok := cs.LookupFID(t.Directory) 500 if !ok { 501 return newErr(unix.EBADF) 502 } 503 defer ref.DecRef() 504 505 refTarget, ok := cs.LookupFID(t.Target) 506 if !ok { 507 return newErr(unix.EBADF) 508 } 509 defer refTarget.DecRef() 510 511 if err := ref.safelyWrite(func() (err error) { 512 // Don't allow create links from non-directories or deleted directories. 513 if ref.isDeleted() || !ref.mode.IsDir() { 514 return unix.EINVAL 515 } 516 517 // Not allowed on open directories. 518 if ref.opened { 519 return unix.EINVAL 520 } 521 522 // Do the link. 523 return ref.file.Link(refTarget.file, t.Name) 524 }); err != nil { 525 return newErr(err) 526 } 527 528 return &Rlink{} 529 } 530 531 // handle implements handler.handle. 532 func (t *Trenameat) handle(cs *connState) message { 533 if err := checkSafeName(t.OldName); err != nil { 534 return newErr(err) 535 } 536 if err := checkSafeName(t.NewName); err != nil { 537 return newErr(err) 538 } 539 540 ref, ok := cs.LookupFID(t.OldDirectory) 541 if !ok { 542 return newErr(unix.EBADF) 543 } 544 defer ref.DecRef() 545 546 refTarget, ok := cs.LookupFID(t.NewDirectory) 547 if !ok { 548 return newErr(unix.EBADF) 549 } 550 defer refTarget.DecRef() 551 552 // Perform the rename holding the global lock. 553 if err := ref.safelyGlobal(func() (err error) { 554 // Don't allow renaming across deleted directories. 555 if ref.isDeleted() || !ref.mode.IsDir() || refTarget.isDeleted() || !refTarget.mode.IsDir() { 556 return unix.EINVAL 557 } 558 559 // Not allowed on open directories. 560 if ref.opened { 561 return unix.EINVAL 562 } 563 564 // Is this the same file? If yes, short-circuit and return success. 565 if ref.pathNode == refTarget.pathNode && t.OldName == t.NewName { 566 return nil 567 } 568 569 // Attempt the actual rename. 570 if err := ref.file.RenameAt(t.OldName, refTarget.file, t.NewName); err != nil { 571 return err 572 } 573 574 // Update the path tree. 575 ref.renameChildTo(t.OldName, refTarget, t.NewName) 576 return nil 577 }); err != nil { 578 return newErr(err) 579 } 580 581 return &Rrenameat{} 582 } 583 584 // handle implements handler.handle. 585 func (t *Tunlinkat) handle(cs *connState) message { 586 if err := checkSafeName(t.Name); err != nil { 587 return newErr(err) 588 } 589 590 ref, ok := cs.LookupFID(t.Directory) 591 if !ok { 592 return newErr(unix.EBADF) 593 } 594 defer ref.DecRef() 595 596 if err := ref.safelyWrite(func() (err error) { 597 // Don't allow deletion from non-directories or deleted directories. 598 if ref.isDeleted() || !ref.mode.IsDir() { 599 return unix.EINVAL 600 } 601 602 // Not allowed on open directories. 603 if ref.opened { 604 return unix.EINVAL 605 } 606 607 // Before we do the unlink itself, we need to ensure that there 608 // are no operations in flight on associated path node. The 609 // child's path node lock must be held to ensure that the 610 // unlinkat marking the child deleted below is atomic with 611 // respect to any other read or write operations. 612 // 613 // This is one case where we have a lock ordering issue, but 614 // since we always acquire deeper in the hierarchy, we know 615 // that we are free of lock cycles. 616 childPathNode := ref.pathNode.pathNodeFor(t.Name) 617 childPathNode.opMu.Lock() 618 defer childPathNode.opMu.Unlock() 619 620 // Do the unlink. 621 err = ref.file.UnlinkAt(t.Name, t.Flags) 622 if err != nil { 623 return err 624 } 625 626 // Mark the path as deleted. 627 ref.markChildDeleted(t.Name) 628 return nil 629 }); err != nil { 630 return newErr(err) 631 } 632 633 return &Runlinkat{} 634 } 635 636 // handle implements handler.handle. 637 func (t *Trename) handle(cs *connState) message { 638 if err := checkSafeName(t.Name); err != nil { 639 return newErr(err) 640 } 641 642 ref, ok := cs.LookupFID(t.FID) 643 if !ok { 644 return newErr(unix.EBADF) 645 } 646 defer ref.DecRef() 647 648 refTarget, ok := cs.LookupFID(t.Directory) 649 if !ok { 650 return newErr(unix.EBADF) 651 } 652 defer refTarget.DecRef() 653 654 if err := ref.safelyGlobal(func() (err error) { 655 // Don't allow a root rename. 656 if ref.isRoot() { 657 return unix.EINVAL 658 } 659 660 // Don't allow renaming deleting entries, or target non-directories. 661 if ref.isDeleted() || refTarget.isDeleted() || !refTarget.mode.IsDir() { 662 return unix.EINVAL 663 } 664 665 // If the parent is deleted, but we not, something is seriously wrong. 666 // It's fail to die at this point with an assertion failure. 667 if ref.parent.isDeleted() { 668 panic(fmt.Sprintf("parent %+v deleted, child %+v is not", ref.parent, ref)) 669 } 670 671 // N.B. The rename operation is allowed to proceed on open files. It 672 // does impact the state of its parent, but this is merely a sanity 673 // check in any case, and the operation is safe. There may be other 674 // files corresponding to the same path that are renamed anyways. 675 676 // Check for the exact same file and short-circuit. 677 oldName := ref.parent.pathNode.nameFor(ref) 678 if ref.parent.pathNode == refTarget.pathNode && oldName == t.Name { 679 return nil 680 } 681 682 // Call the rename method on the parent. 683 if err := ref.parent.file.RenameAt(oldName, refTarget.file, t.Name); err != nil { 684 return err 685 } 686 687 // Update the path tree. 688 ref.parent.renameChildTo(oldName, refTarget, t.Name) 689 return nil 690 }); err != nil { 691 return newErr(err) 692 } 693 694 return &Rrename{} 695 } 696 697 // handle implements handler.handle. 698 func (t *Treadlink) handle(cs *connState) message { 699 ref, ok := cs.LookupFID(t.FID) 700 if !ok { 701 return newErr(unix.EBADF) 702 } 703 defer ref.DecRef() 704 705 var target string 706 if err := ref.safelyRead(func() (err error) { 707 // Don't allow readlink on deleted files. There is no need to 708 // check if this file is opened because symlinks cannot be 709 // opened. 710 if ref.isDeleted() || !ref.mode.IsSymlink() { 711 return unix.EINVAL 712 } 713 714 // Do the read. 715 target, err = ref.file.Readlink() 716 return err 717 }); err != nil { 718 return newErr(err) 719 } 720 721 return &Rreadlink{target} 722 } 723 724 // handle implements handler.handle. 725 func (t *Tread) handle(cs *connState) message { 726 ref, ok := cs.LookupFID(t.FID) 727 if !ok { 728 return newErr(unix.EBADF) 729 } 730 defer ref.DecRef() 731 732 // Constrain the size of the read buffer. 733 if int(t.Count) > int(maximumLength) { 734 return newErr(unix.ENOBUFS) 735 } 736 737 var ( 738 data = make([]byte, t.Count) 739 n int 740 ) 741 if err := ref.safelyRead(func() (err error) { 742 // Has it been opened already? 743 if !ref.opened { 744 return unix.EINVAL 745 } 746 747 // Can it be read? Check permissions. 748 if ref.openFlags&OpenFlagsModeMask == WriteOnly { 749 return unix.EPERM 750 } 751 752 n, err = ref.file.ReadAt(data, t.Offset) 753 return err 754 }); err != nil && err != io.EOF { 755 return newErr(err) 756 } 757 758 return &Rread{Data: data[:n]} 759 } 760 761 // handle implements handler.handle. 762 func (t *Twrite) handle(cs *connState) message { 763 ref, ok := cs.LookupFID(t.FID) 764 if !ok { 765 return newErr(unix.EBADF) 766 } 767 defer ref.DecRef() 768 769 var n int 770 if err := ref.safelyRead(func() (err error) { 771 // Has it been opened already? 772 if !ref.opened { 773 return unix.EINVAL 774 } 775 776 // Can it be written? Check permissions. 777 if ref.openFlags&OpenFlagsModeMask == ReadOnly { 778 return unix.EPERM 779 } 780 781 n, err = ref.file.WriteAt(t.Data, t.Offset) 782 return err 783 }); err != nil { 784 return newErr(err) 785 } 786 787 return &Rwrite{Count: uint32(n)} 788 } 789 790 // handle implements handler.handle. 791 func (t *Tmknod) handle(cs *connState) message { 792 rmknod, err := t.do(cs, NoUID) 793 if err != nil { 794 return newErr(err) 795 } 796 return rmknod 797 } 798 799 func (t *Tmknod) do(cs *connState, uid UID) (*Rmknod, error) { 800 if err := checkSafeName(t.Name); err != nil { 801 return nil, err 802 } 803 804 ref, ok := cs.LookupFID(t.Directory) 805 if !ok { 806 return nil, unix.EBADF 807 } 808 defer ref.DecRef() 809 810 var qid QID 811 if err := ref.safelyWrite(func() (err error) { 812 // Don't allow mknod on deleted files. 813 if ref.isDeleted() || !ref.mode.IsDir() { 814 return unix.EINVAL 815 } 816 817 // Not allowed on open directories. 818 if ref.opened { 819 return unix.EINVAL 820 } 821 822 // Do the mknod. 823 qid, err = ref.file.Mknod(t.Name, t.Mode, t.Major, t.Minor, uid, t.GID) 824 return err 825 }); err != nil { 826 return nil, err 827 } 828 829 return &Rmknod{QID: qid}, nil 830 } 831 832 // handle implements handler.handle. 833 func (t *Tmkdir) handle(cs *connState) message { 834 rmkdir, err := t.do(cs, NoUID) 835 if err != nil { 836 return newErr(err) 837 } 838 return rmkdir 839 } 840 841 func (t *Tmkdir) do(cs *connState, uid UID) (*Rmkdir, error) { 842 if err := checkSafeName(t.Name); err != nil { 843 return nil, err 844 } 845 846 ref, ok := cs.LookupFID(t.Directory) 847 if !ok { 848 return nil, unix.EBADF 849 } 850 defer ref.DecRef() 851 852 var qid QID 853 if err := ref.safelyWrite(func() (err error) { 854 // Don't allow mkdir on deleted files. 855 if ref.isDeleted() || !ref.mode.IsDir() { 856 return unix.EINVAL 857 } 858 859 // Not allowed on open directories. 860 if ref.opened { 861 return unix.EINVAL 862 } 863 864 // Do the mkdir. 865 qid, err = ref.file.Mkdir(t.Name, t.Permissions, uid, t.GID) 866 return err 867 }); err != nil { 868 return nil, err 869 } 870 871 return &Rmkdir{QID: qid}, nil 872 } 873 874 // handle implements handler.handle. 875 func (t *Tgetattr) handle(cs *connState) message { 876 ref, ok := cs.LookupFID(t.FID) 877 if !ok { 878 return newErr(unix.EBADF) 879 } 880 defer ref.DecRef() 881 882 // We allow getattr on deleted files. Depending on the backing 883 // implementation, it's possible that races exist that might allow 884 // fetching attributes of other files. But we need to generally allow 885 // refreshing attributes and this is a minor leak, if at all. 886 887 var ( 888 qid QID 889 valid AttrMask 890 attr Attr 891 ) 892 if err := ref.safelyRead(func() (err error) { 893 qid, valid, attr, err = ref.file.GetAttr(t.AttrMask) 894 return err 895 }); err != nil { 896 return newErr(err) 897 } 898 899 return &Rgetattr{QID: qid, Valid: valid, Attr: attr} 900 } 901 902 // handle implements handler.handle. 903 func (t *Tsetattr) handle(cs *connState) message { 904 ref, ok := cs.LookupFID(t.FID) 905 if !ok { 906 return newErr(unix.EBADF) 907 } 908 defer ref.DecRef() 909 910 if err := ref.safelyWrite(func() error { 911 // We don't allow setattr on files that have been deleted. 912 // This might be technically incorrect, as it's possible that 913 // there were multiple links and you can still change the 914 // corresponding inode information. 915 if ref.isDeleted() { 916 return unix.EINVAL 917 } 918 919 // Set the attributes. 920 return ref.file.SetAttr(t.Valid, t.SetAttr) 921 }); err != nil { 922 return newErr(err) 923 } 924 925 return &Rsetattr{} 926 } 927 928 // handle implements handler.handle. 929 func (t *Tallocate) handle(cs *connState) message { 930 ref, ok := cs.LookupFID(t.FID) 931 if !ok { 932 return newErr(unix.EBADF) 933 } 934 defer ref.DecRef() 935 936 if err := ref.safelyWrite(func() error { 937 // Has it been opened already? 938 if !ref.opened { 939 return unix.EINVAL 940 } 941 942 // Can it be written? Check permissions. 943 if ref.openFlags&OpenFlagsModeMask == ReadOnly { 944 return unix.EBADF 945 } 946 947 // We don't allow allocate on files that have been deleted. 948 if ref.isDeleted() { 949 return unix.EINVAL 950 } 951 952 return ref.file.Allocate(t.Mode, t.Offset, t.Length) 953 }); err != nil { 954 return newErr(err) 955 } 956 957 return &Rallocate{} 958 } 959 960 // handle implements handler.handle. 961 func (t *Txattrwalk) handle(cs *connState) message { 962 ref, ok := cs.LookupFID(t.FID) 963 if !ok { 964 return newErr(unix.EBADF) 965 } 966 defer ref.DecRef() 967 968 // We don't support extended attributes. 969 return newErr(unix.ENODATA) 970 } 971 972 // handle implements handler.handle. 973 func (t *Txattrcreate) handle(cs *connState) message { 974 ref, ok := cs.LookupFID(t.FID) 975 if !ok { 976 return newErr(unix.EBADF) 977 } 978 defer ref.DecRef() 979 980 // We don't support extended attributes. 981 return newErr(unix.ENOSYS) 982 } 983 984 // handle implements handler.handle. 985 func (t *Tgetxattr) handle(cs *connState) message { 986 ref, ok := cs.LookupFID(t.FID) 987 if !ok { 988 return newErr(unix.EBADF) 989 } 990 defer ref.DecRef() 991 992 var val string 993 if err := ref.safelyRead(func() (err error) { 994 // Don't allow getxattr on files that have been deleted. 995 if ref.isDeleted() { 996 return unix.EINVAL 997 } 998 val, err = ref.file.GetXattr(t.Name, t.Size) 999 return err 1000 }); err != nil { 1001 return newErr(err) 1002 } 1003 return &Rgetxattr{Value: val} 1004 } 1005 1006 // handle implements handler.handle. 1007 func (t *Tsetxattr) handle(cs *connState) message { 1008 ref, ok := cs.LookupFID(t.FID) 1009 if !ok { 1010 return newErr(unix.EBADF) 1011 } 1012 defer ref.DecRef() 1013 1014 if err := ref.safelyWrite(func() error { 1015 // Don't allow setxattr on files that have been deleted. 1016 if ref.isDeleted() { 1017 return unix.EINVAL 1018 } 1019 return ref.file.SetXattr(t.Name, t.Value, t.Flags) 1020 }); err != nil { 1021 return newErr(err) 1022 } 1023 return &Rsetxattr{} 1024 } 1025 1026 // handle implements handler.handle. 1027 func (t *Tlistxattr) handle(cs *connState) message { 1028 ref, ok := cs.LookupFID(t.FID) 1029 if !ok { 1030 return newErr(unix.EBADF) 1031 } 1032 defer ref.DecRef() 1033 1034 var xattrs map[string]struct{} 1035 if err := ref.safelyRead(func() (err error) { 1036 // Don't allow listxattr on files that have been deleted. 1037 if ref.isDeleted() { 1038 return unix.EINVAL 1039 } 1040 xattrs, err = ref.file.ListXattr(t.Size) 1041 return err 1042 }); err != nil { 1043 return newErr(err) 1044 } 1045 1046 xattrList := make([]string, 0, len(xattrs)) 1047 for x := range xattrs { 1048 xattrList = append(xattrList, x) 1049 } 1050 return &Rlistxattr{Xattrs: xattrList} 1051 } 1052 1053 // handle implements handler.handle. 1054 func (t *Tremovexattr) handle(cs *connState) message { 1055 ref, ok := cs.LookupFID(t.FID) 1056 if !ok { 1057 return newErr(unix.EBADF) 1058 } 1059 defer ref.DecRef() 1060 1061 if err := ref.safelyWrite(func() error { 1062 // Don't allow removexattr on files that have been deleted. 1063 if ref.isDeleted() { 1064 return unix.EINVAL 1065 } 1066 return ref.file.RemoveXattr(t.Name) 1067 }); err != nil { 1068 return newErr(err) 1069 } 1070 return &Rremovexattr{} 1071 } 1072 1073 // handle implements handler.handle. 1074 func (t *Treaddir) handle(cs *connState) message { 1075 ref, ok := cs.LookupFID(t.Directory) 1076 if !ok { 1077 return newErr(unix.EBADF) 1078 } 1079 defer ref.DecRef() 1080 1081 var entries []Dirent 1082 if err := ref.safelyRead(func() (err error) { 1083 // Don't allow reading deleted directories. 1084 if ref.isDeleted() || !ref.mode.IsDir() { 1085 return unix.EINVAL 1086 } 1087 1088 // Has it been opened yet? 1089 if !ref.opened { 1090 return unix.EINVAL 1091 } 1092 1093 // Read the entries. 1094 entries, err = ref.file.Readdir(t.Offset, t.Count) 1095 if err != nil && err != io.EOF { 1096 return err 1097 } 1098 return nil 1099 }); err != nil { 1100 return newErr(err) 1101 } 1102 1103 return &Rreaddir{Count: t.Count, Entries: entries} 1104 } 1105 1106 // handle implements handler.handle. 1107 func (t *Tfsync) handle(cs *connState) message { 1108 ref, ok := cs.LookupFID(t.FID) 1109 if !ok { 1110 return newErr(unix.EBADF) 1111 } 1112 defer ref.DecRef() 1113 1114 if err := ref.safelyRead(func() (err error) { 1115 // Has it been opened yet? 1116 if !ref.opened { 1117 return unix.EINVAL 1118 } 1119 1120 // Perform the sync. 1121 return ref.file.FSync() 1122 }); err != nil { 1123 return newErr(err) 1124 } 1125 1126 return &Rfsync{} 1127 } 1128 1129 // handle implements handler.handle. 1130 func (t *Tstatfs) handle(cs *connState) message { 1131 ref, ok := cs.LookupFID(t.FID) 1132 if !ok { 1133 return newErr(unix.EBADF) 1134 } 1135 defer ref.DecRef() 1136 1137 st, err := ref.file.StatFS() 1138 if err != nil { 1139 return newErr(err) 1140 } 1141 1142 return &Rstatfs{st} 1143 } 1144 1145 // handle implements handler.handle. 1146 func (t *Tflushf) handle(cs *connState) message { 1147 ref, ok := cs.LookupFID(t.FID) 1148 if !ok { 1149 return newErr(unix.EBADF) 1150 } 1151 defer ref.DecRef() 1152 1153 if err := ref.safelyRead(ref.file.Flush); err != nil { 1154 return newErr(err) 1155 } 1156 1157 return &Rflushf{} 1158 } 1159 1160 // walkOne walks zero or one path elements. 1161 // 1162 // The slice passed as qids is append and returned. 1163 func walkOne(qids []QID, from File, names []string, getattr bool) ([]QID, File, AttrMask, Attr, error) { 1164 if len(names) > 1 { 1165 // We require exactly zero or one elements. 1166 return nil, nil, AttrMask{}, Attr{}, unix.EINVAL 1167 } 1168 var ( 1169 localQIDs []QID 1170 sf File 1171 valid AttrMask 1172 attr Attr 1173 err error 1174 ) 1175 switch { 1176 case getattr: 1177 localQIDs, sf, valid, attr, err = from.WalkGetAttr(names) 1178 // Can't put fallthrough in the if because Go. 1179 if err != unix.ENOSYS { 1180 break 1181 } 1182 fallthrough 1183 default: 1184 localQIDs, sf, err = from.Walk(names) 1185 if err != nil { 1186 // No way to walk this element. 1187 break 1188 } 1189 if getattr { 1190 _, valid, attr, err = sf.GetAttr(AttrMaskAll()) 1191 if err != nil { 1192 // Don't leak the file. 1193 sf.Close() 1194 } 1195 } 1196 } 1197 if err != nil { 1198 // Error walking, don't return anything. 1199 return nil, nil, AttrMask{}, Attr{}, err 1200 } 1201 if len(localQIDs) != 1 { 1202 // Expected a single QID. 1203 sf.Close() 1204 return nil, nil, AttrMask{}, Attr{}, unix.EINVAL 1205 } 1206 return append(qids, localQIDs...), sf, valid, attr, nil 1207 } 1208 1209 // doWalk walks from a given fidRef. 1210 // 1211 // This enforces that all intermediate nodes are walkable (directories). The 1212 // fidRef returned (newRef) has a reference associated with it that is now 1213 // owned by the caller and must be handled appropriately. 1214 func doWalk(cs *connState, ref *fidRef, names []string, getattr bool) (qids []QID, newRef *fidRef, valid AttrMask, attr Attr, err error) { 1215 // Check the names. 1216 for _, name := range names { 1217 err = checkSafeName(name) 1218 if err != nil { 1219 return 1220 } 1221 } 1222 1223 // Has it been opened already? 1224 err = ref.safelyRead(func() (err error) { 1225 if ref.opened { 1226 return unix.EBUSY 1227 } 1228 return nil 1229 }) 1230 if err != nil { 1231 return 1232 } 1233 1234 // Is this an empty list? Handle specially. We don't actually need to 1235 // validate anything since this is always permitted. 1236 if len(names) == 0 { 1237 var sf File // Temporary. 1238 if err := ref.maybeParent().safelyRead(func() (err error) { 1239 // Clone the single element. 1240 qids, sf, valid, attr, err = walkOne(nil, ref.file, nil, getattr) 1241 if err != nil { 1242 return err 1243 } 1244 1245 newRef = &fidRef{ 1246 server: cs.server, 1247 parent: ref.parent, 1248 file: sf, 1249 mode: ref.mode, 1250 pathNode: ref.pathNode, 1251 1252 // For the clone case, the cloned fid must 1253 // preserve the deleted property of the 1254 // original FID. 1255 deleted: ref.deleted, 1256 } 1257 if !ref.isRoot() { 1258 if !newRef.isDeleted() { 1259 // Add only if a non-root node; the same node. 1260 ref.parent.pathNode.addChild(newRef, ref.parent.pathNode.nameFor(ref)) 1261 } 1262 ref.parent.IncRef() // Acquire parent reference. 1263 } 1264 // doWalk returns a reference. 1265 newRef.IncRef() 1266 return nil 1267 }); err != nil { 1268 return nil, nil, AttrMask{}, Attr{}, err 1269 } 1270 // Do not return the new QID. 1271 return nil, newRef, valid, attr, nil 1272 } 1273 1274 // Do the walk, one element at a time. 1275 walkRef := ref 1276 walkRef.IncRef() 1277 for i := 0; i < len(names); i++ { 1278 // We won't allow beyond past symlinks; stop here if this isn't 1279 // a proper directory and we have additional paths to walk. 1280 if !walkRef.mode.IsDir() { 1281 walkRef.DecRef() // Drop walk reference; no lock required. 1282 return nil, nil, AttrMask{}, Attr{}, unix.EINVAL 1283 } 1284 1285 var sf File // Temporary. 1286 if err := walkRef.safelyRead(func() (err error) { 1287 // Pass getattr = true to walkOne since we need the file type for 1288 // newRef. 1289 qids, sf, valid, attr, err = walkOne(qids, walkRef.file, names[i:i+1], true) 1290 if err != nil { 1291 return err 1292 } 1293 1294 // Note that we don't need to acquire a lock on any of 1295 // these individual instances. That's because they are 1296 // not actually addressable via a FID. They are 1297 // anonymous. They exist in the tree for tracking 1298 // purposes. 1299 newRef := &fidRef{ 1300 server: cs.server, 1301 parent: walkRef, 1302 file: sf, 1303 mode: attr.Mode.FileType(), 1304 pathNode: walkRef.pathNode.pathNodeFor(names[i]), 1305 } 1306 walkRef.pathNode.addChild(newRef, names[i]) 1307 // We allow our walk reference to become the new parent 1308 // reference here and so we don't IncRef. Instead, just 1309 // set walkRef to the newRef above and acquire a new 1310 // walk reference. 1311 walkRef = newRef 1312 walkRef.IncRef() 1313 return nil 1314 }); err != nil { 1315 walkRef.DecRef() // Drop the old walkRef. 1316 return nil, nil, AttrMask{}, Attr{}, err 1317 } 1318 } 1319 1320 // Success. 1321 return qids, walkRef, valid, attr, nil 1322 } 1323 1324 // handle implements handler.handle. 1325 func (t *Twalk) handle(cs *connState) message { 1326 ref, ok := cs.LookupFID(t.FID) 1327 if !ok { 1328 return newErr(unix.EBADF) 1329 } 1330 defer ref.DecRef() 1331 1332 // Do the walk. 1333 qids, newRef, _, _, err := doWalk(cs, ref, t.Names, false) 1334 if err != nil { 1335 return newErr(err) 1336 } 1337 defer newRef.DecRef() 1338 1339 // Install the new FID. 1340 cs.InsertFID(t.NewFID, newRef) 1341 return &Rwalk{QIDs: qids} 1342 } 1343 1344 // handle implements handler.handle. 1345 func (t *Twalkgetattr) handle(cs *connState) message { 1346 ref, ok := cs.LookupFID(t.FID) 1347 if !ok { 1348 return newErr(unix.EBADF) 1349 } 1350 defer ref.DecRef() 1351 1352 // Do the walk. 1353 qids, newRef, valid, attr, err := doWalk(cs, ref, t.Names, true) 1354 if err != nil { 1355 return newErr(err) 1356 } 1357 defer newRef.DecRef() 1358 1359 // Install the new FID. 1360 cs.InsertFID(t.NewFID, newRef) 1361 return &Rwalkgetattr{QIDs: qids, Valid: valid, Attr: attr} 1362 } 1363 1364 // handle implements handler.handle. 1365 func (t *Tucreate) handle(cs *connState) message { 1366 rlcreate, err := t.Tlcreate.do(cs, t.UID) 1367 if err != nil { 1368 return newErr(err) 1369 } 1370 return &Rucreate{*rlcreate} 1371 } 1372 1373 // handle implements handler.handle. 1374 func (t *Tumkdir) handle(cs *connState) message { 1375 rmkdir, err := t.Tmkdir.do(cs, t.UID) 1376 if err != nil { 1377 return newErr(err) 1378 } 1379 return &Rumkdir{*rmkdir} 1380 } 1381 1382 // handle implements handler.handle. 1383 func (t *Tusymlink) handle(cs *connState) message { 1384 rsymlink, err := t.Tsymlink.do(cs, t.UID) 1385 if err != nil { 1386 return newErr(err) 1387 } 1388 return &Rusymlink{*rsymlink} 1389 } 1390 1391 // handle implements handler.handle. 1392 func (t *Tumknod) handle(cs *connState) message { 1393 rmknod, err := t.Tmknod.do(cs, t.UID) 1394 if err != nil { 1395 return newErr(err) 1396 } 1397 return &Rumknod{*rmknod} 1398 } 1399 1400 // handle implements handler.handle. 1401 func (t *Tlconnect) handle(cs *connState) message { 1402 ref, ok := cs.LookupFID(t.FID) 1403 if !ok { 1404 return newErr(unix.EBADF) 1405 } 1406 defer ref.DecRef() 1407 1408 var osFile *fd.FD 1409 if err := ref.safelyRead(func() (err error) { 1410 // Don't allow connecting to deleted files. 1411 if ref.isDeleted() || !ref.mode.IsSocket() { 1412 return unix.EINVAL 1413 } 1414 1415 // Do the connect. 1416 osFile, err = ref.file.Connect(t.Flags) 1417 return err 1418 }); err != nil { 1419 return newErr(err) 1420 } 1421 1422 rlconnect := &Rlconnect{} 1423 rlconnect.SetFilePayload(osFile) 1424 return rlconnect 1425 } 1426 1427 // handle implements handler.handle. 1428 func (t *Tchannel) handle(cs *connState) message { 1429 // Ensure that channels are enabled. 1430 if err := cs.initializeChannels(); err != nil { 1431 return newErr(err) 1432 } 1433 1434 ch := cs.lookupChannel(t.ID) 1435 if ch == nil { 1436 return newErr(unix.ENOSYS) 1437 } 1438 1439 // Return the payload. Note that we need to duplicate the file 1440 // descriptor for the channel allocator, because sending is a 1441 // destructive operation between sendRecvLegacy (and now the newer 1442 // channel send operations). Same goes for the client FD. 1443 rchannel := &Rchannel{ 1444 Offset: uint64(ch.desc.Offset), 1445 Length: uint64(ch.desc.Length), 1446 } 1447 switch t.Control { 1448 case 0: 1449 // Open the main data channel. 1450 mfd, err := unix.Dup(int(cs.channelAlloc.FD())) 1451 if err != nil { 1452 return newErr(err) 1453 } 1454 rchannel.SetFilePayload(fd.New(mfd)) 1455 case 1: 1456 cfd, err := unix.Dup(ch.client.FD()) 1457 if err != nil { 1458 return newErr(err) 1459 } 1460 rchannel.SetFilePayload(fd.New(cfd)) 1461 default: 1462 return newErr(unix.EINVAL) 1463 } 1464 return rchannel 1465 } 1466 1467 // handle implements handler.handle. 1468 func (t *Tmultigetattr) handle(cs *connState) message { 1469 for i, name := range t.Names { 1470 if len(name) == 0 && i == 0 { 1471 // Empty name is allowed on the first entry to indicate that the current 1472 // FID needs to be included in the result. 1473 continue 1474 } 1475 if err := checkSafeName(name); err != nil { 1476 return newErr(err) 1477 } 1478 } 1479 ref, ok := cs.LookupFID(t.FID) 1480 if !ok { 1481 return newErr(unix.EBADF) 1482 } 1483 defer ref.DecRef() 1484 1485 var stats []FullStat 1486 if err := ref.safelyRead(func() (err error) { 1487 stats, err = ref.file.MultiGetAttr(t.Names) 1488 return err 1489 }); err != nil { 1490 return newErr(err) 1491 } 1492 return &Rmultigetattr{Stats: stats} 1493 }