Start cleaning up VFS1.

PiperOrigin-RevId: 486586072
This commit is contained in:
Ayush Ranjan
2022-11-07 00:39:54 -08:00
committed by gVisor bot
parent 7520b7f833
commit 020df37be7
25 changed files with 286 additions and 754 deletions
-2
View File
@@ -34,8 +34,6 @@ go_library(
"//pkg/fspath",
"//pkg/log",
"//pkg/sentry/fdimport",
"//pkg/sentry/fs",
"//pkg/sentry/fs/host",
"//pkg/sentry/fs/user",
"//pkg/sentry/fsimpl/host",
"//pkg/sentry/fsmetric",
+4 -4
View File
@@ -246,7 +246,7 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
for i, appFD := range args.DonatedFDs {
fdMap[appFD] = hostFDs[i]
}
if _, _, err := fdimport.Import(ctx, fdTable, false, args.KUID, args.KGID, fdMap); err != nil {
if _, err := fdimport.Import(ctx, fdTable, false, args.KUID, args.KGID, fdMap); err != nil {
return fmt.Errorf("error importing host files: %w", err)
}
initArgs.FDTable = fdTable
@@ -258,9 +258,9 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
l.mu.RUnlock()
return fmt.Errorf("mount namespace is nil for %s", initArgs.ContainerID)
}
initArgs.MountNamespaceVFS2 = mntns
initArgs.MountNamespace = mntns
l.mu.RUnlock()
initArgs.MountNamespaceVFS2.IncRef()
initArgs.MountNamespace.IncRef()
if args.ResolveBinaryPath {
resolved, err := user.ResolveExecutablePath(ctx, &initArgs)
@@ -271,7 +271,7 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
}
if args.ResolveHome {
envVars, err := user.MaybeAddExecUserHomeVFS2(ctx, initArgs.MountNamespaceVFS2, creds.RealKUID, initArgs.Envv)
envVars, err := user.MaybeAddExecUserHome(ctx, initArgs.MountNamespace, creds.RealKUID, initArgs.Envv)
if err != nil {
return fmt.Errorf("failed to get user home dir: %w", err)
}
+20 -48
View File
@@ -26,10 +26,8 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/fd"
"gvisor.dev/gvisor/pkg/sentry/fdimport"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/host"
"gvisor.dev/gvisor/pkg/sentry/fs/user"
hostvfs2 "gvisor.dev/gvisor/pkg/sentry/fsimpl/host"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/host"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
@@ -63,13 +61,7 @@ type ExecArgs struct {
// A reference on MountNamespace must be held for the lifetime of the
// ExecArgs. If MountNamespace is nil, it will default to the init
// process's MountNamespace.
MountNamespace *fs.MountNamespace
// MountNamespaceVFS2 is the mount namespace to execute the new process in.
// A reference on MountNamespace must be held for the lifetime of the
// ExecArgs. If MountNamespace is nil, it will default to the init
// process's MountNamespace.
MountNamespaceVFS2 *vfs.MountNamespace
MountNamespace *vfs.MountNamespace
// WorkingDirectory defines the working directory for the new process.
WorkingDirectory string `json:"wd"`
@@ -119,7 +111,7 @@ func (args ExecArgs) String() string {
// Exec runs a new task.
func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error {
newTG, _, _, _, err := proc.execAsync(args)
newTG, _, _, err := proc.execAsync(args)
if err != nil {
return err
}
@@ -132,14 +124,14 @@ func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error {
// ExecAsync runs a new task, but doesn't wait for it to finish. It is defined
// as a function rather than a method to avoid exposing execAsync as an RPC.
func ExecAsync(proc *Proc, args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, *host.TTYFileOperations, *hostvfs2.TTYFileDescription, error) {
func ExecAsync(proc *Proc, args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, *host.TTYFileDescription, error) {
return proc.execAsync(args)
}
// execAsync runs a new task, but doesn't wait for it to finish. It returns the
// newly created thread group and its PID. If the stdio FDs are TTYs, then a
// TTYFileOperations that wraps the TTY is also returned.
func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, *host.TTYFileOperations, *hostvfs2.TTYFileDescription, error) {
func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, *host.TTYFileDescription, error) {
// Import file descriptors.
fdTable := proc.Kernel.NewFDTable()
@@ -164,7 +156,6 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
Envv: args.Envv,
WorkingDirectory: args.WorkingDirectory,
MountNamespace: args.MountNamespace,
MountNamespaceVFS2: args.MountNamespaceVFS2,
Credentials: creds,
FDTable: fdTable,
Umask: 0022,
@@ -177,46 +168,30 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
PIDNamespace: pidns,
}
if initArgs.MountNamespace != nil {
// initArgs must hold a reference on MountNamespace, which will
// be donated to the new process in CreateProcess.
initArgs.MountNamespace.IncRef()
}
if initArgs.MountNamespaceVFS2 != nil {
// initArgs must hold a reference on MountNamespaceVFS2, which will
// be donated to the new process in CreateProcess.
initArgs.MountNamespaceVFS2.IncRef()
initArgs.MountNamespace.IncRef()
}
ctx := initArgs.NewContext(proc.Kernel)
defer fdTable.DecRef(ctx)
if kernel.VFS2Enabled {
// Get the full path to the filename from the PATH env variable.
if initArgs.MountNamespaceVFS2 == nil {
// Set initArgs so that 'ctx' returns the namespace.
//
// Add a reference to the namespace, which is transferred to the new process.
initArgs.MountNamespaceVFS2 = proc.Kernel.GlobalInit().Leader().MountNamespaceVFS2()
initArgs.MountNamespaceVFS2.IncRef()
}
} else {
if initArgs.MountNamespace == nil {
// Set initArgs so that 'ctx' returns the namespace.
initArgs.MountNamespace = proc.Kernel.GlobalInit().Leader().MountNamespace()
// initArgs must hold a reference on MountNamespace, which will
// be donated to the new process in CreateProcess.
initArgs.MountNamespace.IncRef()
}
// Get the full path to the filename from the PATH env variable.
if initArgs.MountNamespace == nil {
// Set initArgs so that 'ctx' returns the namespace.
//
// Add a reference to the namespace, which is transferred to the new process.
initArgs.MountNamespace = proc.Kernel.GlobalInit().Leader().MountNamespaceVFS2()
initArgs.MountNamespace.IncRef()
}
resolved, err := user.ResolveExecutablePath(ctx, &initArgs)
if err != nil {
return nil, 0, nil, nil, err
return nil, 0, nil, err
}
initArgs.Filename = resolved
fds, err := fd.NewFromFiles(args.Files)
if err != nil {
return nil, 0, nil, nil, fmt.Errorf("duplicating payload files: %w", err)
return nil, 0, nil, fmt.Errorf("duplicating payload files: %w", err)
}
defer func() {
for _, fd := range fds {
@@ -227,28 +202,25 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
for appFD, hostFD := range fds {
fdMap[appFD] = hostFD
}
ttyFile, ttyFileVFS2, err := fdimport.Import(ctx, fdTable, args.StdioIsPty, args.KUID, args.KGID, fdMap)
ttyFile, err := fdimport.Import(ctx, fdTable, args.StdioIsPty, args.KUID, args.KGID, fdMap)
if err != nil {
return nil, 0, nil, nil, err
return nil, 0, nil, err
}
tg, tid, err := proc.Kernel.CreateProcess(initArgs)
if err != nil {
return nil, 0, nil, nil, err
return nil, 0, nil, err
}
// Set the foreground process group on the TTY before starting the process.
switch {
case ttyFile != nil:
if ttyFile != nil {
ttyFile.InitForegroundProcessGroup(tg.ProcessGroup())
case ttyFileVFS2 != nil:
ttyFileVFS2.InitForegroundProcessGroup(tg.ProcessGroup())
}
// Start the newly created process.
proc.Kernel.StartProcess(tg)
return tg, tid, ttyFile, ttyFileVFS2, nil
return tg, tid, ttyFile, nil
}
// PsArgs is the set of arguments to ps.
-2
View File
@@ -11,8 +11,6 @@ go_library(
deps = [
"//pkg/context",
"//pkg/fd",
"//pkg/sentry/fs",
"//pkg/sentry/fs/host",
"//pkg/sentry/fsimpl/host",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
+5 -65
View File
@@ -20,9 +20,7 @@ import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/fd"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/host"
hostvfs2 "gvisor.dev/gvisor/pkg/sentry/fsimpl/host"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/host"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
@@ -32,65 +30,7 @@ import (
// sets up TTY for sentry stdin, stdout, and stderr FDs. Used FDs are either
// closed or released. It's safe for the caller to close any remaining files
// upon return.
func Import(ctx context.Context, fdTable *kernel.FDTable, console bool, uid auth.KUID, gid auth.KGID, fds map[int]*fd.FD) (*host.TTYFileOperations, *hostvfs2.TTYFileDescription, error) {
if kernel.VFS2Enabled {
ttyFile, err := importVFS2(ctx, fdTable, console, uid, gid, fds)
return nil, ttyFile, err
}
ttyFile, err := importFS(ctx, fdTable, console, fds)
return ttyFile, nil, err
}
func importFS(ctx context.Context, fdTable *kernel.FDTable, console bool, fds map[int]*fd.FD) (*host.TTYFileOperations, error) {
var ttyFile *fs.File
for appFD, hostFD := range fds {
var appFile *fs.File
if console && appFD < 3 {
// Import the file as a host TTY file.
if ttyFile == nil {
var err error
appFile, err = host.ImportFile(ctx, hostFD.FD(), true /* isTTY */)
if err != nil {
return nil, err
}
defer appFile.DecRef(ctx)
_ = hostFD.Close() // FD is dup'd i ImportFile.
// Remember this in the TTY file, as we will
// use it for the other stdio FDs.
ttyFile = appFile
} else {
// Re-use the existing TTY file, as all three
// stdio FDs must point to the same fs.File in
// order to share TTY state, specifically the
// foreground process group id.
appFile = ttyFile
}
} else {
// Import the file as a regular host file.
var err error
appFile, err = host.ImportFile(ctx, hostFD.FD(), false /* isTTY */)
if err != nil {
return nil, err
}
defer appFile.DecRef(ctx)
_ = hostFD.Close() // FD is dup'd i ImportFile.
}
// Add the file to the FD map.
if err := fdTable.NewFDAt(ctx, int32(appFD), appFile, kernel.FDFlags{}); err != nil {
return nil, err
}
}
if ttyFile == nil {
return nil, nil
}
return ttyFile.FileOperations.(*host.TTYFileOperations), nil
}
func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, uid auth.KUID, gid auth.KGID, stdioFDs map[int]*fd.FD) (*hostvfs2.TTYFileDescription, error) {
func Import(ctx context.Context, fdTable *kernel.FDTable, console bool, uid auth.KUID, gid auth.KGID, stdioFDs map[int]*fd.FD) (*host.TTYFileDescription, error) {
k := kernel.KernelFromContext(ctx)
if k == nil {
return nil, fmt.Errorf("cannot find kernel from context")
@@ -104,7 +44,7 @@ func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, uid
// Import the file as a host TTY file.
if ttyFile == nil {
var err error
appFile, err = hostvfs2.NewFD(ctx, k.HostMount(), hostFD.FD(), &hostvfs2.NewFDOptions{
appFile, err = host.NewFD(ctx, k.HostMount(), hostFD.FD(), &host.NewFDOptions{
Savable: true,
IsTTY: true,
VirtualOwner: true,
@@ -128,7 +68,7 @@ func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, uid
}
} else {
var err error
appFile, err = hostvfs2.NewFD(ctx, k.HostMount(), hostFD.FD(), &hostvfs2.NewFDOptions{
appFile, err = host.NewFD(ctx, k.HostMount(), hostFD.FD(), &host.NewFDOptions{
Savable: true,
VirtualOwner: true,
UID: uid,
@@ -149,5 +89,5 @@ func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, uid
if ttyFile == nil {
return nil, nil
}
return ttyFile.Impl().(*hostvfs2.TTYFileDescription), nil
return ttyFile.Impl().(*host.TTYFileDescription), nil
}
+3 -3
View File
@@ -15,7 +15,6 @@ go_library(
"//pkg/errors/linuxerr",
"//pkg/fspath",
"//pkg/log",
"//pkg/sentry/fs",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/vfs",
@@ -31,10 +30,11 @@ go_test(
deps = [
"//pkg/abi/linux",
"//pkg/context",
"//pkg/sentry/fs",
"//pkg/sentry/fs/tmpfs",
"//pkg/fspath",
"//pkg/sentry/fsimpl/tmpfs",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/contexttest",
"//pkg/sentry/vfs",
"//pkg/usermem",
],
)
+2 -54
View File
@@ -24,7 +24,6 @@ import (
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
@@ -66,65 +65,14 @@ func ResolveExecutablePath(ctx context.Context, args *kernel.CreateProcessArgs)
// Otherwise, We must lookup the name in the paths.
paths := getPath(args.Envv)
if kernel.VFS2Enabled {
f, err := resolveVFS2(ctx, args.Credentials, args.MountNamespaceVFS2, paths, name)
if err != nil {
return "", &ExecutableResolveError{fmt.Errorf("error finding executable %q in PATH %v: %v", name, paths, err)}
}
return f, nil
}
f, err := resolve(ctx, args.MountNamespace, paths, name)
f, err := resolve(ctx, args.Credentials, args.MountNamespace, paths, name)
if err != nil {
return "", &ExecutableResolveError{fmt.Errorf("error finding executable %q in PATH %v: %v", name, paths, err)}
}
return f, nil
}
func resolve(ctx context.Context, mns *fs.MountNamespace, paths []string, name string) (string, error) {
root := fs.RootFromContext(ctx)
if root == nil {
// Caller has no root. Don't bother traversing anything.
return "", linuxerr.ENOENT
}
defer root.DecRef(ctx)
for _, p := range paths {
if !path.IsAbs(p) {
// Relative paths aren't safe, no one should be using them.
log.Warningf("Skipping relative path %q in $PATH", p)
continue
}
binPath := path.Join(p, name)
traversals := uint(linux.MaxSymlinkTraversals)
d, err := mns.FindInode(ctx, root, nil, binPath, &traversals)
if linuxerr.Equals(linuxerr.ENOENT, err) || linuxerr.Equals(linuxerr.EACCES, err) {
// Didn't find it here.
continue
}
if err != nil {
return "", err
}
defer d.DecRef(ctx)
// Check that it is a regular file.
if !fs.IsRegular(d.Inode.StableAttr) {
continue
}
// Check whether we can read and execute the found file.
if err := d.Inode.CheckPermission(ctx, fs.PermMask{Read: true, Execute: true}); err != nil {
log.Infof("Found executable at %q, but user cannot execute it: %v", binPath, err)
continue
}
return path.Join("/", p, name), nil
}
// Couldn't find it.
return "", linuxerr.ENOENT
}
func resolveVFS2(ctx context.Context, creds *auth.Credentials, mns *vfs.MountNamespace, paths []string, name string) (string, error) {
func resolve(ctx context.Context, creds *auth.Credentials, mns *vfs.MountNamespace, paths []string, name string) (string, error) {
root := mns.Root()
root.IncRef()
defer root.DecRef(ctx)
+14 -90
View File
@@ -26,82 +26,22 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
)
type fileReader struct {
// Ctx is the context for the file reader.
Ctx context.Context
// File is the file to read from.
File *fs.File
}
// Read implements io.Reader.Read.
func (r *fileReader) Read(buf []byte) (int, error) {
n, err := r.File.Readv(r.Ctx, usermem.BytesIOSequence(buf))
return int(n), err
}
// getExecUserHome returns the home directory of the executing user read from
// /etc/passwd as read from the container filesystem.
func getExecUserHome(ctx context.Context, rootMns *fs.MountNamespace, uid auth.KUID) (string, error) {
// The default user home directory to return if no user matching the user
// if found in the /etc/passwd found in the image.
const defaultHome = "/"
// Open the /etc/passwd file from the dirent via the root mount namespace.
mnsRoot := rootMns.Root()
maxTraversals := uint(linux.MaxSymlinkTraversals)
dirent, err := rootMns.FindInode(ctx, mnsRoot, nil, "/etc/passwd", &maxTraversals)
if err != nil {
// NOTE: Ignore errors opening the passwd file. If the passwd file
// doesn't exist we will return the default home directory.
return defaultHome, nil
}
defer dirent.DecRef(ctx)
// Check read permissions on the file.
if err := dirent.Inode.CheckPermission(ctx, fs.PermMask{Read: true}); err != nil {
// NOTE: Ignore permissions errors here and return default root dir.
return defaultHome, nil
}
// Only open regular files. We don't open other files like named pipes as
// they may block and might present some attack surface to the container.
// Note that runc does not seem to do this kind of checking.
if !fs.IsRegular(dirent.Inode.StableAttr) {
return defaultHome, nil
}
f, err := dirent.Inode.GetFile(ctx, dirent, fs.FileFlags{Read: true, Directory: false})
if err != nil {
return "", err
}
defer f.DecRef(ctx)
r := &fileReader{
Ctx: ctx,
File: f,
}
return findHomeInPasswd(uint32(uid), r, defaultHome)
}
type fileReaderVFS2 struct {
ctx context.Context
fd *vfs.FileDescription
}
func (r *fileReaderVFS2) Read(buf []byte) (int, error) {
func (r *fileReader) Read(buf []byte) (int, error) {
n, err := r.fd.Read(r.ctx, usermem.BytesIOSequence(buf), vfs.ReadOptions{})
return int(n), err
}
func getExecUserHomeVFS2(ctx context.Context, mns *vfs.MountNamespace, uid auth.KUID) (string, error) {
func getExecUserHome(ctx context.Context, mns *vfs.MountNamespace, uid auth.KUID) (string, error) {
const defaultHome = "/"
root := mns.Root()
@@ -116,17 +56,24 @@ func getExecUserHomeVFS2(ctx context.Context, mns *vfs.MountNamespace, uid auth.
Path: fspath.Parse("/etc/passwd"),
}
stat, err := root.Mount().Filesystem().VirtualFilesystem().StatAt(ctx, creds, target, &vfs.StatOptions{Mask: linux.STATX_TYPE})
if err != nil {
return defaultHome, nil
}
if stat.Mask&linux.STATX_TYPE == 0 || stat.Mode&linux.FileTypeMask != linux.ModeRegular {
return defaultHome, nil
}
opts := &vfs.OpenOptions{
Flags: linux.O_RDONLY,
}
fd, err := root.Mount().Filesystem().VirtualFilesystem().OpenAt(ctx, creds, target, opts)
if err != nil {
return defaultHome, nil
}
defer fd.DecRef(ctx)
r := &fileReaderVFS2{
r := &fileReader{
ctx: ctx,
fd: fd,
}
@@ -139,33 +86,10 @@ func getExecUserHomeVFS2(ctx context.Context, mns *vfs.MountNamespace, uid auth.
return homeDir, nil
}
// MaybeAddExecUserHome returns a new slice with the HOME enviroment variable
// set if the slice does not already contain it, otherwise it returns the
// original slice unmodified.
func MaybeAddExecUserHome(ctx context.Context, mns *fs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
// Check if the envv already contains HOME.
for _, env := range envv {
if strings.HasPrefix(env, "HOME=") {
// We have it. Return the original slice unmodified.
return envv, nil
}
}
// Read /etc/passwd for the user's HOME directory and set the HOME
// environment variable as required by POSIX if it is not overridden by
// the user.
homeDir, err := getExecUserHome(ctx, mns, uid)
if err != nil {
return nil, fmt.Errorf("error reading exec user: %v", err)
}
return append(envv, "HOME="+homeDir), nil
}
// MaybeAddExecUserHomeVFS2 returns a new slice with the HOME enviroment
// MaybeAddExecUserHome returns a new slice with the HOME environment
// variable set if the slice does not already contain it, otherwise it returns
// the original slice unmodified.
func MaybeAddExecUserHomeVFS2(ctx context.Context, vmns *vfs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
func MaybeAddExecUserHome(ctx context.Context, vmns *vfs.MountNamespace, uid auth.KUID, envv []string) ([]string, error) {
// Check if the envv already contains HOME.
for _, env := range envv {
if strings.HasPrefix(env, "HOME=") {
@@ -177,7 +101,7 @@ func MaybeAddExecUserHomeVFS2(ctx context.Context, vmns *vfs.MountNamespace, uid
// Read /etc/passwd for the user's HOME directory and set the HOME
// environment variable as required by POSIX if it is not overridden by
// the user.
homeDir, err := getExecUserHomeVFS2(ctx, vmns, uid)
homeDir, err := getExecUserHome(ctx, vmns, uid)
if err != nil {
return nil, fmt.Errorf("error reading exec user: %v", err)
}
+37 -26
View File
@@ -21,43 +21,50 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/tmpfs"
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/kernel/contexttest"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
)
// createEtcPasswd creates /etc/passwd with the given contents and mode. If
// mode is empty, then no file will be created. If mode is not a regular file
// mode, then contents is ignored.
func createEtcPasswd(ctx context.Context, root *fs.Dirent, contents string, mode linux.FileMode) error {
if err := root.CreateDirectory(ctx, root, "etc", fs.FilePermsFromMode(0755)); err != nil {
return err
func createEtcPasswd(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, root vfs.VirtualDentry, contents string, mode linux.FileMode) error {
pop := vfs.PathOperation{
Root: root,
Start: root,
Path: fspath.Parse("etc"),
}
etc, err := root.Walk(ctx, root, "etc")
if err != nil {
return err
if err := vfsObj.MkdirAt(ctx, creds, &pop, &vfs.MkdirOptions{
Mode: 0755,
}); err != nil {
return fmt.Errorf("failed to create directory etc: %v", err)
}
pop = vfs.PathOperation{
Root: root,
Start: root,
Path: fspath.Parse("etc/passwd"),
}
defer etc.DecRef(ctx)
switch mode.FileType() {
case 0:
// Don't create anything.
return nil
case linux.S_IFREG:
passwd, err := etc.Create(ctx, root, "passwd", fs.FileFlags{Write: true}, fs.FilePermsFromMode(mode))
fd, err := vfsObj.OpenAt(ctx, creds, &pop, &vfs.OpenOptions{Flags: linux.O_CREAT | linux.O_WRONLY, Mode: mode})
if err != nil {
return err
}
defer passwd.DecRef(ctx)
if _, err := passwd.Writev(ctx, usermem.BytesIOSequence([]byte(contents))); err != nil {
return err
}
return nil
defer fd.DecRef(ctx)
_, err = fd.Write(ctx, usermem.BytesIOSequence([]byte(contents)), vfs.WriteOptions{})
return err
case linux.S_IFDIR:
return etc.CreateDirectory(ctx, root, "passwd", fs.FilePermsFromMode(mode))
return vfsObj.MkdirAt(ctx, creds, &pop, &vfs.MkdirOptions{Mode: mode})
case linux.S_IFIFO:
return etc.CreateFifo(ctx, root, "passwd", fs.FilePermsFromMode(mode))
return vfsObj.MknodAt(ctx, creds, &pop, &vfs.MknodOptions{Mode: mode})
default:
return fmt.Errorf("unknown file type %x", mode.FileType())
}
@@ -103,22 +110,26 @@ func TestGetExecUserHome(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
ctx := contexttest.Context(t)
msrc := fs.NewPseudoMountSource(ctx)
rootInode, err := tmpfs.NewDir(ctx, nil, fs.RootOwner, fs.FilePermsFromMode(0777), msrc, nil /* parent */)
if err != nil {
t.Fatalf("tmpfs.NewDir failed: %v", err)
}
creds := auth.CredentialsFromContext(ctx)
mns, err := fs.NewMountNamespace(ctx, rootInode)
// Create VFS.
vfsObj := vfs.VirtualFilesystem{}
if err := vfsObj.Init(ctx); err != nil {
t.Fatalf("VFS init: %v", err)
}
vfsObj.MustRegisterFilesystemType("tmpfs", tmpfs.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
AllowUserMount: true,
})
mns, err := vfsObj.NewMountNamespace(ctx, creds, "", "tmpfs", &vfs.MountOptions{})
if err != nil {
t.Fatalf("NewMountNamespace failed: %v", err)
t.Fatalf("failed to create tmpfs root mount: %v", err)
}
defer mns.DecRef(ctx)
root := mns.Root()
root.IncRef()
defer root.DecRef(ctx)
ctx = fs.WithRoot(ctx, root)
if err := createEtcPasswd(ctx, root, tc.passwdContents, tc.passwdMode); err != nil {
if err := createEtcPasswd(ctx, &vfsObj, creds, root, tc.passwdContents, tc.passwdMode); err != nil {
t.Fatalf("createEtcPasswd failed: %v", err)
}
+2 -3
View File
@@ -63,7 +63,6 @@ func Boot() (*kernel.Kernel, error) {
return nil, fmt.Errorf("creating platform: %v", err)
}
kernel.VFS2Enabled = true
k := &kernel.Kernel{
Platform: plat,
}
@@ -142,8 +141,8 @@ func CreateTask(ctx context.Context, name string, tc *kernel.ThreadGroup, mntns
UTSNamespace: kernel.UTSNamespaceFromContext(ctx),
IPCNamespace: kernel.IPCNamespaceFromContext(ctx),
AbstractSocketNamespace: kernel.NewAbstractSocketNamespace(),
MountNamespaceVFS2: mntns,
FSContext: kernel.NewFSContextVFS2(root, cwd, 0022),
MountNamespace: mntns,
FSContext: kernel.NewFSContext(root, cwd, 0022),
FDTable: k.NewFDTable(),
UserCounters: k.GetUserCounters(creds.RealKUID),
}
+10 -38
View File
@@ -54,21 +54,8 @@ type FSContext struct {
umask uint
}
// newFSContext returns a new filesystem context.
func newFSContext(root, cwd *fs.Dirent, umask uint) *FSContext {
root.IncRef()
cwd.IncRef()
f := FSContext{
root: root,
cwd: cwd,
umask: umask,
}
f.InitRefs()
return &f
}
// NewFSContextVFS2 returns a new filesystem context.
func NewFSContextVFS2(root, cwd vfs.VirtualDentry, umask uint) *FSContext {
// NewFSContext returns a new filesystem context.
func NewFSContext(root, cwd vfs.VirtualDentry, umask uint) *FSContext {
root.IncRef()
cwd.IncRef()
f := FSContext{
@@ -95,17 +82,10 @@ func (f *FSContext) DecRef(ctx context.Context) {
f.mu.Lock()
defer f.mu.Unlock()
if VFS2Enabled {
f.rootVFS2.DecRef(ctx)
f.rootVFS2 = vfs.VirtualDentry{}
f.cwdVFS2.DecRef(ctx)
f.cwdVFS2 = vfs.VirtualDentry{}
} else {
f.root.DecRef(ctx)
f.root = nil
f.cwd.DecRef(ctx)
f.cwd = nil
}
f.rootVFS2.DecRef(ctx)
f.rootVFS2 = vfs.VirtualDentry{}
f.cwdVFS2.DecRef(ctx)
f.cwdVFS2 = vfs.VirtualDentry{}
})
}
@@ -116,19 +96,11 @@ func (f *FSContext) Fork() *FSContext {
f.mu.Lock()
defer f.mu.Unlock()
if VFS2Enabled {
if !f.cwdVFS2.Ok() {
panic("FSContext.Fork() called after destroy")
}
f.cwdVFS2.IncRef()
f.rootVFS2.IncRef()
} else {
if f.cwd == nil {
panic("FSContext.Fork() called after destroy")
}
f.cwd.IncRef()
f.root.IncRef()
if !f.cwdVFS2.Ok() {
panic("FSContext.Fork() called after destroy")
}
f.cwdVFS2.IncRef()
f.rootVFS2.IncRef()
ctx := &FSContext{
cwd: f.cwd,
+99 -223
View File
@@ -49,7 +49,6 @@ import (
"gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
oldtimerfd "gvisor.dev/gvisor/pkg/sentry/fs/timerfd"
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/pipefs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
@@ -79,12 +78,6 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
)
// VFS2Enabled is set to true when VFS2 is enabled. Added as a global to allow
// easy access everywhere.
//
// TODO(gvisor.dev/issue/1624): Remove when VFS1 is no longer used.
var VFS2Enabled = false
// LISAFSEnabled is set to true when lisafs protocol is enabled. Added as a
// global to allow easy access everywhere.
//
@@ -442,44 +435,42 @@ func (k *Kernel) Init(args InitKernelArgs) error {
k.YAMAPtraceScope = atomicbitops.FromInt32(linux.YAMA_SCOPE_RELATIONAL)
k.userCountersMap = make(map[auth.KUID]*userCounters)
if VFS2Enabled {
ctx := k.SupervisorContext()
if err := k.vfs.Init(ctx); err != nil {
return fmt.Errorf("failed to initialize VFS: %v", err)
}
err := k.rootIPCNamespace.InitPosixQueues(ctx, &k.vfs, auth.CredentialsFromContext(ctx))
if err != nil {
return fmt.Errorf("failed to create mqfs filesystem: %v", err)
}
pipeFilesystem, err := pipefs.NewFilesystem(&k.vfs)
if err != nil {
return fmt.Errorf("failed to create pipefs filesystem: %v", err)
}
defer pipeFilesystem.DecRef(ctx)
pipeMount := k.vfs.NewDisconnectedMount(pipeFilesystem, nil, &vfs.MountOptions{})
k.pipeMount = pipeMount
tmpfsFilesystem, tmpfsRoot, err := tmpfs.NewFilesystem(ctx, &k.vfs, auth.NewRootCredentials(k.rootUserNamespace))
if err != nil {
return fmt.Errorf("failed to create tmpfs filesystem: %v", err)
}
defer tmpfsFilesystem.DecRef(ctx)
defer tmpfsRoot.DecRef(ctx)
k.shmMount = k.vfs.NewDisconnectedMount(tmpfsFilesystem, tmpfsRoot, &vfs.MountOptions{})
socketFilesystem, err := sockfs.NewFilesystem(&k.vfs)
if err != nil {
return fmt.Errorf("failed to create sockfs filesystem: %v", err)
}
defer socketFilesystem.DecRef(ctx)
k.socketMount = k.vfs.NewDisconnectedMount(socketFilesystem, nil, &vfs.MountOptions{})
k.socketsVFS2 = make(map[*vfs.FileDescription]*SocketRecord)
k.cgroupRegistry = newCgroupRegistry()
ctx := k.SupervisorContext()
if err := k.vfs.Init(ctx); err != nil {
return fmt.Errorf("failed to initialize VFS: %v", err)
}
err := k.rootIPCNamespace.InitPosixQueues(ctx, &k.vfs, auth.CredentialsFromContext(ctx))
if err != nil {
return fmt.Errorf("failed to create mqfs filesystem: %v", err)
}
pipeFilesystem, err := pipefs.NewFilesystem(&k.vfs)
if err != nil {
return fmt.Errorf("failed to create pipefs filesystem: %v", err)
}
defer pipeFilesystem.DecRef(ctx)
pipeMount := k.vfs.NewDisconnectedMount(pipeFilesystem, nil, &vfs.MountOptions{})
k.pipeMount = pipeMount
tmpfsFilesystem, tmpfsRoot, err := tmpfs.NewFilesystem(ctx, &k.vfs, auth.NewRootCredentials(k.rootUserNamespace))
if err != nil {
return fmt.Errorf("failed to create tmpfs filesystem: %v", err)
}
defer tmpfsFilesystem.DecRef(ctx)
defer tmpfsRoot.DecRef(ctx)
k.shmMount = k.vfs.NewDisconnectedMount(tmpfsFilesystem, tmpfsRoot, &vfs.MountOptions{})
socketFilesystem, err := sockfs.NewFilesystem(&k.vfs)
if err != nil {
return fmt.Errorf("failed to create sockfs filesystem: %v", err)
}
defer socketFilesystem.DecRef(ctx)
k.socketMount = k.vfs.NewDisconnectedMount(socketFilesystem, nil, &vfs.MountOptions{})
k.socketsVFS2 = make(map[*vfs.FileDescription]*SocketRecord)
k.cgroupRegistry = newCgroupRegistry()
return nil
}
@@ -501,50 +492,16 @@ func (k *Kernel) SaveTo(ctx context.Context, w wire.Writer) error {
k.mf.StartEvictions()
k.mf.WaitForEvictions()
if VFS2Enabled {
// Discard unsavable mappings, such as those for host file descriptors.
if err := k.invalidateUnsavableMappings(ctx); err != nil {
return fmt.Errorf("failed to invalidate unsavable mappings: %v", err)
}
// Discard unsavable mappings, such as those for host file descriptors.
if err := k.invalidateUnsavableMappings(ctx); err != nil {
return fmt.Errorf("failed to invalidate unsavable mappings: %v", err)
}
// Prepare filesystems for saving. This must be done after
// invalidateUnsavableMappings(), since dropping memory mappings may
// affect filesystem state (e.g. page cache reference counts).
if err := k.vfs.PrepareSave(ctx); err != nil {
return err
}
} else {
// Flush cached file writes to backing storage. This must come after
// MemoryFile eviction since eviction may cause file writes.
if err := k.flushWritesToFiles(ctx); err != nil {
return err
}
// Clear the dirent cache before saving because Dirents must be Loaded in a
// particular order (parents before children), and Loading dirents from a cache
// breaks that order.
if err := k.flushMountSourceRefs(ctx); err != nil {
return err
}
// Ensure that all inode and mount release operations have completed.
fs.AsyncBarrier()
// Once all fs work has completed (flushed references have all been released),
// reset mount mappings. This allows individual mounts to save how inodes map
// to filesystem resources. Without this, fs.Inodes cannot be restored.
fs.SaveInodeMappings()
// Discard unsavable mappings, such as those for host file descriptors.
// This must be done after waiting for "asynchronous fs work", which
// includes async I/O that may touch application memory.
//
// TODO(gvisor.dev/issue/1624): This rationale is believed to be
// obsolete since AIO callbacks are now waited-for by Kernel.Pause(),
// but this order is conservatively retained for VFS1.
if err := k.invalidateUnsavableMappings(ctx); err != nil {
return fmt.Errorf("failed to invalidate unsavable mappings: %v", err)
}
// Prepare filesystems for saving. This must be done after
// invalidateUnsavableMappings(), since dropping memory mappings may
// affect filesystem state (e.g. page cache reference counts).
if err := k.vfs.PrepareSave(ctx); err != nil {
return err
}
// Save the CPUID FeatureSet before the rest of the kernel so we can
@@ -746,17 +703,8 @@ func (k *Kernel) LoadFrom(ctx context.Context, r wire.Reader, timeReady chan str
net.Resume()
}
if VFS2Enabled {
if err := k.vfs.CompleteRestore(ctx, vfsOpts); err != nil {
return err
}
} else {
// Ensure that all pending asynchronous work is complete:
// - namedpipe opening
// - inode file opening
if err := fs.AsyncErrorBarrier(); err != nil {
return err
}
if err := k.vfs.CompleteRestore(ctx, vfsOpts); err != nil {
return err
}
tcpip.AsyncLoading.Wait()
@@ -843,14 +791,7 @@ type CreateProcessArgs struct {
//
// Anyone setting MountNamespace must donate a reference (i.e.
// increment it).
MountNamespace *fs.MountNamespace
// MountNamespaceVFS2 optionally contains the mount namespace for this
// process. If nil, the init process's mount namespace is used.
//
// Anyone setting MountNamespaceVFS2 must donate a reference (i.e.
// increment it).
MountNamespaceVFS2 *vfs.MountNamespace
MountNamespace *vfs.MountNamespace
// ContainerID is the container that the process belongs to.
ContainerID string
@@ -889,17 +830,11 @@ func (ctx *createProcessContext) Value(key interface{}) interface{} {
return ipcns
case auth.CtxCredentials:
return ctx.args.Credentials
case fs.CtxRoot:
if ctx.args.MountNamespace != nil {
// MountNamespace.Root() will take a reference on the root dirent for us.
return ctx.args.MountNamespace.Root()
}
return nil
case vfs.CtxRoot:
if ctx.args.MountNamespaceVFS2 == nil {
if ctx.args.MountNamespace == nil {
return nil
}
root := ctx.args.MountNamespaceVFS2.Root()
root := ctx.args.MountNamespace.Root()
root.IncRef()
return root
case vfs.CtxMountNamespace:
@@ -953,86 +888,47 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
log.Infof("EXEC: %v", args.Argv)
ctx := args.NewContext(k)
var (
opener fsbridge.Lookup
fsContext *FSContext
mntns *fs.MountNamespace
mntnsVFS2 *vfs.MountNamespace
)
if VFS2Enabled {
mntnsVFS2 = args.MountNamespaceVFS2
if mntnsVFS2 == nil {
if k.globalInit == nil {
return nil, 0, fmt.Errorf("mount namespace is nil")
}
// Add a reference to the namespace, which is transferred to the new process.
mntnsVFS2 = k.globalInit.Leader().MountNamespaceVFS2()
mntnsVFS2.IncRef()
mntns := args.MountNamespace
if mntns == nil {
if k.globalInit == nil {
return nil, 0, fmt.Errorf("mount namespace is nil")
}
// Get the root directory from the MountNamespace.
root := mntnsVFS2.Root()
root.IncRef()
defer root.DecRef(ctx)
// Grab the working directory.
wd := root // Default.
if args.WorkingDirectory != "" {
pop := vfs.PathOperation{
Root: root,
Start: wd,
Path: fspath.Parse(args.WorkingDirectory),
FollowFinalSymlink: true,
}
// NOTE(b/236028361): Do not set CheckSearchable flag to true.
// Application is allowed to start with a working directory that it can
// not access/search. This is consistent with Docker and VFS1. Runc
// explicitly allows for this in 6ce2d63a5db6 ("libct/init_linux: retry
// chdir to fix EPERM"). As described in the commit, runc unintentionally
// allowed this behavior in a couple of releases and applications started
// relying on it. So they decided to allow it for backward compatibility.
var err error
wd, err = k.VFS().GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{})
if err != nil {
return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err)
}
defer wd.DecRef(ctx)
}
opener = fsbridge.NewVFSLookup(mntnsVFS2, root, wd)
fsContext = NewFSContextVFS2(root, wd, args.Umask)
} else {
mntns = args.MountNamespace
if mntns == nil {
if k.globalInit == nil {
return nil, 0, fmt.Errorf("mount namespace is nil")
}
mntns = k.GlobalInit().Leader().MountNamespace()
mntns.IncRef()
}
// Get the root directory from the MountNamespace.
root := mntns.Root()
// The call to newFSContext below will take a reference on root, so we
// don't need to hold this one.
defer root.DecRef(ctx)
// Grab the working directory.
remainingTraversals := args.MaxSymlinkTraversals
wd := root // Default.
if args.WorkingDirectory != "" {
var err error
wd, err = mntns.FindInode(ctx, root, nil, args.WorkingDirectory, &remainingTraversals)
if err != nil {
return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err)
}
defer wd.DecRef(ctx)
}
opener = fsbridge.NewFSLookup(mntns, root, wd)
fsContext = newFSContext(root, wd, args.Umask)
// Add a reference to the namespace, which is transferred to the new process.
mntns = k.globalInit.Leader().MountNamespaceVFS2()
mntns.IncRef()
}
// Get the root directory from the MountNamespace.
root := mntns.Root()
root.IncRef()
defer root.DecRef(ctx)
tg := k.NewThreadGroup(mntns, args.PIDNamespace, NewSignalHandlers(), linux.SIGCHLD, args.Limits)
// Grab the working directory.
wd := root // Default.
if args.WorkingDirectory != "" {
pop := vfs.PathOperation{
Root: root,
Start: wd,
Path: fspath.Parse(args.WorkingDirectory),
FollowFinalSymlink: true,
}
// NOTE(b/236028361): Do not set CheckSearchable flag to true.
// Application is allowed to start with a working directory that it can
// not access/search. This is consistent with Docker and VFS1. Runc
// explicitly allows for this in 6ce2d63a5db6 ("libct/init_linux: retry
// chdir to fix EPERM"). As described in the commit, runc unintentionally
// allowed this behavior in a couple of releases and applications started
// relying on it. So they decided to allow it for backward compatibility.
var err error
wd, err = k.VFS().GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{})
if err != nil {
return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err)
}
defer wd.DecRef(ctx)
}
opener := fsbridge.NewVFSLookup(mntns, root, wd)
fsContext := NewFSContext(root, wd, args.Umask)
tg := k.NewThreadGroup(nil, args.PIDNamespace, NewSignalHandlers(), linux.SIGCHLD, args.Limits)
cu := cleanup.Make(func() {
tg.Release(ctx)
})
@@ -1094,7 +990,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
UTSNamespace: args.UTSNamespace,
IPCNamespace: args.IPCNamespace,
AbstractSocketNamespace: args.AbstractSocketNamespace,
MountNamespaceVFS2: mntnsVFS2,
MountNamespace: mntns,
ContainerID: args.ContainerID,
UserCounters: k.GetUserCounters(args.Credentials.RealKUID),
}
@@ -1193,14 +1089,8 @@ func (k *Kernel) pauseTimeLocked(ctx context.Context) {
// but ktime.Timer.Pause is idempotent so this is harmless.
if t.fdTable != nil {
t.fdTable.forEach(ctx, func(_ int32, file *fs.File, fd *vfs.FileDescription, _ FDFlags) {
if VFS2Enabled {
if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok {
tfd.PauseTimer()
}
} else {
if tfd, ok := file.FileOperations.(*oldtimerfd.TimerOperations); ok {
tfd.PauseTimer()
}
if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok {
tfd.PauseTimer()
}
})
}
@@ -1229,14 +1119,8 @@ func (k *Kernel) resumeTimeLocked(ctx context.Context) {
}
if t.fdTable != nil {
t.fdTable.forEach(ctx, func(_ int32, file *fs.File, fd *vfs.FileDescription, _ FDFlags) {
if VFS2Enabled {
if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok {
tfd.ResumeTimer()
}
} else {
if tfd, ok := file.FileOperations.(*oldtimerfd.TimerOperations); ok {
tfd.ResumeTimer()
}
if tfd, ok := fd.Impl().(*timerfd.TimerFileDescription); ok {
tfd.ResumeTimer()
}
})
}
@@ -1678,14 +1562,8 @@ func (k *Kernel) DeleteSocketVFS2(sock *vfs.FileDescription) {
func (k *Kernel) ListSockets() []*SocketRecord {
k.extMu.Lock()
var socks []*SocketRecord
if VFS2Enabled {
for _, s := range k.socketsVFS2 {
socks = append(socks, s)
}
} else {
for s := k.sockets.Front(); s != nil; s = s.Next() {
socks = append(socks, &s.SocketRecord)
}
for _, s := range k.socketsVFS2 {
socks = append(socks, s)
}
k.extMu.Unlock()
return socks
@@ -1847,13 +1725,11 @@ func (k *Kernel) CgroupRegistry() *CgroupRegistry {
// initialized, e.g. after k.Start() has been called.
func (k *Kernel) Release() {
ctx := k.SupervisorContext()
if VFS2Enabled {
k.hostMount.DecRef(ctx)
k.pipeMount.DecRef(ctx)
k.shmMount.DecRef(ctx)
k.socketMount.DecRef(ctx)
k.vfs.Release(ctx)
}
k.hostMount.DecRef(ctx)
k.pipeMount.DecRef(ctx)
k.shmMount.DecRef(ctx)
k.socketMount.DecRef(ctx)
k.vfs.Release(ctx)
k.timekeeper.Destroy()
k.vdso.Release(ctx)
k.RootNetworkNamespace().DecRef()
-10
View File
@@ -123,11 +123,6 @@ func (t *Task) CanTrace(target *Task, attach bool) bool {
return false
}
// YAMA only supported for vfs2.
if !VFS2Enabled {
return true
}
if t.k.YAMAPtraceScope.Load() == linux.YAMA_SCOPE_RELATIONAL {
t.tg.pidns.owner.mu.RLock()
defer t.tg.pidns.owner.mu.RUnlock()
@@ -149,11 +144,6 @@ func (t *Task) canTraceLocked(target *Task, attach bool) bool {
return false
}
// YAMA only supported for vfs2.
if !VFS2Enabled {
return true
}
if t.k.YAMAPtraceScope.Load() == linux.YAMA_SCOPE_RELATIONAL {
if !t.canTraceYAMALocked(target) {
return false
+4 -6
View File
@@ -104,13 +104,11 @@ func (s *syslog) Log() []byte {
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, selectMessage()))...)
}
if VFS2Enabled {
time += rand.Float64() / 2
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up VFS..."))...)
if FUSEEnabled {
time += rand.Float64() / 2
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up VFS2..."))...)
if FUSEEnabled {
time += rand.Float64() / 2
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up FUSE..."))...)
}
s.msg = append(s.msg, []byte(fmt.Sprintf(format, time, "Setting up FUSE..."))...)
}
time += rand.Float64() / 2
+6 -16
View File
@@ -447,10 +447,10 @@ type Task struct {
// abstractSockets is protected by mu.
abstractSockets *AbstractSocketNamespace
// mountNamespaceVFS2 is the task's mount namespace.
// mountNamespace is the task's mount namespace.
//
// It is protected by mu. It is owned by the task goroutine.
mountNamespaceVFS2 *vfs.MountNamespace
mountNamespace *vfs.MountNamespace
// parentDeathSignal is sent to this task's thread group when its parent exits.
//
@@ -705,19 +705,9 @@ func (t *Task) SyscallRestartBlock() SyscallRestartBlock {
// Preconditions: The caller must be running on the task goroutine, or t.mu
// must be locked.
func (t *Task) IsChrooted() bool {
if VFS2Enabled {
realRoot := t.mountNamespaceVFS2.Root()
root := t.fsContext.RootDirectoryVFS2()
defer root.DecRef(t)
return root != realRoot
}
realRoot := t.tg.mounts.Root()
defer realRoot.DecRef(t)
root := t.fsContext.RootDirectory()
if root != nil {
defer root.DecRef(t)
}
realRoot := t.mountNamespace.Root()
root := t.fsContext.RootDirectoryVFS2()
defer root.DecRef(t)
return root != realRoot
}
@@ -839,7 +829,7 @@ func (t *Task) MountNamespace() *fs.MountNamespace {
func (t *Task) MountNamespaceVFS2() *vfs.MountNamespace {
t.mu.Lock()
defer t.mu.Unlock()
return t.mountNamespaceVFS2
return t.mountNamespace
}
// AbstractSockets returns t's AbstractSocketNamespace.
+7 -11
View File
@@ -103,9 +103,7 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
ipcns := t.IPCNamespace()
if args.Flags&linux.CLONE_NEWIPC != 0 {
ipcns = NewIPCNamespace(userns)
if VFS2Enabled {
ipcns.InitPosixQueues(t, t.k.VFS(), creds)
}
ipcns.InitPosixQueues(t, t.k.VFS(), creds)
} else {
ipcns.IncRef()
}
@@ -125,11 +123,11 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
})
// TODO(b/63601033): Implement CLONE_NEWNS.
mntnsVFS2 := t.mountNamespaceVFS2
if mntnsVFS2 != nil {
mntnsVFS2.IncRef()
mntns := t.mountNamespace
if mntns != nil {
mntns.IncRef()
cu.Add(func() {
mntnsVFS2.DecRef(t)
mntns.DecRef(t)
})
}
@@ -210,7 +208,7 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
UTSNamespace: utsns,
IPCNamespace: ipcns,
AbstractSocketNamespace: t.abstractSockets,
MountNamespaceVFS2: mntnsVFS2,
MountNamespace: mntns,
RSeqAddr: rseqAddr,
RSeqSignature: rseqSignature,
ContainerID: t.ContainerID(),
@@ -487,9 +485,7 @@ func (t *Task) Unshare(flags int32) error {
// namespace"
oldIPCNS = t.ipcns
t.ipcns = NewIPCNamespace(creds.UserNamespace)
if VFS2Enabled {
t.ipcns.InitPosixQueues(t, t.k.VFS(), creds)
}
t.ipcns.InitPosixQueues(t, t.k.VFS(), creds)
}
var oldFDTable *FDTable
if flags&linux.CLONE_FILES != 0 {
+2 -2
View File
@@ -105,8 +105,8 @@ func (t *Task) contextValue(key interface{}, isTaskGoroutine bool) interface{} {
t.mu.Lock()
defer t.mu.Unlock()
}
t.mountNamespaceVFS2.IncRef()
return t.mountNamespaceVFS2
t.mountNamespace.IncRef()
return t.mountNamespace
case fs.CtxDirentCacheLimiter:
return t.k.DirentCacheLimiter
case inet.CtxStack:
+2 -2
View File
@@ -285,8 +285,8 @@ func (*runExitMain) execute(t *Task) taskRunState {
t.LeaveCgroups()
t.mu.Lock()
mntns := t.mountNamespaceVFS2
t.mountNamespaceVFS2 = nil
mntns := t.mountNamespace
t.mountNamespace = nil
ipcns := t.ipcns
netns := t.NetworkNamespace()
t.mu.Unlock()
+29 -31
View File
@@ -85,8 +85,8 @@ type TaskConfig struct {
// AbstractSocketNamespace is the AbstractSocketNamespace of the new task.
AbstractSocketNamespace *AbstractSocketNamespace
// MountNamespaceVFS2 is the MountNamespace of the new task.
MountNamespaceVFS2 *vfs.MountNamespace
// MountNamespace is the MountNamespace of the new task.
MountNamespace *vfs.MountNamespace
// RSeqAddr is a pointer to the the userspace linux.RSeq structure.
RSeqAddr hostarch.Addr
@@ -116,8 +116,8 @@ func (ts *TaskSet) NewTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
cfg.FDTable.DecRef(ctx)
cfg.IPCNamespace.DecRef(ctx)
cfg.NetworkNamespace.DecRef()
if cfg.MountNamespaceVFS2 != nil {
cfg.MountNamespaceVFS2.DecRef(ctx)
if cfg.MountNamespace != nil {
cfg.MountNamespace.DecRef(ctx)
}
}
if err := cfg.UserCounters.incRLimitNProc(ctx); err != nil {
@@ -145,29 +145,29 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
parent: cfg.Parent,
children: make(map[*Task]struct{}),
},
runState: (*runApp)(nil),
interruptChan: make(chan struct{}, 1),
signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)),
signalStack: linux.SignalStack{Flags: linux.SS_DISABLE},
image: *image,
fsContext: cfg.FSContext,
fdTable: cfg.FDTable,
k: cfg.Kernel,
ptraceTracees: make(map[*Task]struct{}),
allowedCPUMask: cfg.AllowedCPUMask.Copy(),
ioUsage: &usage.IO{},
niceness: cfg.Niceness,
utsns: cfg.UTSNamespace,
ipcns: cfg.IPCNamespace,
abstractSockets: cfg.AbstractSocketNamespace,
mountNamespaceVFS2: cfg.MountNamespaceVFS2,
rseqCPU: -1,
rseqAddr: cfg.RSeqAddr,
rseqSignature: cfg.RSeqSignature,
futexWaiter: futex.NewWaiter(),
containerID: cfg.ContainerID,
cgroups: make(map[Cgroup]struct{}),
userCounters: cfg.UserCounters,
runState: (*runApp)(nil),
interruptChan: make(chan struct{}, 1),
signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)),
signalStack: linux.SignalStack{Flags: linux.SS_DISABLE},
image: *image,
fsContext: cfg.FSContext,
fdTable: cfg.FDTable,
k: cfg.Kernel,
ptraceTracees: make(map[*Task]struct{}),
allowedCPUMask: cfg.AllowedCPUMask.Copy(),
ioUsage: &usage.IO{},
niceness: cfg.Niceness,
utsns: cfg.UTSNamespace,
ipcns: cfg.IPCNamespace,
abstractSockets: cfg.AbstractSocketNamespace,
mountNamespace: cfg.MountNamespace,
rseqCPU: -1,
rseqAddr: cfg.RSeqAddr,
rseqSignature: cfg.RSeqSignature,
futexWaiter: futex.NewWaiter(),
containerID: cfg.ContainerID,
cgroups: make(map[Cgroup]struct{}),
userCounters: cfg.UserCounters,
}
t.netns.Store(cfg.NetworkNamespace)
t.creds.Store(cfg.Credentials)
@@ -238,10 +238,8 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
t.parent.children[t] = struct{}{}
}
if VFS2Enabled {
// srcT may be nil, in which case we default to root cgroups.
t.EnterInitialCgroups(srcT)
}
// srcT may be nil, in which case we default to root cgroups.
t.EnterInitialCgroups(srcT)
if tg.leader == nil {
// New thread group.
+4 -12
View File
@@ -712,19 +712,11 @@ func Parse(t *kernel.Task, socketOrEndpoint interface{}, buf []byte, width uint)
}
if len(fds) > 0 {
if kernel.VFS2Enabled {
rights, err := NewSCMRightsVFS2(t, fds)
if err != nil {
return socket.ControlMessages{}, err
}
cmsgs.Unix.Rights = rights
} else {
rights, err := NewSCMRights(t, fds)
if err != nil {
return socket.ControlMessages{}, err
}
cmsgs.Unix.Rights = rights
rights, err := NewSCMRightsVFS2(t, fds)
if err != nil {
return socket.ControlMessages{}, err
}
cmsgs.Unix.Rights = rights
}
return cmsgs, nil

Some files were not shown because too many files have changed in this diff Show More