summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/kernfs/filesystem.go
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2021-05-03 13:47:45 -0700
committergVisor bot <gvisor-bot@google.com>2021-05-03 13:50:37 -0700
commit1947c873423cabcaf5e67b667542421ade7414ff (patch)
treeb54dd4f68aa20b95367594b8941fcca4cb766636 /pkg/sentry/fsimpl/kernfs/filesystem.go
parent7cafac9f42a8355e7192b57fcc8d41e31d836c53 (diff)
Fix deadlock in /proc/[pid]/fd/[num]
In order to resolve path names, fsSymlink.Readlink() may need to reenter kernfs. Change the code so that kernfs.Inode.Readlink() is called without locks and document the new contract. PiperOrigin-RevId: 371770222
Diffstat (limited to 'pkg/sentry/fsimpl/kernfs/filesystem.go')
-rw-r--r--pkg/sentry/fsimpl/kernfs/filesystem.go12
1 files changed, 10 insertions, 2 deletions
diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go
index badca4d9f..f50b0fb08 100644
--- a/pkg/sentry/fsimpl/kernfs/filesystem.go
+++ b/pkg/sentry/fsimpl/kernfs/filesystem.go
@@ -612,16 +612,24 @@ afterTrailingSymlink:
// ReadlinkAt implements vfs.FilesystemImpl.ReadlinkAt.
func (fs *Filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (string, error) {
- fs.mu.RLock()
defer fs.processDeferredDecRefs(ctx)
- defer fs.mu.RUnlock()
+
+ fs.mu.RLock()
d, err := fs.walkExistingLocked(ctx, rp)
if err != nil {
+ fs.mu.RUnlock()
return "", err
}
if !d.isSymlink() {
+ fs.mu.RUnlock()
return "", syserror.EINVAL
}
+
+ // Inode.Readlink() cannot be called holding fs locks.
+ d.IncRef()
+ defer d.DecRef(ctx)
+ fs.mu.RUnlock()
+
return d.inode.Readlink(ctx, rp.Mount())
}