Skip to content

Commit d54ff32

Browse files
ayushr2gvisor-bot
authored andcommitted
gofer: Invalidate dentry if file type changes but inode number doesn't.
For some filesystems like ext4, it possible that the inode number is re-used in between unlink and file creation. Hence it is possible a file is replaced on the host filesystem with another file but the inode number remains the same. The gofer client can't detect such changes and trigger invalidation. But at least we can detect if the file type has changed and invalidate the old file. PiperOrigin-RevId: 809831715
1 parent 6448dbe commit d54ff32

File tree

2 files changed

+6
-14
lines changed

2 files changed

+6
-14
lines changed

pkg/sentry/fsimpl/gofer/directfs_inode.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,9 @@ func doRevalidationDirectfs(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
789789
}
790790

791791
// Note that synthetic dentries will always fail this comparison check.
792-
if !found || d.inode.inoKey != inoKeyFromStat(&stat) {
792+
if !found ||
793+
d.inode.inoKey != inoKeyFromStat(&stat) ||
794+
stat.Mode&unix.S_IFMT != d.inode.fileType() {
793795
d.inode.metadataMu.Unlock()
794796
if !found && d.inode.isSynthetic() {
795797
// We have a synthetic file, and no remote file has arisen to replace
@@ -802,11 +804,6 @@ func doRevalidationDirectfs(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
802804
return nil
803805
}
804806

805-
// Check that the file type has not changed.
806-
if got, want := stat.Mode&unix.S_IFMT, d.inode.fileType(); got != want {
807-
panic(fmt.Sprintf("file type of %q changed from %#o to %#o while inode key (%+v) did not change", genericDebugPathname(d.inode.fs, d), want, got, d.inode.inoKey))
808-
}
809-
810807
// The file at this path hasn't changed. Just update cached metadata.
811808
d.inode.impl.(*directfsInode).updateMetadataFromStatLocked(&stat) // +checklocksforce: i.metadataMu is locked above.
812809
d.inode.metadataMu.Unlock()

pkg/sentry/fsimpl/gofer/lisafs_inode.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,9 @@ func doRevalidationLisafs(ctx context.Context, vfsObj *vfs.VirtualFilesystem, st
709709
lastUnlockedDentry = i
710710

711711
// Note that synthetic dentries will always fail this comparison check.
712-
if !found || d.inode.inoKey != inoKeyFromStatx(&stats[i]) {
712+
if !found ||
713+
d.inode.inoKey != inoKeyFromStatx(&stats[i]) ||
714+
(stats[i].Mask&linux.STATX_TYPE != 0 && uint32(stats[i].Mode&linux.FileTypeMask) != d.inode.fileType()) {
713715
d.inode.metadataMu.Unlock()
714716
if !found && d.inode.isSynthetic() {
715717
// We have a synthetic file, and no remote file has arisen to replace
@@ -722,13 +724,6 @@ func doRevalidationLisafs(ctx context.Context, vfsObj *vfs.VirtualFilesystem, st
722724
return nil
723725
}
724726

725-
// Check that the file type has not changed.
726-
if stats[i].Mask&linux.STATX_TYPE != 0 {
727-
if got, want := stats[i].Mode&linux.FileTypeMask, d.inode.fileType(); uint32(got) != want {
728-
panic(fmt.Sprintf("file type of %q changed from %#o to %#o while inode key (%+v) did not change", genericDebugPathname(d.inode.fs, d), want, got, d.inode.inoKey))
729-
}
730-
}
731-
732727
// The file at this path hasn't changed. Just update cached metadata.
733728
d.inode.impl.(*lisafsInode).updateMetadataFromStatxLocked(&stats[i]) // +checklocksforce: see above.
734729
d.inode.metadataMu.Unlock()

0 commit comments

Comments
 (0)