gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/fsimpl/dev/dev_test.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dev 16 17 import ( 18 "testing" 19 20 "gvisor.dev/gvisor/pkg/abi/linux" 21 "gvisor.dev/gvisor/pkg/context" 22 "gvisor.dev/gvisor/pkg/fspath" 23 "gvisor.dev/gvisor/pkg/sentry/contexttest" 24 "gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs" 25 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 26 "gvisor.dev/gvisor/pkg/sentry/vfs" 27 ) 28 29 const ( 30 testDevMajor = 111 31 testDevMinor = 11 32 testDevPathname = "test" 33 testDevPerms = 0655 34 ) 35 36 func setupDev(t *testing.T) (context.Context, *auth.Credentials, *vfs.VirtualFilesystem, vfs.VirtualDentry, func()) { 37 t.Helper() 38 39 ctx := contexttest.Context(t) 40 creds := auth.CredentialsFromContext(ctx) 41 vfsObj := &vfs.VirtualFilesystem{} 42 if err := vfsObj.Init(ctx); err != nil { 43 t.Fatalf("VFS init: %v", err) 44 } 45 // Register tmpfs. 46 vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ 47 AllowUserMount: true, 48 }) 49 vfsObj.MustRegisterFilesystemType(Name, &FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{}) 50 51 vfsObj.RegisterDevice(vfs.CharDevice, testDevMajor, testDevMinor, nil, &vfs.RegisterDeviceOptions{ 52 GroupName: "test", 53 Pathname: testDevPathname, 54 FilePerms: testDevPerms, 55 }) 56 57 // Create a test mount namespace with devfs mounted at root. 58 mntns, err := vfsObj.NewMountNamespace(ctx, creds, "dev" /* source */, Name /* fsTypeName */, &vfs.MountOptions{}, nil) 59 if err != nil { 60 t.Fatalf("failed to create tmpfs root mount: %v", err) 61 } 62 root := mntns.Root(ctx) 63 64 return ctx, creds, vfsObj, root, func() { 65 root.DecRef(ctx) 66 mntns.DecRef(ctx) 67 } 68 } 69 70 func TestUserspaceFiles(t *testing.T) { 71 ctx, creds, vfsObj, root, cleanup := setupDev(t) 72 defer cleanup() 73 74 // Created files should be visible in the test mount namespace. 75 links := []struct { 76 source string 77 target string 78 }{ 79 { 80 source: "fd", 81 target: "/proc/self/fd", 82 }, 83 { 84 source: "stdin", 85 target: "/proc/self/fd/0", 86 }, 87 { 88 source: "stdout", 89 target: "/proc/self/fd/1", 90 }, 91 { 92 source: "stderr", 93 target: "/proc/self/fd/2", 94 }, 95 { 96 source: "ptmx", 97 target: "pts/ptmx", 98 }, 99 } 100 101 for _, link := range links { 102 if gotTarget, err := vfsObj.ReadlinkAt(ctx, creds, &vfs.PathOperation{ 103 Root: root, 104 Start: root, 105 Path: fspath.Parse(link.source), 106 }); err != nil || gotTarget != link.target { 107 t.Errorf("readlink(%q): got (%q, %v), wanted (%q, nil)", link.source, gotTarget, err, link.target) 108 } 109 } 110 111 dirs := []string{"shm", "pts"} 112 for _, dir := range dirs { 113 statx, err := vfsObj.StatAt(ctx, creds, &vfs.PathOperation{ 114 Root: root, 115 Start: root, 116 Path: fspath.Parse(dir), 117 }, &vfs.StatOptions{ 118 Mask: linux.STATX_MODE, 119 }) 120 if err != nil { 121 t.Errorf("stat(%q): got error %v ", dir, err) 122 continue 123 } 124 if want := uint16(0755) | linux.S_IFDIR; statx.Mode != want { 125 t.Errorf("stat(%q): got mode %x, want %x", dir, statx.Mode, want) 126 } 127 } 128 } 129 130 func TestDeviceFile(t *testing.T) { 131 ctx, creds, vfsObj, root, cleanup := setupDev(t) 132 defer cleanup() 133 134 // Test that the test device is created. 135 stat, err := vfsObj.StatAt(ctx, creds, &vfs.PathOperation{ 136 Root: root, 137 Start: root, 138 Path: fspath.Parse(testDevPathname), 139 }, &vfs.StatOptions{ 140 Mask: linux.STATX_TYPE | linux.STATX_MODE, 141 }) 142 if err != nil { 143 t.Fatalf("failed to stat device file at %q: %v", testDevPathname, err) 144 } 145 if stat.RdevMajor != testDevMajor { 146 t.Errorf("major device number: got %v, wanted %v", stat.RdevMajor, testDevMajor) 147 } 148 if stat.RdevMinor != testDevMinor { 149 t.Errorf("minor device number: got %v, wanted %v", stat.RdevMinor, testDevMinor) 150 } 151 if wantMode := uint16(linux.S_IFCHR | testDevPerms); stat.Mode != wantMode { 152 t.Errorf("device file mode: got %v, wanted %v", stat.Mode, wantMode) 153 } 154 }