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  }