Skip to content

Commit d71a9b3

Browse files
nixprimegvisor-bot
authored andcommitted
gofer: fix ref drop when racily-unlinked synthetic file is invalidated
PiperOrigin-RevId: 732340885
1 parent b4cc9c5 commit d71a9b3

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

pkg/sentry/fsimpl/gofer/filesystem.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,12 @@ func (fs *filesystem) unlinkAt(ctx context.Context, rp *vfs.ResolvingPath, dir b
714714
if child != nil {
715715
toDecRef = vfsObj.CommitDeleteDentry(ctx, &child.vfsd) // +checklocksforce: see above.
716716
child.setDeleted()
717+
// If an extra reference is held on child as described by the comment
718+
// for dentry.refs, drop that reference now. We can't race with another
719+
// fs.unlinkAt() or invalidation since parent.opMu has been locked for
720+
// writing since before we obtained child, and we can't race with
721+
// fs.RenameAt() since fs.renameMu has been locked since before we
722+
// obtained child.
717723
if child.isSynthetic() {
718724
parent.syntheticChildren--
719725
child.decRefNoCaching()
@@ -1507,6 +1513,10 @@ func (fs *filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, oldPa
15071513
toDecRef = vfsObj.CommitRenameReplaceDentry(ctx, &renamed.vfsd, replacedVFSD)
15081514
if replaced != nil {
15091515
replaced.setDeleted()
1516+
// If an extra reference is held on replaced as described by the
1517+
// comment for dentry.refs, drop that reference now. We can't race with
1518+
// fs.unlinkAt() or invalidation since fs.renameMu has been locked for
1519+
// writing since before we obtained replaced.
15101520
if replaced.isSynthetic() {
15111521
newParent.syntheticChildren--
15121522
replaced.decRefNoCaching()

pkg/sentry/fsimpl/gofer/revalidate.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -198,29 +198,30 @@ func (fs *filesystem) revalidateStep(ctx context.Context, rp resolvingPath, d *d
198198
// Precondition: fs.renameMu must be locked.
199199
func (d *dentry) invalidate(ctx context.Context, vfsObj *vfs.VirtualFilesystem, ds **[]*dentry) {
200200
// Remove d from its parent.
201-
func() {
201+
removed := func() bool {
202202
parent := d.parent.Load()
203203
parent.opMu.RLock()
204204
defer parent.opMu.RUnlock()
205205
parent.childrenMu.Lock()
206206
defer parent.childrenMu.Unlock()
207207

208-
if d.isSynthetic() {
209-
// Normally we don't mark invalidated dentries as deleted since
210-
// they may still exist (but at a different path), and also for
211-
// consistency with Linux. However, synthetic files are guaranteed
212-
// to become unreachable if their dentries are invalidated, so
213-
// treat their invalidation as deletion.
214-
d.deleteSynthetic(parent, ds)
215-
}
216-
217208
// Since the opMu was just reacquired above, re-check that the
218209
// parent's child with this name is still the same. Do not touch it if
219210
// it has been replaced with a different one.
220211
if child := parent.children[d.name]; child == d {
221212
// Invalidate dentry so it gets reloaded next time it's accessed.
222213
delete(parent.children, d.name)
214+
if d.isSynthetic() {
215+
// Normally we don't mark invalidated dentries as deleted since
216+
// they may still exist (but at a different path), and also for
217+
// consistency with Linux. However, synthetic files are
218+
// guaranteed to become unreachable if their dentries are
219+
// invalidated, so treat their invalidation as deletion.
220+
d.deleteSynthetic(parent, ds)
221+
}
222+
return true
223223
}
224+
return false
224225
}()
225226

226227
// Invalidate d and its descendants.
@@ -239,7 +240,14 @@ func (d *dentry) invalidate(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
239240
rc.DecRef(ctx)
240241
}
241242
d.decRefNoCaching()
242-
if d.isSynthetic() || d.endpoint != nil {
243+
244+
// If an extra reference is held on d as described by the comment for
245+
// dentry.refs, and d hasn't been racily removed by
246+
// filesystem.unlinkAt() or another revalidation, drop that reference
247+
// now. (The same would apply to racy replacement by
248+
// filesystem.RenameAt(), but we can't race with rename since renameMu
249+
// has been locked since entering filesystem.revalidatePath().)
250+
if removed && (d.isSynthetic() || d.endpoint != nil) {
243251
d.decRefNoCaching()
244252
}
245253

0 commit comments

Comments
 (0)