// Copyright 2020 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 kernel import ( "time" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/cpuid" "gvisor.dev/gvisor/pkg/devutil" "gvisor.dev/gvisor/pkg/sentry/inet" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" "gvisor.dev/gvisor/pkg/sentry/kernel/shm" "gvisor.dev/gvisor/pkg/sentry/ktime" "gvisor.dev/gvisor/pkg/sentry/limits" "gvisor.dev/gvisor/pkg/sentry/pgalloc" "gvisor.dev/gvisor/pkg/sentry/platform" "gvisor.dev/gvisor/pkg/sentry/unimpl" "gvisor.dev/gvisor/pkg/sentry/uniqueid" "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/pkg/sync" ) // Deadline implements context.Context.Deadline. func (*Task) Deadline() (time.Time, bool) { return time.Time{}, false } // Done implements context.Context.Done. func (*Task) Done() <-chan struct{} { return nil } // Err implements context.Context.Err. func (*Task) Err() error { return nil } // Value implements context.Context.Value. // // Preconditions: The caller must be running on the task goroutine. func (t *Task) Value(key any) any { // This function is very hot; skip this check outside of +race builds. if sync.RaceEnabled { t.assertTaskGoroutine() } return t.contextValue(key, true /* isTaskGoroutine */) } func (t *Task) contextValue(key any, isTaskGoroutine bool) any { switch key { case CtxCanTrace: return t.CanTrace case CtxKernel: return t.k case CtxPIDNamespace: return t.tg.pidns case CtxUTSNamespace: if !isTaskGoroutine { t.mu.Lock() defer t.mu.Unlock() } utsns := t.utsns utsns.IncRef() return utsns case ipc.CtxIPCNamespace: if !isTaskGoroutine { t.mu.Lock() defer t.mu.Unlock() } ipcns := t.ipcns ipcns.IncRef() return ipcns case CtxTask: return t case auth.CtxCredentials: return t.creds.Load() case auth.CtxThreadGroupID: return int32(t.tg.ID()) case vfs.CtxRoot: if !isTaskGoroutine { t.mu.Lock() defer t.mu.Unlock() } return t.fsContext.RootDirectory() case vfs.CtxMountNamespace: if !isTaskGoroutine { t.mu.Lock() defer t.mu.Unlock() } t.mountNamespace.IncRef() return t.mountNamespace case devutil.CtxDevGoferClient: return t.k.GetDevGoferClient(t.k.ContainerName(t.containerID)) case inet.CtxStack: return t.NetworkContext() case inet.CtxNamespaceByFD: return t.NetworkNamespaceByFD case ktime.CtxRealtimeClock: return t.k.RealtimeClock() case limits.CtxLimits: return t.tg.limits case linux.CtxSignalNoInfoFunc: return func(sig linux.Signal) error { return t.SendSignal(SignalInfoNoInfo(sig, t, t)) } case pgalloc.CtxMemoryCgroupID: return t.memCgID.Load() case pgalloc.CtxMemoryFile: return t.k.mf case platform.CtxPlatform: return t.k case shm.CtxDeviceID: return t.k.sysVShmDevID case uniqueid.CtxGlobalUniqueID: return t.k.UniqueID() case uniqueid.CtxGlobalUniqueIDProvider: return t.k case uniqueid.CtxInotifyCookie: return t.k.GenerateInotifyCookie() case unimpl.CtxEvents: return t.k case cpuid.CtxFeatureSet: return t.k.featureSet default: return nil } } // fallbackContext adds a level of indirection for embedding to resolve // ambiguity for method resolution. We favor context.NoTask. type fallbackTask struct { *Task } // taskAsyncContext implements context.Context for a goroutine that performs // work on behalf of a Task, but is not the task goroutine. type taskAsyncContext struct { context.NoTask fallbackTask } // Value implements context.Context.Value. func (t *taskAsyncContext) Value(key any) any { return t.fallbackTask.contextValue(key, false /* isTaskGoroutine */) } // AsyncContext returns a context.Context representing t. The returned // context.Context is intended for use by goroutines other than t's task // goroutine; for example, signal delivery to t will not interrupt goroutines // that are blocking using the returned context.Context. func (t *Task) AsyncContext() context.Context { return &taskAsyncContext{ fallbackTask: fallbackTask{t}, } }