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