gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/fsimpl/testutil/kernel.go (about) 1 // Copyright 2019 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 testutil 16 17 import ( 18 "flag" 19 "fmt" 20 "os" 21 "runtime" 22 23 "gvisor.dev/gvisor/pkg/abi/linux" 24 "gvisor.dev/gvisor/pkg/context" 25 "gvisor.dev/gvisor/pkg/cpuid" 26 "gvisor.dev/gvisor/pkg/fspath" 27 "gvisor.dev/gvisor/pkg/memutil" 28 "gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs" 29 "gvisor.dev/gvisor/pkg/sentry/kernel" 30 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 31 "gvisor.dev/gvisor/pkg/sentry/kernel/sched" 32 "gvisor.dev/gvisor/pkg/sentry/limits" 33 "gvisor.dev/gvisor/pkg/sentry/loader" 34 "gvisor.dev/gvisor/pkg/sentry/mm" 35 "gvisor.dev/gvisor/pkg/sentry/pgalloc" 36 "gvisor.dev/gvisor/pkg/sentry/platform" 37 "gvisor.dev/gvisor/pkg/sentry/seccheck" 38 "gvisor.dev/gvisor/pkg/sentry/time" 39 "gvisor.dev/gvisor/pkg/sentry/vfs" 40 41 // Platforms are pluggable. 42 _ "gvisor.dev/gvisor/pkg/sentry/platform/kvm" 43 _ "gvisor.dev/gvisor/pkg/sentry/platform/ptrace" 44 ) 45 46 var ( 47 platformFlag = flag.String("platform", "ptrace", "specify which platform to use") 48 platformDevicePathFlag = flag.String("platform_device_path", "", "path to a platform-specific device file (e.g. /dev/kvm for KVM platform). If unset, will use a sane platform-specific default.") 49 ) 50 51 // Boot initializes a new bare bones kernel for test. 52 func Boot() (*kernel.Kernel, error) { 53 cpuid.Initialize() 54 seccheck.Initialize() 55 56 platformCtr, err := platform.Lookup(*platformFlag) 57 if err != nil { 58 return nil, fmt.Errorf("platform not found: %v", err) 59 } 60 deviceFile, err := platformCtr.OpenDevice(*platformDevicePathFlag) 61 if err != nil { 62 return nil, fmt.Errorf("creating platform: %v", err) 63 } 64 plat, err := platformCtr.New(deviceFile) 65 if err != nil { 66 return nil, fmt.Errorf("creating platform: %v", err) 67 } 68 69 k := &kernel.Kernel{ 70 Platform: plat, 71 } 72 73 mf, err := createMemoryFile() 74 if err != nil { 75 return nil, err 76 } 77 k.SetMemoryFile(mf) 78 79 // Pass k as the platform since it is savable, unlike the actual platform. 80 vdso, err := loader.PrepareVDSO(k.MemoryFile()) 81 if err != nil { 82 return nil, fmt.Errorf("creating vdso: %v", err) 83 } 84 85 // Create timekeeper. 86 tk := kernel.NewTimekeeper(k.MemoryFile(), vdso.ParamPage.FileRange()) 87 tk.SetClocks(time.NewCalibratedClocks()) 88 89 creds := auth.NewRootCredentials(auth.NewRootUserNamespace()) 90 91 // Initiate the Kernel object, which is required by the Context passed 92 // to createVFS in order to mount (among other things) procfs. 93 if err = k.Init(kernel.InitKernelArgs{ 94 ApplicationCores: uint(runtime.GOMAXPROCS(-1)), 95 FeatureSet: cpuid.HostFeatureSet(), 96 Timekeeper: tk, 97 RootUserNamespace: creds.UserNamespace, 98 Vdso: vdso, 99 RootUTSNamespace: kernel.NewUTSNamespace("hostname", "domain", creds.UserNamespace), 100 RootIPCNamespace: kernel.NewIPCNamespace(creds.UserNamespace), 101 PIDNamespace: kernel.NewRootPIDNamespace(creds.UserNamespace), 102 }); err != nil { 103 return nil, fmt.Errorf("initializing kernel: %v", err) 104 } 105 106 k.VFS().MustRegisterFilesystemType(tmpfs.Name, &tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ 107 AllowUserMount: true, 108 AllowUserList: true, 109 }) 110 111 ls, err := limits.NewLinuxLimitSet() 112 if err != nil { 113 return nil, err 114 } 115 tg := k.NewThreadGroup(k.RootPIDNamespace(), kernel.NewSignalHandlers(), linux.SIGCHLD, ls) 116 k.TestOnlySetGlobalInit(tg) 117 118 return k, nil 119 } 120 121 // CreateTask creates a new bare bones task for tests. 122 func CreateTask(ctx context.Context, name string, tc *kernel.ThreadGroup, mntns *vfs.MountNamespace, root, cwd vfs.VirtualDentry) (*kernel.Task, error) { 123 k := kernel.KernelFromContext(ctx) 124 if k == nil { 125 return nil, fmt.Errorf("cannot find kernel from context") 126 } 127 128 exe, err := newFakeExecutable(ctx, k.VFS(), auth.CredentialsFromContext(ctx), root) 129 if err != nil { 130 return nil, err 131 } 132 m := mm.NewMemoryManager(k, k.MemoryFile(), k.SleepForAddressSpaceActivation) 133 m.SetExecutable(ctx, exe) 134 135 creds := auth.CredentialsFromContext(ctx) 136 config := &kernel.TaskConfig{ 137 Kernel: k, 138 ThreadGroup: tc, 139 TaskImage: &kernel.TaskImage{Name: name, MemoryManager: m}, 140 Credentials: auth.CredentialsFromContext(ctx), 141 NetworkNamespace: k.RootNetworkNamespace(), 142 AllowedCPUMask: sched.NewFullCPUSet(k.ApplicationCores()), 143 UTSNamespace: kernel.UTSNamespaceFromContext(ctx), 144 IPCNamespace: kernel.IPCNamespaceFromContext(ctx), 145 MountNamespace: mntns, 146 FSContext: kernel.NewFSContext(root, cwd, 0022), 147 FDTable: k.NewFDTable(), 148 UserCounters: k.GetUserCounters(creds.RealKUID), 149 } 150 config.NetworkNamespace.IncRef() 151 t, err := k.TaskSet().NewTask(ctx, config) 152 if err != nil { 153 config.ThreadGroup.Release(ctx) 154 return nil, err 155 } 156 return t, nil 157 } 158 159 func newFakeExecutable(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, root vfs.VirtualDentry) (*vfs.FileDescription, error) { 160 const name = "executable" 161 pop := &vfs.PathOperation{ 162 Root: root, 163 Start: root, 164 Path: fspath.Parse(name), 165 } 166 opts := &vfs.OpenOptions{ 167 Flags: linux.O_RDONLY | linux.O_CREAT, 168 Mode: 0777, 169 } 170 return vfsObj.OpenAt(ctx, creds, pop, opts) 171 } 172 173 func createMemoryFile() (*pgalloc.MemoryFile, error) { 174 const memfileName = "test-memory" 175 memfd, err := memutil.CreateMemFD(memfileName, 0) 176 if err != nil { 177 return nil, fmt.Errorf("error creating memfd: %v", err) 178 } 179 memfile := os.NewFile(uintptr(memfd), memfileName) 180 mf, err := pgalloc.NewMemoryFile(memfile, pgalloc.MemoryFileOpts{}) 181 if err != nil { 182 _ = memfile.Close() 183 return nil, fmt.Errorf("error creating pgalloc.MemoryFile: %v", err) 184 } 185 return mf, nil 186 }