summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/sentry/inet/atomicptr_netns_unsafe.go39
-rw-r--r--pkg/sentry/inet/inet_unsafe_state_autogen.go38
-rw-r--r--pkg/sentry/kernel/task.go2
-rw-r--r--pkg/sentry/kernel/task_clone.go2
-rw-r--r--pkg/sentry/kernel/task_net.go12
-rw-r--r--pkg/sentry/kernel/task_start.go2
6 files changed, 83 insertions, 12 deletions
diff --git a/pkg/sentry/inet/atomicptr_netns_unsafe.go b/pkg/sentry/inet/atomicptr_netns_unsafe.go
new file mode 100644
index 000000000..e338ca663
--- /dev/null
+++ b/pkg/sentry/inet/atomicptr_netns_unsafe.go
@@ -0,0 +1,39 @@
+package inet
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+// An AtomicPtr is a pointer to a value of type Value that can be atomically
+// loaded and stored. The zero value of an AtomicPtr represents nil.
+//
+// Note that copying AtomicPtr by value performs a non-atomic read of the
+// stored pointer, which is unsafe if Store() can be called concurrently; in
+// this case, do `dst.Store(src.Load())` instead.
+//
+// +stateify savable
+type NamespaceAtomicPtr struct {
+ ptr unsafe.Pointer `state:".(*Namespace)"`
+}
+
+func (p *NamespaceAtomicPtr) savePtr() *Namespace {
+ return p.Load()
+}
+
+func (p *NamespaceAtomicPtr) loadPtr(v *Namespace) {
+ p.Store(v)
+}
+
+// Load returns the value set by the most recent Store. It returns nil if there
+// has been no previous call to Store.
+//
+//go:nosplit
+func (p *NamespaceAtomicPtr) Load() *Namespace {
+ return (*Namespace)(atomic.LoadPointer(&p.ptr))
+}
+
+// Store sets the value returned by Load to x.
+func (p *NamespaceAtomicPtr) Store(x *Namespace) {
+ atomic.StorePointer(&p.ptr, (unsafe.Pointer)(x))
+}
diff --git a/pkg/sentry/inet/inet_unsafe_state_autogen.go b/pkg/sentry/inet/inet_unsafe_state_autogen.go
new file mode 100644
index 000000000..d1a8d74b3
--- /dev/null
+++ b/pkg/sentry/inet/inet_unsafe_state_autogen.go
@@ -0,0 +1,38 @@
+// automatically generated by stateify.
+
+package inet
+
+import (
+ "gvisor.dev/gvisor/pkg/state"
+)
+
+func (p *NamespaceAtomicPtr) StateTypeName() string {
+ return "pkg/sentry/inet.NamespaceAtomicPtr"
+}
+
+func (p *NamespaceAtomicPtr) StateFields() []string {
+ return []string{
+ "ptr",
+ }
+}
+
+func (p *NamespaceAtomicPtr) beforeSave() {}
+
+// +checklocksignore
+func (p *NamespaceAtomicPtr) StateSave(stateSinkObject state.Sink) {
+ p.beforeSave()
+ var ptrValue *Namespace
+ ptrValue = p.savePtr()
+ stateSinkObject.SaveValue(0, ptrValue)
+}
+
+func (p *NamespaceAtomicPtr) afterLoad() {}
+
+// +checklocksignore
+func (p *NamespaceAtomicPtr) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.LoadValue(0, new(*Namespace), func(y interface{}) { p.loadPtr(y.(*Namespace)) })
+}
+
+func init() {
+ state.Register((*NamespaceAtomicPtr)(nil))
+}
diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go
index 9a95bf44c..2eebd1b47 100644
--- a/pkg/sentry/kernel/task.go
+++ b/pkg/sentry/kernel/task.go
@@ -513,7 +513,7 @@ type Task struct {
// netns is the task's network namespace. netns is never nil.
//
// netns is protected by mu.
- netns *inet.Namespace
+ netns inet.NamespaceAtomicPtr
// If rseqPreempted is true, before the next call to p.Switch(),
// interrupt rseq critical regions as defined by rseqAddr and
diff --git a/pkg/sentry/kernel/task_clone.go b/pkg/sentry/kernel/task_clone.go
index 26a981f36..a6d8fb163 100644
--- a/pkg/sentry/kernel/task_clone.go
+++ b/pkg/sentry/kernel/task_clone.go
@@ -444,7 +444,7 @@ func (t *Task) Unshare(flags int32) error {
t.mu.Unlock()
return linuxerr.EPERM
}
- t.netns = inet.NewNamespace(t.netns)
+ t.netns.Store(inet.NewNamespace(t.netns.Load()))
}
if flags&linux.CLONE_NEWUTS != 0 {
if !haveCapSysAdmin {
diff --git a/pkg/sentry/kernel/task_net.go b/pkg/sentry/kernel/task_net.go
index f7711232c..e31e2b2e8 100644
--- a/pkg/sentry/kernel/task_net.go
+++ b/pkg/sentry/kernel/task_net.go
@@ -20,9 +20,7 @@ import (
// IsNetworkNamespaced returns true if t is in a non-root network namespace.
func (t *Task) IsNetworkNamespaced() bool {
- t.mu.Lock()
- defer t.mu.Unlock()
- return !t.netns.IsRoot()
+ return !t.netns.Load().IsRoot()
}
// NetworkContext returns the network stack used by the task. NetworkContext
@@ -31,14 +29,10 @@ func (t *Task) IsNetworkNamespaced() bool {
// TODO(gvisor.dev/issue/1833): Migrate callers of this method to
// NetworkNamespace().
func (t *Task) NetworkContext() inet.Stack {
- t.mu.Lock()
- defer t.mu.Unlock()
- return t.netns.Stack()
+ return t.netns.Load().Stack()
}
// NetworkNamespace returns the network namespace observed by the task.
func (t *Task) NetworkNamespace() *inet.Namespace {
- t.mu.Lock()
- defer t.mu.Unlock()
- return t.netns
+ return t.netns.Load()
}
diff --git a/pkg/sentry/kernel/task_start.go b/pkg/sentry/kernel/task_start.go
index 217c6f531..4919dea7c 100644
--- a/pkg/sentry/kernel/task_start.go
+++ b/pkg/sentry/kernel/task_start.go
@@ -140,7 +140,6 @@ func (ts *TaskSet) newTask(cfg *TaskConfig) (*Task, error) {
allowedCPUMask: cfg.AllowedCPUMask.Copy(),
ioUsage: &usage.IO{},
niceness: cfg.Niceness,
- netns: cfg.NetworkNamespace,
utsns: cfg.UTSNamespace,
ipcns: cfg.IPCNamespace,
abstractSockets: cfg.AbstractSocketNamespace,
@@ -152,6 +151,7 @@ func (ts *TaskSet) newTask(cfg *TaskConfig) (*Task, error) {
containerID: cfg.ContainerID,
cgroups: make(map[Cgroup]struct{}),
}
+ t.netns.Store(cfg.NetworkNamespace)
t.creds.Store(cfg.Credentials)
t.endStopCond.L = &t.tg.signalHandlers.mu
t.ptraceTracer.Store((*Task)(nil))