github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/fsgofer/fsgofer_test.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 fsgofer 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "net" 21 "os" 22 "path" 23 "path/filepath" 24 "testing" 25 26 "github.com/syndtr/gocapability/capability" 27 "golang.org/x/sys/unix" 28 "github.com/SagerNet/gvisor/pkg/fd" 29 "github.com/SagerNet/gvisor/pkg/log" 30 "github.com/SagerNet/gvisor/pkg/p9" 31 "github.com/SagerNet/gvisor/pkg/test/testutil" 32 "github.com/SagerNet/gvisor/runsc/specutils" 33 ) 34 35 // Nodoby is the standard UID/GID for the nobody user/group. 36 const nobody = 65534 37 38 var allOpenFlags = []p9.OpenFlags{p9.ReadOnly, p9.WriteOnly, p9.ReadWrite} 39 40 var ( 41 allTypes = []uint32{unix.S_IFREG, unix.S_IFDIR, unix.S_IFLNK} 42 43 // allConfs is set in init(). 44 allConfs []Config 45 46 rwConfs = []Config{{ROMount: false}} 47 roConfs = []Config{{ROMount: true}} 48 ) 49 50 func init() { 51 log.SetLevel(log.Debug) 52 53 allConfs = append(allConfs, rwConfs...) 54 allConfs = append(allConfs, roConfs...) 55 56 if err := OpenProcSelfFD(); err != nil { 57 panic(err) 58 } 59 } 60 61 func configTestName(conf *Config) string { 62 if conf.ROMount { 63 return "ROMount" 64 } 65 return "RWMount" 66 } 67 68 func assertPanic(t *testing.T, f func()) { 69 defer func() { 70 if r := recover(); r == nil { 71 t.Errorf("function did not panic") 72 } 73 }() 74 f() 75 } 76 77 func testReadWrite(f p9.File, flags p9.OpenFlags, content []byte) error { 78 want := make([]byte, len(content)) 79 copy(want, content) 80 81 b := []byte("test-1-2-3") 82 w, err := f.WriteAt(b, uint64(len(content))) 83 if flags == p9.WriteOnly || flags == p9.ReadWrite { 84 if err != nil { 85 return fmt.Errorf("WriteAt(): %v", err) 86 } 87 if w != len(b) { 88 return fmt.Errorf("WriteAt() was partial, got: %d, want: %d", w, len(b)) 89 } 90 want = append(want, b...) 91 } else { 92 if e, ok := err.(unix.Errno); !ok || e != unix.EBADF { 93 return fmt.Errorf("WriteAt() should have failed, got: %d, want: EBADFD", err) 94 } 95 } 96 97 rBuf := make([]byte, len(want)) 98 r, err := f.ReadAt(rBuf, 0) 99 if flags == p9.ReadOnly || flags == p9.ReadWrite { 100 if err != nil { 101 return fmt.Errorf("ReadAt(): %v", err) 102 } 103 if r != len(rBuf) { 104 return fmt.Errorf("ReadAt() was partial, got: %d, want: %d", r, len(rBuf)) 105 } 106 if string(rBuf) != string(want) { 107 return fmt.Errorf("ReadAt() wrong data, got: %s, want: %s", string(rBuf), want) 108 } 109 } else { 110 if e, ok := err.(unix.Errno); !ok || e != unix.EBADF { 111 return fmt.Errorf("ReadAt() should have failed, got: %d, want: EBADFD", err) 112 } 113 } 114 return nil 115 } 116 117 type state struct { 118 root *localFile 119 file *localFile 120 conf Config 121 fileType uint32 122 } 123 124 func (s state) String() string { 125 return fmt.Sprintf("type(%v)", s.fileType) 126 } 127 128 func typeName(fileType uint32) string { 129 switch fileType { 130 case unix.S_IFREG: 131 return "file" 132 case unix.S_IFDIR: 133 return "directory" 134 case unix.S_IFLNK: 135 return "symlink" 136 default: 137 panic(fmt.Sprintf("invalid file type for test: %d", fileType)) 138 } 139 } 140 141 func runAll(t *testing.T, test func(*testing.T, state)) { 142 runCustom(t, allTypes, allConfs, test) 143 } 144 145 func runCustom(t *testing.T, types []uint32, confs []Config, test func(*testing.T, state)) { 146 for _, c := range confs { 147 for _, ft := range types { 148 name := fmt.Sprintf("%s/%s", configTestName(&c), typeName(ft)) 149 t.Run(name, func(t *testing.T) { 150 path, name, err := setup(ft) 151 if err != nil { 152 t.Fatalf("%v", err) 153 } 154 defer os.RemoveAll(path) 155 156 a, err := NewAttachPoint(path, c) 157 if err != nil { 158 t.Fatalf("NewAttachPoint failed: %v", err) 159 } 160 root, err := a.Attach() 161 if err != nil { 162 t.Fatalf("Attach failed, err: %v", err) 163 } 164 165 _, file, err := root.Walk([]string{name}) 166 if err != nil { 167 root.Close() 168 t.Fatalf("root.Walk({%q}) failed, err: %v", "symlink", err) 169 } 170 171 st := state{ 172 root: root.(*localFile), 173 file: file.(*localFile), 174 conf: c, 175 fileType: ft, 176 } 177 test(t, st) 178 file.Close() 179 root.Close() 180 }) 181 } 182 } 183 } 184 185 func setup(fileType uint32) (string, string, error) { 186 path, err := ioutil.TempDir(testutil.TmpDir(), "root-") 187 if err != nil { 188 return "", "", fmt.Errorf("ioutil.TempDir() failed, err: %v", err) 189 } 190 191 // First attach with writable configuration to setup tree. 192 a, err := NewAttachPoint(path, Config{}) 193 if err != nil { 194 return "", "", err 195 } 196 root, err := a.Attach() 197 if err != nil { 198 return "", "", fmt.Errorf("Attach failed, err: %v", err) 199 } 200 defer root.Close() 201 202 var name string 203 switch fileType { 204 case unix.S_IFREG: 205 name = "file" 206 fd, f, _, _, err := root.Create(name, p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 207 if err != nil { 208 return "", "", fmt.Errorf("createFile(root, %q) failed, err: %v", "test", err) 209 } 210 if fd != nil { 211 fd.Close() 212 } 213 defer f.Close() 214 case unix.S_IFDIR: 215 name = "dir" 216 if _, err := root.Mkdir(name, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 217 return "", "", fmt.Errorf("root.MkDir(%q) failed, err: %v", name, err) 218 } 219 case unix.S_IFLNK: 220 name = "symlink" 221 if _, err := root.Symlink("/some/target", name, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 222 return "", "", fmt.Errorf("root.Symlink(%q) failed, err: %v", name, err) 223 } 224 default: 225 panic(fmt.Sprintf("unknown file type %v", fileType)) 226 } 227 return path, name, nil 228 } 229 230 func createFile(dir *localFile, name string) (*localFile, error) { 231 _, f, _, _, err := dir.Create(name, p9.ReadWrite, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 232 if err != nil { 233 return nil, err 234 } 235 return f.(*localFile), nil 236 } 237 238 func TestReadWrite(t *testing.T) { 239 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 240 child, err := createFile(s.file, "test") 241 if err != nil { 242 t.Fatalf("%v: createFile() failed, err: %v", s, err) 243 } 244 defer child.Close() 245 want := []byte("foobar") 246 w, err := child.WriteAt(want, 0) 247 if err != nil { 248 t.Fatalf("%v: Write() failed, err: %v", s, err) 249 } 250 if w != len(want) { 251 t.Fatalf("%v: Write() was partial, got: %d, expected: %d", s, w, len(want)) 252 } 253 for _, flags := range allOpenFlags { 254 _, l, err := s.file.Walk([]string{"test"}) 255 if err != nil { 256 t.Fatalf("%v: Walk(%s) failed, err: %v", s, "test", err) 257 } 258 fd, _, _, err := l.Open(flags) 259 if err != nil { 260 t.Fatalf("%v: Open(%v) failed, err: %v", s, flags, err) 261 } 262 if fd != nil { 263 defer fd.Close() 264 } 265 if err := testReadWrite(l, flags, want); err != nil { 266 t.Fatalf("%v: testReadWrite(%v) failed: %v", s, flags, err) 267 } 268 } 269 }) 270 } 271 272 func TestCreate(t *testing.T) { 273 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 274 for i, flags := range allOpenFlags { 275 _, l, _, _, err := s.file.Create(fmt.Sprintf("test-%d", i), flags, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 276 if err != nil { 277 t.Fatalf("%v, %v: WriteAt() failed, err: %v", s, flags, err) 278 } 279 280 if err := testReadWrite(l, flags, nil); err != nil { 281 t.Fatalf("%v: testReadWrite(%v) failed: %v", s, flags, err) 282 } 283 } 284 }) 285 } 286 287 func checkIDs(f p9.File, uid, gid int) error { 288 _, _, stat, err := f.GetAttr(p9.AttrMask{UID: true, GID: true}) 289 if err != nil { 290 return fmt.Errorf("GetAttr() failed, err: %v", err) 291 } 292 if want := p9.UID(uid); stat.UID != want { 293 return fmt.Errorf("Wrong UID, want: %v, got: %v", want, stat.UID) 294 } 295 if want := p9.GID(gid); stat.GID != want { 296 return fmt.Errorf("Wrong GID, want: %v, got: %v", want, stat.GID) 297 } 298 return nil 299 } 300 301 // TestCreateSetGID checks files/dirs/symlinks are created with the proper 302 // owner when the parent directory has setgid set, 303 func TestCreateSetGID(t *testing.T) { 304 if !specutils.HasCapabilities(capability.CAP_CHOWN) { 305 t.Skipf("Test requires CAP_CHOWN") 306 } 307 308 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 309 // Change group and set setgid to the parent dir. 310 if err := unix.Chown(s.file.hostPath, os.Getuid(), nobody); err != nil { 311 t.Fatalf("Chown() failed: %v", err) 312 } 313 if err := unix.Chmod(s.file.hostPath, 02777); err != nil { 314 t.Fatalf("Chmod() failed: %v", err) 315 } 316 317 t.Run("create", func(t *testing.T) { 318 _, l, _, _, err := s.file.Create("test", p9.ReadOnly, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 319 if err != nil { 320 t.Fatalf("WriteAt() failed: %v", err) 321 } 322 defer l.Close() 323 if err := checkIDs(l, os.Getuid(), os.Getgid()); err != nil { 324 t.Error(err) 325 } 326 }) 327 328 t.Run("mkdir", func(t *testing.T) { 329 _, err := s.file.Mkdir("test-dir", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 330 if err != nil { 331 t.Fatalf("WriteAt() failed: %v", err) 332 } 333 _, l, err := s.file.Walk([]string{"test-dir"}) 334 if err != nil { 335 t.Fatalf("Walk() failed: %v", err) 336 } 337 defer l.Close() 338 if err := checkIDs(l, os.Getuid(), os.Getgid()); err != nil { 339 t.Error(err) 340 } 341 }) 342 343 t.Run("symlink", func(t *testing.T) { 344 if _, err := s.file.Symlink("/some/target", "symlink", p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 345 t.Fatalf("Symlink() failed: %v", err) 346 } 347 _, l, err := s.file.Walk([]string{"symlink"}) 348 if err != nil { 349 t.Fatalf("Walk() failed, err: %v", err) 350 } 351 defer l.Close() 352 if err := checkIDs(l, os.Getuid(), os.Getgid()); err != nil { 353 t.Error(err) 354 } 355 }) 356 357 t.Run("mknod", func(t *testing.T) { 358 if _, err := s.file.Mknod("nod", p9.ModeRegular|0777, 0, 0, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 359 t.Fatalf("Mknod() failed: %v", err) 360 } 361 _, l, err := s.file.Walk([]string{"nod"}) 362 if err != nil { 363 t.Fatalf("Walk() failed, err: %v", err) 364 } 365 defer l.Close() 366 if err := checkIDs(l, os.Getuid(), os.Getgid()); err != nil { 367 t.Error(err) 368 } 369 }) 370 }) 371 } 372 373 // TestReadWriteDup tests that a file opened in any mode can be dup'ed and 374 // reopened in any other mode. 375 func TestReadWriteDup(t *testing.T) { 376 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 377 child, err := createFile(s.file, "test") 378 if err != nil { 379 t.Fatalf("%v: createFile() failed, err: %v", s, err) 380 } 381 defer child.Close() 382 want := []byte("foobar") 383 w, err := child.WriteAt(want, 0) 384 if err != nil { 385 t.Fatalf("%v: Write() failed, err: %v", s, err) 386 } 387 if w != len(want) { 388 t.Fatalf("%v: Write() was partial, got: %d, expected: %d", s, w, len(want)) 389 } 390 for _, flags := range allOpenFlags { 391 _, l, err := s.file.Walk([]string{"test"}) 392 if err != nil { 393 t.Fatalf("%v: Walk(%s) failed, err: %v", s, "test", err) 394 } 395 defer l.Close() 396 if _, _, _, err := l.Open(flags); err != nil { 397 t.Fatalf("%v: Open(%v) failed, err: %v", s, flags, err) 398 } 399 for _, dupFlags := range allOpenFlags { 400 t.Logf("Original flags: %v, dup flags: %v", flags, dupFlags) 401 _, dup, err := l.Walk([]string{}) 402 if err != nil { 403 t.Fatalf("%v: Walk(<empty>) failed: %v", s, err) 404 } 405 defer dup.Close() 406 fd, _, _, err := dup.Open(dupFlags) 407 if err != nil { 408 t.Fatalf("%v: Open(%v) failed: %v", s, flags, err) 409 } 410 if fd != nil { 411 defer fd.Close() 412 } 413 if err := testReadWrite(dup, dupFlags, want); err != nil { 414 t.Fatalf("%v: testReadWrite(%v) failed: %v", s, dupFlags, err) 415 } 416 } 417 } 418 }) 419 } 420 421 func TestUnopened(t *testing.T) { 422 runCustom(t, []uint32{unix.S_IFREG}, allConfs, func(t *testing.T, s state) { 423 b := []byte("foobar") 424 if _, err := s.file.WriteAt(b, 0); err != unix.EBADF { 425 t.Errorf("%v: WriteAt() should have failed, got: %v, expected: unix.EBADF", s, err) 426 } 427 if _, err := s.file.ReadAt(b, 0); err != unix.EBADF { 428 t.Errorf("%v: ReadAt() should have failed, got: %v, expected: unix.EBADF", s, err) 429 } 430 if _, err := s.file.Readdir(0, 100); err != unix.EBADF { 431 t.Errorf("%v: Readdir() should have failed, got: %v, expected: unix.EBADF", s, err) 432 } 433 if err := s.file.FSync(); err != unix.EBADF { 434 t.Errorf("%v: FSync() should have failed, got: %v, expected: unix.EBADF", s, err) 435 } 436 }) 437 } 438 439 // TestOpenOPath is a regression test to ensure that a file that cannot be open 440 // for read is allowed to be open. This was happening because the control file 441 // was open with O_PATH, but Open() was not checking for it and allowing the 442 // control file to be reused. 443 func TestOpenOPath(t *testing.T) { 444 runCustom(t, []uint32{unix.S_IFREG}, rwConfs, func(t *testing.T, s state) { 445 // Fist remove all permissions on the file. 446 if err := s.file.SetAttr(p9.SetAttrMask{Permissions: true}, p9.SetAttr{Permissions: p9.FileMode(0)}); err != nil { 447 t.Fatalf("SetAttr(): %v", err) 448 } 449 // Then walk to the file again to open a new control file. 450 filename := filepath.Base(s.file.hostPath) 451 _, newFile, err := s.root.Walk([]string{filename}) 452 if err != nil { 453 t.Fatalf("root.Walk(%q): %v", filename, err) 454 } 455 456 if newFile.(*localFile).controlReadable { 457 t.Fatalf("control file didn't open with O_PATH: %+v", newFile) 458 } 459 if _, _, _, err := newFile.Open(p9.ReadOnly); err != unix.EACCES { 460 t.Fatalf("Open() should have failed, got: %v, wanted: EACCES", err) 461 } 462 }) 463 } 464 465 func SetGetAttr(l *localFile, valid p9.SetAttrMask, attr p9.SetAttr) (p9.Attr, error) { 466 if err := l.SetAttr(valid, attr); err != nil { 467 return p9.Attr{}, err 468 } 469 _, _, a, err := l.GetAttr(p9.AttrMask{}) 470 if err != nil { 471 return p9.Attr{}, err 472 } 473 return a, nil 474 } 475 476 func TestSetAttrPerm(t *testing.T) { 477 runCustom(t, allTypes, rwConfs, func(t *testing.T, s state) { 478 valid := p9.SetAttrMask{Permissions: true} 479 attr := p9.SetAttr{Permissions: 0777} 480 got, err := SetGetAttr(s.file, valid, attr) 481 if s.fileType == unix.S_IFLNK { 482 if err == nil { 483 t.Fatalf("%v: SetGetAttr(valid, %v) should have failed", s, attr.Permissions) 484 } 485 } else { 486 if err != nil { 487 t.Fatalf("%v: SetGetAttr(valid, %v) failed, err: %v", s, attr.Permissions, err) 488 } 489 if got.Mode.Permissions() != attr.Permissions { 490 t.Errorf("%v: wrong permission, got: %v, expected: %v", s, got.Mode.Permissions(), attr.Permissions) 491 } 492 } 493 }) 494 } 495 496 func TestSetAttrSize(t *testing.T) { 497 runCustom(t, allTypes, rwConfs, func(t *testing.T, s state) { 498 for _, size := range []uint64{1024, 0, 1024 * 1024} { 499 valid := p9.SetAttrMask{Size: true} 500 attr := p9.SetAttr{Size: size} 501 got, err := SetGetAttr(s.file, valid, attr) 502 if s.fileType == unix.S_IFLNK || s.fileType == unix.S_IFDIR { 503 if err == nil { 504 t.Fatalf("%v: SetGetAttr(valid, %v) should have failed", s, attr.Permissions) 505 } 506 // Run for one size only, they will all fail the same way. 507 return 508 } 509 if err != nil { 510 t.Fatalf("%v: SetGetAttr(valid, %v) failed, err: %v", s, attr.Size, err) 511 } 512 if got.Size != size { 513 t.Errorf("%v: wrong size, got: %v, expected: %v", s, got.Size, size) 514 } 515 } 516 }) 517 } 518 519 func TestSetAttrTime(t *testing.T) { 520 runCustom(t, allTypes, rwConfs, func(t *testing.T, s state) { 521 valid := p9.SetAttrMask{ATime: true, ATimeNotSystemTime: true} 522 attr := p9.SetAttr{ATimeSeconds: 123, ATimeNanoSeconds: 456} 523 got, err := SetGetAttr(s.file, valid, attr) 524 if err != nil { 525 t.Fatalf("%v: SetGetAttr(valid, %v:%v) failed, err: %v", s, attr.ATimeSeconds, attr.ATimeNanoSeconds, err) 526 } 527 if got.ATimeSeconds != 123 { 528 t.Errorf("%v: wrong ATimeSeconds, got: %v, expected: %v", s, got.ATimeSeconds, 123) 529 } 530 if got.ATimeNanoSeconds != 456 { 531 t.Errorf("%v: wrong ATimeNanoSeconds, got: %v, expected: %v", s, got.ATimeNanoSeconds, 456) 532 } 533 534 valid = p9.SetAttrMask{MTime: true, MTimeNotSystemTime: true} 535 attr = p9.SetAttr{MTimeSeconds: 789, MTimeNanoSeconds: 012} 536 got, err = SetGetAttr(s.file, valid, attr) 537 if err != nil { 538 t.Fatalf("%v: SetGetAttr(valid, %v:%v) failed, err: %v", s, attr.MTimeSeconds, attr.MTimeNanoSeconds, err) 539 } 540 if got.MTimeSeconds != 789 { 541 t.Errorf("%v: wrong MTimeSeconds, got: %v, expected: %v", s, got.MTimeSeconds, 789) 542 } 543 if got.MTimeNanoSeconds != 012 { 544 t.Errorf("%v: wrong MTimeNanoSeconds, got: %v, expected: %v", s, got.MTimeNanoSeconds, 012) 545 } 546 }) 547 } 548 549 func TestSetAttrOwner(t *testing.T) { 550 if !specutils.HasCapabilities(capability.CAP_CHOWN) { 551 t.Skipf("SetAttr(owner) test requires CAP_CHOWN, running as %d", os.Getuid()) 552 } 553 554 runCustom(t, allTypes, rwConfs, func(t *testing.T, s state) { 555 newUID := os.Getuid() + 1 556 valid := p9.SetAttrMask{UID: true} 557 attr := p9.SetAttr{UID: p9.UID(newUID)} 558 got, err := SetGetAttr(s.file, valid, attr) 559 if err != nil { 560 t.Fatalf("%v: SetGetAttr(valid, %v) failed, err: %v", s, attr.UID, err) 561 } 562 if got.UID != p9.UID(newUID) { 563 t.Errorf("%v: wrong uid, got: %v, expected: %v", s, got.UID, newUID) 564 } 565 }) 566 } 567 568 func SetGetXattr(l *localFile, name string, value string) error { 569 if err := l.SetXattr(name, value, 0 /* flags */); err != nil { 570 return err 571 } 572 ret, err := l.GetXattr(name, uint64(len(value))) 573 if err != nil { 574 return err 575 } 576 if ret != value { 577 return fmt.Errorf("Got value %s, want %s", ret, value) 578 } 579 return nil 580 } 581 582 func TestSetGetDisabledXattr(t *testing.T) { 583 runCustom(t, []uint32{unix.S_IFREG}, rwConfs, func(t *testing.T, s state) { 584 name := "user.merkle.offset" 585 value := "tmp" 586 err := SetGetXattr(s.file, name, value) 587 if err == nil { 588 t.Fatalf("%v: SetGetXattr should have failed", s) 589 } 590 }) 591 } 592 593 func TestSetGetXattr(t *testing.T) { 594 runCustom(t, []uint32{unix.S_IFREG}, []Config{{ROMount: false, EnableVerityXattr: true}}, func(t *testing.T, s state) { 595 name := "user.merkle.offset" 596 value := "tmp" 597 err := SetGetXattr(s.file, name, value) 598 if err != nil { 599 t.Fatalf("%v: SetGetXattr failed, err: %v", s, err) 600 } 601 }) 602 } 603 604 func TestLink(t *testing.T) { 605 if !specutils.HasCapabilities(capability.CAP_DAC_READ_SEARCH) { 606 t.Skipf("Link test requires CAP_DAC_READ_SEARCH, running as %d", os.Getuid()) 607 } 608 runCustom(t, allTypes, rwConfs, func(t *testing.T, s state) { 609 const dirName = "linkdir" 610 const linkFile = "link" 611 if _, err := s.root.Mkdir(dirName, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 612 t.Fatalf("%v: MkDir(%s) failed, err: %v", s, dirName, err) 613 } 614 _, dir, err := s.root.Walk([]string{dirName}) 615 if err != nil { 616 t.Fatalf("%v: Walk({%s}) failed, err: %v", s, dirName, err) 617 } 618 619 err = dir.Link(s.file, linkFile) 620 if s.fileType == unix.S_IFDIR { 621 if err != unix.EPERM { 622 t.Errorf("%v: Link(target, %s) should have failed, got: %v, expected: unix.EPERM", s, linkFile, err) 623 } 624 return 625 } 626 if err != nil { 627 t.Errorf("%v: Link(target, %s) failed, err: %v", s, linkFile, err) 628 } 629 }) 630 } 631 632 func TestROMountChecks(t *testing.T) { 633 const want = unix.EROFS 634 uid := p9.UID(os.Getuid()) 635 gid := p9.GID(os.Getgid()) 636 637 runCustom(t, allTypes, roConfs, func(t *testing.T, s state) { 638 if s.fileType != unix.S_IFLNK { 639 if _, _, _, err := s.file.Open(p9.WriteOnly); err != want { 640 t.Errorf("Open() should have failed, got: %v, expected: %v", err, want) 641 } 642 if _, _, _, err := s.file.Open(p9.ReadWrite); err != want { 643 t.Errorf("Open() should have failed, got: %v, expected: %v", err, want) 644 } 645 if _, _, _, err := s.file.Open(p9.ReadOnly | p9.OpenTruncate); err != want { 646 t.Errorf("Open() should have failed, got: %v, expected: %v", err, want) 647 } 648 f, _, _, err := s.file.Open(p9.ReadOnly) 649 if err != nil { 650 t.Errorf("Open() failed: %v", err) 651 } 652 if f != nil { 653 _ = f.Close() 654 } 655 } 656 657 if _, _, _, _, err := s.file.Create("some_file", p9.ReadWrite, 0777, uid, gid); err != want { 658 t.Errorf("Create() should have failed, got: %v, expected: %v", err, want) 659 } 660 if _, err := s.file.Mkdir("some_dir", 0777, uid, gid); err != want { 661 t.Errorf("MkDir() should have failed, got: %v, expected: %v", err, want) 662 } 663 if err := s.file.RenameAt("some_file", s.file, "other_file"); err != want { 664 t.Errorf("Rename() should have failed, got: %v, expected: %v", err, want) 665 } 666 if _, err := s.file.Symlink("some_place", "some_symlink", uid, gid); err != want { 667 t.Errorf("Symlink() should have failed, got: %v, expected: %v", err, want) 668 } 669 if err := s.file.UnlinkAt("some_file", 0); err != want { 670 t.Errorf("UnlinkAt() should have failed, got: %v, expected: %v", err, want) 671 } 672 if err := s.file.Link(s.file, "some_link"); err != want { 673 t.Errorf("Link() should have failed, got: %v, expected: %v", err, want) 674 } 675 if _, err := s.file.Mknod("some-nod", 0777, 1, 2, uid, gid); err != want { 676 t.Errorf("Mknod() should have failed, got: %v, expected: %v", err, want) 677 } 678 679 valid := p9.SetAttrMask{Size: true} 680 attr := p9.SetAttr{Size: 0} 681 if err := s.file.SetAttr(valid, attr); err != want { 682 t.Errorf("SetAttr() should have failed, got: %v, expected: %v", err, want) 683 } 684 }) 685 } 686 687 func TestWalkNotFound(t *testing.T) { 688 runCustom(t, []uint32{unix.S_IFDIR}, allConfs, func(t *testing.T, s state) { 689 if _, _, err := s.file.Walk([]string{"nobody-here"}); err != unix.ENOENT { 690 t.Errorf("Walk(%q) should have failed, got: %v, expected: unix.ENOENT", "nobody-here", err) 691 } 692 if _, _, err := s.file.Walk([]string{"nobody", "here"}); err != unix.ENOENT { 693 t.Errorf("Walk(%q) should have failed, got: %v, expected: unix.ENOENT", "nobody/here", err) 694 } 695 if !s.conf.ROMount { 696 if _, err := s.file.Mkdir("dir", 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 697 t.Fatalf("MkDir(dir) failed, err: %v", err) 698 } 699 if _, _, err := s.file.Walk([]string{"dir", "nobody-here"}); err != unix.ENOENT { 700 t.Errorf("Walk(%q) should have failed, got: %v, expected: unix.ENOENT", "dir/nobody-here", err) 701 } 702 } 703 }) 704 } 705 706 func TestWalkDup(t *testing.T) { 707 runAll(t, func(t *testing.T, s state) { 708 _, dup, err := s.file.Walk([]string{}) 709 if err != nil { 710 t.Fatalf("%v: Walk(nil) failed, err: %v", s, err) 711 } 712 // Check that 'dup' is usable. 713 if _, _, _, err := dup.GetAttr(p9.AttrMask{}); err != nil { 714 t.Errorf("%v: GetAttr() failed, err: %v", s, err) 715 } 716 }) 717 } 718 719 func TestWalkMultiple(t *testing.T) { 720 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 721 var names []string 722 var parent p9.File = s.file 723 for i := 0; i < 5; i++ { 724 name := fmt.Sprintf("dir%d", i) 725 names = append(names, name) 726 727 if _, err := parent.Mkdir(name, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 728 t.Fatalf("MkDir(%q) failed, err: %v", name, err) 729 } 730 731 var err error 732 _, parent, err = s.file.Walk(names) 733 if err != nil { 734 t.Errorf("Walk(%q): %v", name, err) 735 } 736 } 737 }) 738 } 739 740 func TestReaddir(t *testing.T) { 741 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 742 name := "dir" 743 if _, err := s.file.Mkdir(name, 0777, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 744 t.Fatalf("%v: MkDir(%s) failed, err: %v", s, name, err) 745 } 746 name = "symlink" 747 if _, err := s.file.Symlink("/some/target", name, p9.UID(os.Getuid()), p9.GID(os.Getgid())); err != nil { 748 t.Fatalf("%v: Symlink(%q) failed, err: %v", s, name, err) 749 } 750 name = "file" 751 _, f, _, _, err := s.file.Create(name, p9.ReadWrite, 0555, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 752 if err != nil { 753 t.Fatalf("%v: createFile(root, %q) failed, err: %v", s, name, err) 754 } 755 f.Close() 756 757 if _, _, _, err := s.file.Open(p9.ReadOnly); err != nil { 758 t.Fatalf("%v: Open(ReadOnly) failed, err: %v", s, err) 759 } 760 761 dirents, err := s.file.Readdir(0, 10) 762 if err != nil { 763 t.Fatalf("%v: Readdir(0, 10) failed, err: %v", s, err) 764 } 765 if len(dirents) != 3 { 766 t.Fatalf("%v: Readdir(0, 10) wrong number of items, got: %v, expected: 3", s, len(dirents)) 767 } 768 var dir, symlink, file bool 769 for _, d := range dirents { 770 switch d.Name { 771 case "dir": 772 if d.Type != p9.TypeDir { 773 t.Errorf("%v: dirent.Type got: %v, expected: %v", s, d.Type, p9.TypeDir) 774 } 775 dir = true 776 case "symlink": 777 if d.Type != p9.TypeSymlink { 778 t.Errorf("%v: dirent.Type got: %v, expected: %v", s, d.Type, p9.TypeSymlink) 779 } 780 symlink = true 781 case "file": 782 if d.Type != p9.TypeRegular { 783 t.Errorf("%v: dirent.Type got: %v, expected: %v", s, d.Type, p9.TypeRegular) 784 } 785 file = true 786 default: 787 t.Errorf("%v: dirent.Name got: %v", s, d.Name) 788 } 789 790 _, f, err := s.file.Walk([]string{d.Name}) 791 if err != nil { 792 t.Fatalf("%v: Walk({%s}) failed, err: %v", s, d.Name, err) 793 } 794 _, _, a, err := f.GetAttr(p9.AttrMask{}) 795 if err != nil { 796 t.Fatalf("%v: GetAttr() failed, err: %v", s, err) 797 } 798 if d.Type != a.Mode.QIDType() { 799 t.Errorf("%v: dirent.Type different than GetAttr().Mode.QIDType(), got: %v, expected: %v", s, d.Type, a.Mode.QIDType()) 800 } 801 } 802 if !dir || !symlink || !file { 803 t.Errorf("%v: Readdir(0, 10) wrong files returned, dir: %v, symlink: %v, file: %v", s, dir, symlink, file) 804 } 805 }) 806 } 807 808 // Test that attach point can be written to when it points to a file, e.g. 809 // /etc/hosts. 810 func TestAttachFile(t *testing.T) { 811 conf := Config{ROMount: false} 812 dir, err := ioutil.TempDir("", "root-") 813 if err != nil { 814 t.Fatalf("ioutil.TempDir() failed, err: %v", err) 815 } 816 defer os.RemoveAll(dir) 817 818 path := path.Join(dir, "test") 819 if _, err := os.Create(path); err != nil { 820 t.Fatalf("os.Create(%q) failed, err: %v", path, err) 821 } 822 823 a, err := NewAttachPoint(path, conf) 824 if err != nil { 825 t.Fatalf("NewAttachPoint failed: %v", err) 826 } 827 root, err := a.Attach() 828 if err != nil { 829 t.Fatalf("Attach failed, err: %v", err) 830 } 831 832 if _, _, _, err := root.Open(p9.ReadWrite); err != nil { 833 t.Fatalf("Open(ReadWrite) failed, err: %v", err) 834 } 835 defer root.Close() 836 837 b := []byte("foobar") 838 w, err := root.WriteAt(b, 0) 839 if err != nil { 840 t.Fatalf("Write() failed, err: %v", err) 841 } 842 if w != len(b) { 843 t.Fatalf("Write() was partial, got: %d, expected: %d", w, len(b)) 844 } 845 rBuf := make([]byte, len(b)) 846 r, err := root.ReadAt(rBuf, 0) 847 if err != nil { 848 t.Fatalf("ReadAt() failed, err: %v", err) 849 } 850 if r != len(rBuf) { 851 t.Fatalf("ReadAt() was partial, got: %d, expected: %d", r, len(rBuf)) 852 } 853 if string(rBuf) != "foobar" { 854 t.Fatalf("ReadAt() wrong data, got: %s, expected: %s", string(rBuf), "foobar") 855 } 856 } 857 858 func TestAttachInvalidType(t *testing.T) { 859 dir, err := ioutil.TempDir("", "attach-") 860 if err != nil { 861 t.Fatalf("ioutil.TempDir() failed, err: %v", err) 862 } 863 defer os.RemoveAll(dir) 864 865 fifo := filepath.Join(dir, "fifo") 866 if err := unix.Mkfifo(fifo, 0755); err != nil { 867 t.Fatalf("Mkfifo(%q): %v", fifo, err) 868 } 869 870 dirFile, err := os.Open(dir) 871 if err != nil { 872 t.Fatalf("Open(%s): %v", dir, err) 873 } 874 defer dirFile.Close() 875 876 // Bind a socket via /proc to be sure that a length of a socket path 877 // is less than UNIX_PATH_MAX. 878 socket := filepath.Join(fmt.Sprintf("/proc/self/fd/%d", dirFile.Fd()), "socket") 879 l, err := net.Listen("unix", socket) 880 if err != nil { 881 t.Fatalf("net.Listen(unix, %q): %v", socket, err) 882 } 883 defer l.Close() 884 885 for _, tc := range []struct { 886 name string 887 path string 888 }{ 889 {name: "fifo", path: fifo}, 890 {name: "socket", path: socket}, 891 } { 892 t.Run(tc.name, func(t *testing.T) { 893 conf := Config{ROMount: false} 894 a, err := NewAttachPoint(tc.path, conf) 895 if err != nil { 896 t.Fatalf("NewAttachPoint failed: %v", err) 897 } 898 f, err := a.Attach() 899 if f != nil || err == nil { 900 t.Fatalf("Attach should have failed, got (%v, %v)", f, err) 901 } 902 }) 903 } 904 } 905 906 func TestDoubleAttachError(t *testing.T) { 907 conf := Config{ROMount: false} 908 root, err := ioutil.TempDir("", "root-") 909 if err != nil { 910 t.Fatalf("ioutil.TempDir() failed, err: %v", err) 911 } 912 defer os.RemoveAll(root) 913 a, err := NewAttachPoint(root, conf) 914 if err != nil { 915 t.Fatalf("NewAttachPoint failed: %v", err) 916 } 917 918 if _, err := a.Attach(); err != nil { 919 t.Fatalf("Attach failed: %v", err) 920 } 921 if _, err := a.Attach(); err == nil { 922 t.Fatalf("Attach should have failed, got %v want non-nil", err) 923 } 924 } 925 926 func TestTruncate(t *testing.T) { 927 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 928 child, err := createFile(s.file, "test") 929 if err != nil { 930 t.Fatalf("createFile() failed: %v", err) 931 } 932 defer child.Close() 933 want := []byte("foobar") 934 w, err := child.WriteAt(want, 0) 935 if err != nil { 936 t.Fatalf("Write() failed: %v", err) 937 } 938 if w != len(want) { 939 t.Fatalf("Write() was partial, got: %d, expected: %d", w, len(want)) 940 } 941 942 _, l, err := s.file.Walk([]string{"test"}) 943 if err != nil { 944 t.Fatalf("Walk(%s) failed: %v", "test", err) 945 } 946 if _, _, _, err := l.Open(p9.ReadOnly | p9.OpenTruncate); err != nil { 947 t.Fatalf("Open() failed: %v", err) 948 } 949 _, mask, attr, err := l.GetAttr(p9.AttrMask{Size: true}) 950 if err != nil { 951 t.Fatalf("GetAttr() failed: %v", err) 952 } 953 if !mask.Size { 954 t.Fatalf("GetAttr() didn't return size: %+v", mask) 955 } 956 if attr.Size != 0 { 957 t.Fatalf("truncate didn't work, want: 0, got: %d", attr.Size) 958 } 959 }) 960 } 961 962 func TestMknod(t *testing.T) { 963 runCustom(t, []uint32{unix.S_IFDIR}, rwConfs, func(t *testing.T, s state) { 964 _, err := s.file.Mknod("test", p9.ModeRegular|0777, 1, 2, p9.UID(os.Getuid()), p9.GID(os.Getgid())) 965 if err != nil { 966 t.Fatalf("Mknod() failed: %v", err) 967 } 968 969 _, f, err := s.file.Walk([]string{"test"}) 970 if err != nil { 971 t.Fatalf("Walk() failed: %v", err) 972 } 973 fd, _, _, err := f.Open(p9.ReadWrite) 974 if err != nil { 975 t.Fatalf("Open() failed: %v", err) 976 } 977 if fd != nil { 978 defer fd.Close() 979 } 980 if err := testReadWrite(f, p9.ReadWrite, nil); err != nil { 981 t.Fatalf("testReadWrite() failed: %v", err) 982 } 983 }) 984 } 985 986 func BenchmarkWalkOne(b *testing.B) { 987 path, name, err := setup(unix.S_IFDIR) 988 if err != nil { 989 b.Fatalf("%v", err) 990 } 991 defer os.RemoveAll(path) 992 993 a, err := NewAttachPoint(path, Config{}) 994 if err != nil { 995 b.Fatalf("NewAttachPoint failed: %v", err) 996 } 997 root, err := a.Attach() 998 if err != nil { 999 b.Fatalf("Attach failed, err: %v", err) 1000 } 1001 defer root.Close() 1002 1003 names := []string{name} 1004 files := make([]p9.File, 0, 1000) 1005 1006 b.ResetTimer() 1007 for i := 0; i < b.N; i++ { 1008 _, file, err := root.Walk(names) 1009 if err != nil { 1010 b.Fatalf("Walk(%q): %v", name, err) 1011 } 1012 files = append(files, file) 1013 1014 // Avoid running out of FDs. 1015 if len(files) == cap(files) { 1016 b.StopTimer() 1017 for _, file := range files { 1018 file.Close() 1019 } 1020 files = files[:0] 1021 b.StartTimer() 1022 } 1023 } 1024 1025 b.StopTimer() 1026 for _, file := range files { 1027 file.Close() 1028 } 1029 } 1030 1031 func BenchmarkCreate(b *testing.B) { 1032 path, _, err := setup(unix.S_IFDIR) 1033 if err != nil { 1034 b.Fatalf("%v", err) 1035 } 1036 defer os.RemoveAll(path) 1037 1038 a, err := NewAttachPoint(path, Config{}) 1039 if err != nil { 1040 b.Fatalf("NewAttachPoint failed: %v", err) 1041 } 1042 root, err := a.Attach() 1043 if err != nil { 1044 b.Fatalf("Attach failed, err: %v", err) 1045 } 1046 defer root.Close() 1047 1048 files := make([]p9.File, 0, 500) 1049 fds := make([]*fd.FD, 0, 500) 1050 uid := p9.UID(os.Getuid()) 1051 gid := p9.GID(os.Getgid()) 1052 1053 b.ResetTimer() 1054 for i := 0; i < b.N; i++ { 1055 name := fmt.Sprintf("same-%d", i) 1056 fd, file, _, _, err := root.Create(name, p9.ReadOnly, 0777, uid, gid) 1057 if err != nil { 1058 b.Fatalf("Create(%q): %v", name, err) 1059 } 1060 files = append(files, file) 1061 if fd != nil { 1062 fds = append(fds, fd) 1063 } 1064 1065 // Avoid running out of FDs. 1066 if len(files) == cap(files) { 1067 b.StopTimer() 1068 for _, file := range files { 1069 file.Close() 1070 } 1071 files = files[:0] 1072 for _, fd := range fds { 1073 fd.Close() 1074 } 1075 fds = fds[:0] 1076 b.StartTimer() 1077 } 1078 } 1079 1080 b.StopTimer() 1081 for _, file := range files { 1082 file.Close() 1083 } 1084 for _, fd := range fds { 1085 fd.Close() 1086 } 1087 } 1088 1089 func BenchmarkCreateDiffOwner(b *testing.B) { 1090 if !specutils.HasCapabilities(capability.CAP_CHOWN) { 1091 b.Skipf("Test requires CAP_CHOWN") 1092 } 1093 1094 path, _, err := setup(unix.S_IFDIR) 1095 if err != nil { 1096 b.Fatalf("%v", err) 1097 } 1098 defer os.RemoveAll(path) 1099 1100 a, err := NewAttachPoint(path, Config{}) 1101 if err != nil { 1102 b.Fatalf("NewAttachPoint failed: %v", err) 1103 } 1104 root, err := a.Attach() 1105 if err != nil { 1106 b.Fatalf("Attach failed, err: %v", err) 1107 } 1108 defer root.Close() 1109 1110 files := make([]p9.File, 0, 500) 1111 fds := make([]*fd.FD, 0, 500) 1112 gid := p9.GID(os.Getgid()) 1113 1114 b.ResetTimer() 1115 for i := 0; i < b.N; i++ { 1116 name := fmt.Sprintf("diff-%d", i) 1117 fd, file, _, _, err := root.Create(name, p9.ReadOnly, 0777, nobody, gid) 1118 if err != nil { 1119 b.Fatalf("Create(%q): %v", name, err) 1120 } 1121 files = append(files, file) 1122 if fd != nil { 1123 fds = append(fds, fd) 1124 } 1125 1126 // Avoid running out of FDs. 1127 if len(files) == cap(files) { 1128 b.StopTimer() 1129 for _, file := range files { 1130 file.Close() 1131 } 1132 files = files[:0] 1133 for _, fd := range fds { 1134 fd.Close() 1135 } 1136 fds = fds[:0] 1137 b.StartTimer() 1138 } 1139 } 1140 1141 b.StopTimer() 1142 for _, file := range files { 1143 file.Close() 1144 } 1145 for _, fd := range fds { 1146 fd.Close() 1147 } 1148 }