Implement the setns syscall

This change introduces the nsfs file system. Each new namespace allocates
a new nsfs inode.

Here are reasons why we need these inodes:
* each namespace has to have an unique id.
* proc/pid/ns/ contains one entry for each namespace. Bind mounting one of
  the files in this directory to somewhere else in the filesystem keeps the
  corresponding namespace alive even if all processes currently in
  the namespace terminate.
* setns() allows the calling process to join an existing namespace specified
  by a file descriptor.

PiperOrigin-RevId: 550694515
This commit is contained in:
Andrei Vagin
2023-07-24 15:45:08 -07:00
committed by gVisor bot
parent a5fd5015e9
commit 46115504ec
24 changed files with 509 additions and 44 deletions
+1
View File
@@ -24,6 +24,7 @@ const (
EXT_SUPER_MAGIC = 0xef53
FUSE_SUPER_MAGIC = 0x65735546
MQUEUE_MAGIC = 0x19800202
NSFS_MAGIC = 0x6e736673
OVERLAYFS_SUPER_MAGIC = 0x794c7630
PIPEFS_MAGIC = 0x50495045
PROC_SUPER_MAGIC = 0x9fa0
+39
View File
@@ -0,0 +1,39 @@
load("//tools:defs.bzl", "go_library")
load("//tools/go_generics:defs.bzl", "go_template_instance")
package(default_applicable_licenses = ["//:license"])
licenses(["notice"])
go_template_instance(
name = "inode_refs",
out = "inode_refs.go",
package = "nsfs",
prefix = "inode",
template = "//pkg/refs:refs_template",
types = {
"T": "Inode",
},
)
go_library(
name = "nsfs",
srcs = [
"inode_refs.go",
"nsfs.go",
],
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/abi/linux",
"//pkg/atomicbitops",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/hostarch",
"//pkg/refs",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/time",
"//pkg/sentry/vfs",
"//pkg/sync",
],
)
+205
View File
@@ -0,0 +1,205 @@
// Copyright 2023 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package nsfs provides the filesystem implementation backing
// Kernel.NsfsMount.
package nsfs
import (
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/vfs"
)
// +stateify savable
type filesystemType struct{}
// Name implements vfs.FilesystemType.Name.
func (filesystemType) Name() string {
return "nsfs"
}
// Release implements vfs.FilesystemType.Release.
func (filesystemType) Release(ctx context.Context) {}
// GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (filesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
panic("nsfs.filesystemType.GetFilesystem should never be called")
}
// +stateify savable
type filesystem struct {
kernfs.Filesystem
devMinor uint32
}
// NewFilesystem sets up and returns a new vfs.Filesystem implemented by nsfs.
func NewFilesystem(vfsObj *vfs.VirtualFilesystem) (*vfs.Filesystem, error) {
devMinor, err := vfsObj.GetAnonBlockDevMinor()
if err != nil {
return nil, err
}
fs := &filesystem{
devMinor: devMinor,
}
fs.Filesystem.VFSFilesystem().Init(vfsObj, filesystemType{}, fs)
return fs.Filesystem.VFSFilesystem(), nil
}
// Release implements vfs.FilesystemImpl.Release.
func (fs *filesystem) Release(ctx context.Context) {
fs.Filesystem.VFSFilesystem().VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor)
fs.Filesystem.Release(ctx)
}
// MountOptions implements vfs.FilesystemImpl.MountOptions.
func (fs *filesystem) MountOptions() string {
return ""
}
// Inode implements kernfs.Inode.
//
// +stateify savable
type Inode struct {
kernfs.InodeAttrs
kernfs.InodeNotAnonymous
kernfs.InodeNotDirectory
kernfs.InodeNotSymlink
kernfs.InodeWatches
inodeRefs
locks vfs.FileLocks
namespace Namespace
mnt *vfs.Mount
}
// DecRef implements kernfs.Inode.DecRef.
func (i *Inode) DecRef(ctx context.Context) {
i.inodeRefs.DecRef(func() { i.namespace.Destroy(ctx) })
}
// Keep implements kernfs.Inode.Keep.
func (i *Inode) Keep() bool {
return false
}
// Namespace is the namespace interface.
type Namespace interface {
Type() string
Destroy(ctx context.Context)
}
// NewInode creates a new nsfs inode.
func NewInode(ctx context.Context, mnt *vfs.Mount, namespace Namespace) *Inode {
fs := mnt.Filesystem().Impl().(*filesystem)
creds := auth.CredentialsFromContext(ctx)
i := &Inode{
namespace: namespace,
mnt: mnt,
}
i.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.Filesystem.NextIno(), nsfsMode)
i.InitRefs()
return i
}
const nsfsMode = linux.S_IFREG | linux.ModeUserRead | linux.ModeGroupRead | linux.ModeOtherRead
// Namespace returns the namespace associated with the inode.
func (i *Inode) Namespace() Namespace {
return i.namespace
}
// Name returns the inode name that is used to implement readlink() of
// /proc/pid/ns/ files.
func (i *Inode) Name() string {
return fmt.Sprintf("%s:[%d]", i.namespace.Type(), i.Ino())
}
// VirtualDentry returns VirtualDentry for the inode.
func (i *Inode) VirtualDentry() vfs.VirtualDentry {
dentry := &kernfs.Dentry{}
mnt := i.mnt
fs := mnt.Filesystem().Impl().(*filesystem)
i.IncRef()
mnt.IncRef()
dentry.Init(&fs.Filesystem, i)
vd := vfs.MakeVirtualDentry(mnt, dentry.VFSDentry())
return vd
}
// Mode implements kernfs.Inode.Mode.
func (i *Inode) Mode() linux.FileMode {
return nsfsMode
}
// SetStat implements kernfs.Inode.SetStat.
//
// Linux sets S_IMMUTABLE to nsfs inodes that prevents any attribute changes on
// them.
func (i *Inode) SetStat(ctx context.Context, vfsfs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
return linuxerr.EPERM
}
// namespace FD is a synthetic file that represents a namespace in
// /proc/[pid]/ns/*.
//
// +stateify savable
type namespaceFD struct {
vfs.FileDescriptionDefaultImpl
vfs.LockFD
vfsfd vfs.FileDescription
inode *Inode
}
// Stat implements vfs.FileDescriptionImpl.Stat.
func (fd *namespaceFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
return fd.inode.Stat(ctx, vfs, opts)
}
// SetStat implements vfs.FileDescriptionImpl.SetStat.
func (fd *namespaceFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error {
vfs := fd.vfsfd.VirtualDentry().Mount().Filesystem()
creds := auth.CredentialsFromContext(ctx)
return fd.inode.SetStat(ctx, vfs, creds, opts)
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *namespaceFD) Release(ctx context.Context) {
fd.inode.DecRef(ctx)
}
// Open implements kernfs.Inode.Open.
func (i *Inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
fd := &namespaceFD{inode: i}
i.IncRef()
fd.LockFD.Init(&i.locks)
if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{}); err != nil {
return nil, err
}
return &fd.vfsfd, nil
}
// StatFS implements kernfs.Inode.StatFS.
func (i *Inode) StatFS(ctx context.Context, fs *vfs.Filesystem) (linux.Statfs, error) {
return vfs.GenericStatFS(linux.NSFS_MAGIC), nil
}
+1
View File
@@ -91,6 +91,7 @@ go_library(
"//pkg/safemem",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/fsimpl/lock",
"//pkg/sentry/fsimpl/nsfs",
"//pkg/sentry/inet",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
+1 -1
View File
@@ -72,7 +72,7 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns
"mounts": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &mountsData{fs: fs, task: task}),
"net": fs.newTaskNetDir(ctx, task),
"ns": fs.newTaskOwnedDir(ctx, task, fs.NextIno(), 0511, map[string]kernfs.Inode{
"net": fs.newFakeNamespaceSymlink(ctx, task, fs.NextIno(), "net"),
"net": fs.newNamespaceSymlink(ctx, task, fs.NextIno(), linux.CLONE_NEWNET),
"pid": fs.newPIDNamespaceSymlink(ctx, task, fs.NextIno()),
"user": fs.newFakeNamespaceSymlink(ctx, task, fs.NextIno(), "user"),
}),
+39 -1
View File
@@ -27,6 +27,7 @@ import (
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/safemem"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/nsfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/limits"
@@ -1230,7 +1231,18 @@ func (i *mountsData) Generate(ctx context.Context, buf *bytes.Buffer) error {
type namespaceSymlink struct {
kernfs.StaticSymlink
task *kernel.Task
task *kernel.Task
nsType int
}
func (fs *filesystem) newNamespaceSymlink(ctx context.Context, task *kernel.Task, ino uint64, nsType int) kernfs.Inode {
inode := &namespaceSymlink{task: task, nsType: nsType}
// Note: credentials are overridden by taskOwnedInode.
inode.Init(ctx, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, "")
taskInode := &taskOwnedInode{Inode: inode, owner: task}
return taskInode
}
func (fs *filesystem) newPIDNamespaceSymlink(ctx context.Context, task *kernel.Task, ino uint64) kernfs.Inode {
@@ -1258,11 +1270,29 @@ func (fs *filesystem) newFakeNamespaceSymlink(ctx context.Context, task *kernel.
return taskInode
}
func (s *namespaceSymlink) getInode(t *kernel.Task) *nsfs.Inode {
switch s.nsType {
case linux.CLONE_NEWNET:
return t.GetNetworkNamespace().GetInode()
default:
panic("unknown namespace")
}
}
// Readlink implements kernfs.Inode.Readlink.
func (s *namespaceSymlink) Readlink(ctx context.Context, mnt *vfs.Mount) (string, error) {
if err := checkTaskState(s.task); err != nil {
return "", err
}
if s.nsType != 0 {
inode := s.getInode(s.task)
if inode == nil {
return "", linuxerr.ENOENT
}
target := inode.Name()
inode.DecRef(ctx)
return target, nil
}
return s.StaticSymlink.Readlink(ctx, mnt)
}
@@ -1272,6 +1302,14 @@ func (s *namespaceSymlink) Getlink(ctx context.Context, mnt *vfs.Mount) (vfs.Vir
return vfs.VirtualDentry{}, "", err
}
if s.nsType != 0 {
inode := s.getInode(s.task)
if inode == nil {
return vfs.VirtualDentry{}, "", linuxerr.ENOENT
}
defer inode.DecRef(ctx)
return inode.VirtualDentry(), "", nil
}
// Create a synthetic inode to represent the namespace.
fs := mnt.Filesystem().Impl().(*filesystem)
nsInode := &namespaceInode{}
-1
View File
@@ -100,7 +100,6 @@ go_library(
"//pkg/sentry/kernel/time",
"//pkg/sentry/memmap",
"//pkg/sentry/pgalloc",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/usage",
"//pkg/state",
"//pkg/sync",
+2
View File
@@ -44,6 +44,8 @@ go_library(
"//pkg/atomicbitops",
"//pkg/context",
"//pkg/refs",
"//pkg/sentry/fsimpl/nsfs",
"//pkg/sentry/kernel/auth",
"//pkg/tcpip",
"//pkg/tcpip/stack",
],
+47 -11
View File
@@ -14,11 +14,17 @@
package inet
import (
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/nsfs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
)
// Namespace represents a network namespace. See network_namespaces(7).
//
// +stateify savable
type Namespace struct {
namespaceRefs
inode *nsfs.Inode
// stack is the network stack implementation of this network namespace.
stack Stack `state:"nosave"`
@@ -32,38 +38,68 @@ type Namespace struct {
// isRoot indicates whether this is the root network namespace.
isRoot bool
userNS *auth.UserNamespace
}
// NewRootNamespace creates the root network namespace, with creator
// allowing new network namespaces to be created. If creator is nil, no
// networking will function if the network is namespaced.
func NewRootNamespace(stack Stack, creator NetworkStackCreator) *Namespace {
func NewRootNamespace(stack Stack, creator NetworkStackCreator, userNS *auth.UserNamespace) *Namespace {
n := &Namespace{
stack: stack,
creator: creator,
isRoot: true,
userNS: userNS,
}
n.InitRefs()
return n
}
// UserNamespace returns the user namespace associated with this namespace.
func (n *Namespace) UserNamespace() *auth.UserNamespace {
return n.userNS
}
// SetInode sets the nsfs `inode` to the namespace.
func (n *Namespace) SetInode(inode *nsfs.Inode) {
n.inode = inode
}
// GetInode returns the nsfs inode associated with this namespace.
func (n *Namespace) GetInode() *nsfs.Inode {
return n.inode
}
// NewNamespace creates a new network namespace from the root.
func NewNamespace(root *Namespace) *Namespace {
func NewNamespace(root *Namespace, userNS *auth.UserNamespace) *Namespace {
n := &Namespace{
creator: root.creator,
userNS: userNS,
}
n.init()
n.InitRefs()
return n
}
// Destroy implements nsfs.Namespace.Destroy.
func (n *Namespace) Destroy(ctx context.Context) {
if s := n.Stack(); s != nil {
s.Destroy()
}
}
// Type implements nsfs.Namespace.Type.
func (n *Namespace) Type() string {
return "net"
}
// IncRef increments the Namespace's refcount.
func (n *Namespace) IncRef() {
n.inode.IncRef()
}
// DecRef decrements the Namespace's refcount.
func (n *Namespace) DecRef() {
n.namespaceRefs.DecRef(func() {
if s := n.Stack(); s != nil {
s.Destroy()
}
})
func (n *Namespace) DecRef(ctx context.Context) {
n.inode.DecRef(ctx)
}
// Stack returns the network stack of n. Stack may return nil if no network
+1
View File
@@ -354,6 +354,7 @@ go_library(
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/fsimpl/lock",
"//pkg/sentry/fsimpl/mqfs",
"//pkg/sentry/fsimpl/nsfs",
"//pkg/sentry/fsimpl/pipefs",
"//pkg/sentry/fsimpl/sockfs",
"//pkg/sentry/fsimpl/timerfd",
+21 -2
View File
@@ -47,6 +47,7 @@ import (
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/nsfs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/pipefs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/timerfd"
@@ -274,6 +275,9 @@ type Kernel struct {
// syscalls (as opposed to named pipes created by mknod()).
pipeMount *vfs.Mount
// nsfsMount is the Mount used for namespaces.
nsfsMount *vfs.Mount
// shmMount is the Mount used for anonymous files created by the
// memfd_create() syscalls. It is analogous to Linux's shm_mnt.
shmMount *vfs.Mount
@@ -395,7 +399,7 @@ func (k *Kernel) Init(args InitKernelArgs) error {
k.rootAbstractSocketNamespace = args.RootAbstractSocketNamespace
k.rootNetworkNamespace = args.RootNetworkNamespace
if k.rootNetworkNamespace == nil {
k.rootNetworkNamespace = inet.NewRootNamespace(nil, nil)
k.rootNetworkNamespace = inet.NewRootNamespace(nil, nil, args.RootUserNamespace)
}
k.runningTasksCond.L = &k.runningTasksMu
k.cpuClockTickerWakeCh = make(chan struct{}, 1)
@@ -439,6 +443,15 @@ func (k *Kernel) Init(args InitKernelArgs) error {
pipeMount := k.vfs.NewDisconnectedMount(pipeFilesystem, nil, &vfs.MountOptions{})
k.pipeMount = pipeMount
nsfsFilesystem, err := nsfs.NewFilesystem(&k.vfs)
if err != nil {
return fmt.Errorf("failed to create nsfs filesystem: %v", err)
}
defer nsfsFilesystem.DecRef(ctx)
nsfsMount := k.vfs.NewDisconnectedMount(nsfsFilesystem, nil, &vfs.MountOptions{})
k.nsfsMount = nsfsMount
k.rootNetworkNamespace.SetInode(nsfs.NewInode(ctx, nsfsMount, k.rootNetworkNamespace))
tmpfsOpts := vfs.GetFilesystemOptions{
InternalData: tmpfs.FilesystemOpts{
// See mm/shmem.c:shmem_init() => vfs_kern_mount(flags=SB_KERNMOUNT).
@@ -1607,6 +1620,11 @@ func (k *Kernel) PipeMount() *vfs.Mount {
return k.pipeMount
}
// NsfsMount returns the nsfs mount.
func (k *Kernel) NsfsMount() *vfs.Mount {
return k.nsfsMount
}
// ShmMount returns the tmpfs mount.
func (k *Kernel) ShmMount() *vfs.Mount {
return k.shmMount
@@ -1630,12 +1648,13 @@ func (k *Kernel) Release() {
ctx := k.SupervisorContext()
k.hostMount.DecRef(ctx)
k.pipeMount.DecRef(ctx)
k.nsfsMount.DecRef(ctx)
k.shmMount.DecRef(ctx)
k.socketMount.DecRef(ctx)
k.vfs.Release(ctx)
k.timekeeper.Destroy()
k.vdso.Release(ctx)
k.RootNetworkNamespace().DecRef()
k.RootNetworkNamespace().DecRef(ctx)
}
// PopulateNewCgroupHierarchy moves all tasks into a newly created cgroup
+3 -1
View File
@@ -506,7 +506,9 @@ type Task struct {
numaPolicy linux.NumaPolicy
numaNodeMask uint64
// netns is the task's network namespace. netns is never nil.
// netns is the task's network namespace. It has to be changed under mu
// so that GetNetworkNamespace can take a reference before it is
// released.
netns inet.NamespaceAtomicPtr
// If rseqPreempted is true, before the next call to p.Switch(),
+49 -10
View File
@@ -21,9 +21,12 @@ import (
"gvisor.dev/gvisor/pkg/cleanup"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/nsfs"
"gvisor.dev/gvisor/pkg/sentry/inet"
"gvisor.dev/gvisor/pkg/sentry/seccheck"
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/usermem"
)
@@ -117,14 +120,16 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
})
defer cu.Clean()
netns := t.NetworkNamespace()
netns := t.netns.Load()
if args.Flags&linux.CLONE_NEWNET != 0 {
netns = inet.NewNamespace(netns)
netns = inet.NewNamespace(netns, userns)
inode := nsfs.NewInode(t, t.k.nsfsMount, netns)
netns.SetInode(inode)
} else {
netns.IncRef()
}
cu.Add(func() {
netns.DecRef()
netns.DecRef(t)
})
// TODO(b/63601033): Implement CLONE_NEWNS.
@@ -405,6 +410,38 @@ func (r *runSyscallAfterVforkStop) execute(t *Task) taskRunState {
return (*runSyscallExit)(nil)
}
// Setns reassociates thread with the specified namespace.
func (t *Task) Setns(fd *vfs.FileDescription, flags int32) error {
d, ok := fd.Dentry().Impl().(*kernfs.Dentry)
if !ok {
return linuxerr.EINVAL
}
i, ok := d.Inode().(*nsfs.Inode)
if !ok {
return linuxerr.EINVAL
}
switch ns := i.Namespace().(type) {
case *inet.Namespace:
if flags != 0 && flags != linux.CLONE_NEWNET {
return linuxerr.EINVAL
}
if !t.HasCapabilityIn(linux.CAP_SYS_ADMIN, ns.UserNamespace()) ||
!t.Credentials().HasCapability(linux.CAP_SYS_ADMIN) {
return linuxerr.EPERM
}
oldNS := t.NetworkNamespace()
ns.IncRef()
t.mu.Lock()
t.netns.Store(ns)
t.mu.Unlock()
oldNS.DecRef(t)
return nil
default:
return linuxerr.EINVAL
}
}
// Unshare changes the set of resources t shares with other tasks, as specified
// by flags.
//
@@ -456,7 +493,7 @@ func (t *Task) Unshare(flags int32) error {
if err != nil {
return err
}
// Need to reload creds, becaue t.SetUserNamespace() changed task credentials.
// Need to reload creds, because t.SetUserNamespace() changed task credentials.
creds = t.Credentials()
}
haveCapSysAdmin := t.HasCapability(linux.CAP_SYS_ADMIN)
@@ -466,13 +503,18 @@ func (t *Task) Unshare(flags int32) error {
}
t.childPIDNamespace = t.tg.pidns.NewChild(t.UserNamespace())
}
var oldNETNS *inet.Namespace
if flags&linux.CLONE_NEWNET != 0 {
if !haveCapSysAdmin {
return linuxerr.EPERM
}
oldNETNS = t.netns.Load()
t.netns.Store(inet.NewNamespace(t.netns.Load()))
netns := t.NetworkNamespace()
netns = inet.NewNamespace(netns, t.UserNamespace())
netnsInode := nsfs.NewInode(t, t.k.nsfsMount, netns)
netns.SetInode(netnsInode)
t.mu.Lock()
netns = t.netns.Swap(netns)
t.mu.Unlock()
netns.DecRef(t)
}
t.mu.Lock()
// Can't defer unlock: DecRefs must occur without holding t.mu.
@@ -511,9 +553,6 @@ func (t *Task) Unshare(flags int32) error {
if oldIPCNS != nil {
oldIPCNS.DecRef(t)
}
if oldNETNS != nil {
oldNETNS.DecRef()
}
if oldFDTable != nil {
oldFDTable.DecRef(t)
}
+2 -2
View File
@@ -288,13 +288,13 @@ func (*runExitMain) execute(t *Task) taskRunState {
mntns := t.mountNamespace
t.mountNamespace = nil
ipcns := t.ipcns
netns := t.NetworkNamespace()
netns := t.netns.Swap(nil)
t.mu.Unlock()
if mntns != nil {
mntns.DecRef(t)
}
ipcns.DecRef(t)
netns.DecRef()
netns.DecRef(t)
// If this is the last task to exit from the thread group, release the
// thread group's resources.
+14
View File
@@ -36,3 +36,17 @@ func (t *Task) NetworkContext() inet.Stack {
func (t *Task) NetworkNamespace() *inet.Namespace {
return t.netns.Load()
}
// GetNetworkNamespace takes a reference on the task network namespace and
// returns it. It can return nil if the task isn't alive.
func (t *Task) GetNetworkNamespace() *inet.Namespace {
// t.mu is required to be sure that the network namespace will not be
// released.
t.mu.Lock()
netns := t.netns.Load()
if netns != nil {
netns.IncRef()
}
t.mu.Unlock()
return netns
}
+1 -1
View File
@@ -117,7 +117,7 @@ func (ts *TaskSet) NewTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
cfg.FSContext.DecRef(ctx)
cfg.FDTable.DecRef(ctx)
cfg.IPCNamespace.DecRef(ctx)
cfg.NetworkNamespace.DecRef()
cfg.NetworkNamespace.DecRef(ctx)
if cfg.MountNamespace != nil {
cfg.MountNamespace.DecRef(ctx)
}
+1 -1
View File
@@ -442,7 +442,7 @@ func (s *sock) Release(ctx context.Context) {
_ = t.BlockWithDeadline(ch, true, deadline)
}
}
s.namespace.DecRef()
s.namespace.DecRef(ctx)
}
// Epollable implements FileDescriptionImpl.Epollable.
-1
View File
@@ -97,7 +97,6 @@ go_library(
"//pkg/log",
"//pkg/refs",
"//pkg/sentry/hostfd",
"//pkg/sentry/inet",
"//pkg/sentry/uniqueid",
"//pkg/sync",
"//pkg/sync/locking",
+2 -2
View File
@@ -360,7 +360,7 @@ var AMD64 = &kernel.SyscallTable{
305: syscalls.CapError("clock_adjtime", linux.CAP_SYS_TIME, "", nil),
306: syscalls.Supported("syncfs", Syncfs),
307: syscalls.Supported("sendmmsg", SendMMsg),
308: syscalls.ErrorWithEvent("setns", linuxerr.EOPNOTSUPP, "Needs filesystem support", []string{"gvisor.dev/issue/140"}), // TODO(b/29354995)
308: syscalls.Supported("setns", Setns),
309: syscalls.Supported("getcpu", Getcpu),
310: syscalls.ErrorWithEvent("process_vm_readv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}), // TODO(b/260724654)
311: syscalls.ErrorWithEvent("process_vm_writev", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}), // TODO(b/260724654)
@@ -683,7 +683,7 @@ var ARM64 = &kernel.SyscallTable{
265: syscalls.Error("open_by_handle_at", linuxerr.EOPNOTSUPP, "Not supported by gVisor filesystems", nil),
266: syscalls.CapError("clock_adjtime", linux.CAP_SYS_TIME, "", nil),
267: syscalls.Supported("syncfs", Syncfs),
268: syscalls.ErrorWithEvent("setns", linuxerr.EOPNOTSUPP, "Needs filesystem support", []string{"gvisor.dev/issue/140"}), // TODO(b/29354995)
268: syscalls.Supported("setns", Setns),
269: syscalls.Supported("sendmmsg", SendMMsg),
270: syscalls.ErrorWithEvent("process_vm_readv", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}), // TODO(b/260724654)
271: syscalls.ErrorWithEvent("process_vm_writev", linuxerr.ENOSYS, "", []string{"gvisor.dev/issue/158"}), // TODO(b/260724654)
+1 -1
View File
@@ -76,7 +76,7 @@ func Mount(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr,
return 0, nil, err
}
var sourceTpop taskPathOperation
sourceTpop, err = getTaskPathOperation(t, linux.AT_FDCWD, sourcePath, disallowEmptyPath, nofollowFinalSymlink)
sourceTpop, err = getTaskPathOperation(t, linux.AT_FDCWD, sourcePath, disallowEmptyPath, followFinalSymlink)
if err != nil {
return 0, nil, err
}

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