gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/contexttest/contexttest.go (about) 1 // Copyright 2018 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 contexttest builds a test context.Context. 16 package contexttest 17 18 import ( 19 "os" 20 "testing" 21 "time" 22 23 "gvisor.dev/gvisor/pkg/atomicbitops" 24 "gvisor.dev/gvisor/pkg/context" 25 "gvisor.dev/gvisor/pkg/memutil" 26 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 27 ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time" 28 "gvisor.dev/gvisor/pkg/sentry/limits" 29 "gvisor.dev/gvisor/pkg/sentry/pgalloc" 30 "gvisor.dev/gvisor/pkg/sentry/platform" 31 "gvisor.dev/gvisor/pkg/sentry/platform/ptrace" 32 "gvisor.dev/gvisor/pkg/sentry/uniqueid" 33 ) 34 35 // Context returns a Context that may be used in tests. Uses ptrace as the 36 // platform.Platform. 37 // 38 // Note that some filesystems may require a minimal kernel for testing, which 39 // this test context does not provide. For such tests, see kernel/contexttest. 40 func Context(tb testing.TB) context.Context { 41 const memfileName = "contexttest-memory" 42 memfd, err := memutil.CreateMemFD(memfileName, 0) 43 if err != nil { 44 tb.Fatalf("error creating application memory file: %v", err) 45 } 46 memfile := os.NewFile(uintptr(memfd), memfileName) 47 mf, err := pgalloc.NewMemoryFile(memfile, pgalloc.MemoryFileOpts{}) 48 if err != nil { 49 memfile.Close() 50 tb.Fatalf("error creating pgalloc.MemoryFile: %v", err) 51 } 52 p, err := ptrace.New() 53 if err != nil { 54 tb.Fatal(err) 55 } 56 // Test usage of context.Background is fine. 57 return &TestContext{ 58 Context: context.Background(), 59 l: limits.NewLimitSet(), 60 mf: mf, 61 platform: p, 62 creds: auth.NewAnonymousCredentials(), 63 otherValues: make(map[any]any), 64 } 65 } 66 67 // TestContext represents a context with minimal functionality suitable for 68 // running tests. 69 type TestContext struct { 70 context.Context 71 l *limits.LimitSet 72 mf *pgalloc.MemoryFile 73 platform platform.Platform 74 creds *auth.Credentials 75 otherValues map[any]any 76 } 77 78 // globalUniqueID tracks incremental unique identifiers for tests. 79 var globalUniqueID atomicbitops.Uint64 80 81 // globalUniqueIDProvider implements unix.UniqueIDProvider. 82 type globalUniqueIDProvider struct{} 83 84 // UniqueID implements unix.UniqueIDProvider.UniqueID. 85 func (*globalUniqueIDProvider) UniqueID() uint64 { 86 return globalUniqueID.Add(1) 87 } 88 89 // lastInotifyCookie is a monotonically increasing counter for generating unique 90 // inotify cookies. 91 var lastInotifyCookie atomicbitops.Uint32 92 93 // hostClock implements ktime.Clock. 94 type hostClock struct { 95 ktime.WallRateClock 96 ktime.NoClockEvents 97 } 98 99 // Now implements ktime.Clock.Now. 100 func (*hostClock) Now() ktime.Time { 101 return ktime.FromNanoseconds(time.Now().UnixNano()) 102 } 103 104 // RegisterValue registers additional values with this test context. Useful for 105 // providing values from external packages that contexttest can't depend on. 106 func (t *TestContext) RegisterValue(key, value any) { 107 t.otherValues[key] = value 108 } 109 110 // Value implements context.Context. 111 func (t *TestContext) Value(key any) any { 112 switch key { 113 case auth.CtxCredentials: 114 return t.creds 115 case limits.CtxLimits: 116 return t.l 117 case pgalloc.CtxMemoryFile: 118 return t.mf 119 case platform.CtxPlatform: 120 return t.platform 121 case uniqueid.CtxGlobalUniqueID: 122 return (*globalUniqueIDProvider).UniqueID(nil) 123 case uniqueid.CtxGlobalUniqueIDProvider: 124 return &globalUniqueIDProvider{} 125 case uniqueid.CtxInotifyCookie: 126 return lastInotifyCookie.Add(1) 127 case ktime.CtxRealtimeClock: 128 return &hostClock{} 129 default: 130 if val, ok := t.otherValues[key]; ok { 131 return val 132 } 133 return t.Context.Value(key) 134 } 135 } 136 137 // RootContext returns a Context that may be used in tests that need root 138 // credentials. Uses ptrace as the platform.Platform. 139 func RootContext(tb testing.TB) context.Context { 140 return auth.ContextWithCredentials(Context(tb), auth.NewRootCredentials(auth.NewRootUserNamespace())) 141 } 142 143 // WithLimitSet returns a copy of ctx carrying l. 144 func WithLimitSet(ctx context.Context, l *limits.LimitSet) context.Context { 145 return limitContext{ctx, l} 146 } 147 148 type limitContext struct { 149 context.Context 150 l *limits.LimitSet 151 } 152 153 // Value implements context.Context. 154 func (lc limitContext) Value(key any) any { 155 switch key { 156 case limits.CtxLimits: 157 return lc.l 158 default: 159 return lc.Context.Value(key) 160 } 161 }