github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/kernel/fs_context.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 kernel 16 17 import ( 18 "fmt" 19 20 "github.com/MerlinKodo/gvisor/pkg/context" 21 "github.com/MerlinKodo/gvisor/pkg/sentry/vfs" 22 "github.com/MerlinKodo/gvisor/pkg/sync" 23 ) 24 25 // FSContext contains filesystem context. 26 // 27 // This includes umask and working directory. 28 // 29 // +stateify savable 30 type FSContext struct { 31 FSContextRefs 32 33 // mu protects below. 34 mu sync.Mutex `state:"nosave"` 35 36 // root is the filesystem root. 37 root vfs.VirtualDentry 38 39 // cwd is the current working directory. 40 cwd vfs.VirtualDentry 41 42 // umask is the current file mode creation mask. When a thread using this 43 // context invokes a syscall that creates a file, bits set in umask are 44 // removed from the permissions that the file is created with. 45 umask uint 46 } 47 48 // NewFSContext returns a new filesystem context. 49 func NewFSContext(root, cwd vfs.VirtualDentry, umask uint) *FSContext { 50 root.IncRef() 51 cwd.IncRef() 52 f := FSContext{ 53 root: root, 54 cwd: cwd, 55 umask: umask, 56 } 57 f.InitRefs() 58 return &f 59 } 60 61 // DecRef implements RefCounter.DecRef. 62 // 63 // When f reaches zero references, DecRef will be called on both root and cwd 64 // Dirents. 65 // 66 // Note that there may still be calls to WorkingDirectory() or RootDirectory() 67 // (that return nil). This is because valid references may still be held via 68 // proc files or other mechanisms. 69 func (f *FSContext) DecRef(ctx context.Context) { 70 f.FSContextRefs.DecRef(func() { 71 // Hold f.mu so that we don't race with RootDirectory() and 72 // WorkingDirectory(). 73 f.mu.Lock() 74 defer f.mu.Unlock() 75 76 f.root.DecRef(ctx) 77 f.root = vfs.VirtualDentry{} 78 f.cwd.DecRef(ctx) 79 f.cwd = vfs.VirtualDentry{} 80 }) 81 } 82 83 // Fork forks this FSContext. 84 // 85 // This is not a valid call after f is destroyed. 86 func (f *FSContext) Fork() *FSContext { 87 f.mu.Lock() 88 defer f.mu.Unlock() 89 90 if !f.cwd.Ok() { 91 panic("FSContext.Fork() called after destroy") 92 } 93 f.cwd.IncRef() 94 f.root.IncRef() 95 96 ctx := &FSContext{ 97 cwd: f.cwd, 98 root: f.root, 99 umask: f.umask, 100 } 101 ctx.InitRefs() 102 return ctx 103 } 104 105 // WorkingDirectory returns the current working directory. 106 // 107 // This will return an empty vfs.VirtualDentry if called after f is 108 // destroyed, otherwise it will return a Dirent with a reference taken. 109 func (f *FSContext) WorkingDirectory() vfs.VirtualDentry { 110 f.mu.Lock() 111 defer f.mu.Unlock() 112 113 if f.cwd.Ok() { 114 f.cwd.IncRef() 115 } 116 return f.cwd 117 } 118 119 // SetWorkingDirectory sets the current working directory. 120 // This will take an extra reference on the VirtualDentry. 121 // 122 // This is not a valid call after f is destroyed. 123 func (f *FSContext) SetWorkingDirectory(ctx context.Context, d vfs.VirtualDentry) { 124 f.mu.Lock() 125 defer f.mu.Unlock() 126 127 if !f.cwd.Ok() { 128 panic(fmt.Sprintf("FSContext.SetWorkingDirectory(%v)) called after destroy", d)) 129 } 130 131 old := f.cwd 132 f.cwd = d 133 d.IncRef() 134 old.DecRef(ctx) 135 } 136 137 // RootDirectory returns the current filesystem root. 138 // 139 // This will return an empty vfs.VirtualDentry if called after f is 140 // destroyed, otherwise it will return a Dirent with a reference taken. 141 func (f *FSContext) RootDirectory() vfs.VirtualDentry { 142 f.mu.Lock() 143 defer f.mu.Unlock() 144 145 if f.root.Ok() { 146 f.root.IncRef() 147 } 148 return f.root 149 } 150 151 // SetRootDirectory sets the root directory. It takes a reference on vd. 152 // 153 // This is not a valid call after f is destroyed. 154 func (f *FSContext) SetRootDirectory(ctx context.Context, vd vfs.VirtualDentry) { 155 if !vd.Ok() { 156 panic("FSContext.SetRootDirectory called with zero-value VirtualDentry") 157 } 158 159 f.mu.Lock() 160 161 if !f.root.Ok() { 162 f.mu.Unlock() 163 panic(fmt.Sprintf("FSContext.SetRootDirectory(%v)) called after destroy", vd)) 164 } 165 166 old := f.root 167 vd.IncRef() 168 f.root = vd 169 f.mu.Unlock() 170 old.DecRef(ctx) 171 } 172 173 // Umask returns the current umask. 174 func (f *FSContext) Umask() uint { 175 f.mu.Lock() 176 defer f.mu.Unlock() 177 return f.umask 178 } 179 180 // SwapUmask atomically sets the current umask and returns the old umask. 181 func (f *FSContext) SwapUmask(mask uint) uint { 182 f.mu.Lock() 183 defer f.mu.Unlock() 184 old := f.umask 185 f.umask = mask 186 return old 187 }