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  }