Skip to content

Commit 3eeac33

Browse files
Darrick J. Wonggregkh
authored andcommitted
xfs: allow unlinked symlinks and dirs with zero size
commit 1ec9307 upstream. For a very very long time, inode inactivation has set the inode size to zero before unmapping the extents associated with the data fork. Unfortunately, commit 3c6f46e changed the inode verifier to prohibit zero-length symlinks and directories. If an inode happens to get logged in this state and the system crashes before freeing the inode, log recovery will also fail on the broken inode. Therefore, allow zero-size symlinks and directories as long as the link count is zero; nobody will be able to open these files by handle so there isn't any risk of data exposure. Fixes: 3c6f46e ("xfs: sanity check directory inode di_size") Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Chandan Babu R <[email protected]> Signed-off-by: Catherine Hoang <[email protected]> Acked-by: Darrick J. Wong <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2bc2d49 commit 3eeac33

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,13 @@ xfs_dinode_verify_fork(
371371
/*
372372
* A directory small enough to fit in the inode must be stored
373373
* in local format. The directory sf <-> extents conversion
374-
* code updates the directory size accordingly.
374+
* code updates the directory size accordingly. Directories
375+
* being truncated have zero size and are not subject to this
376+
* check.
375377
*/
376378
if (S_ISDIR(mode)) {
377-
if (be64_to_cpu(dip->di_size) <= fork_size &&
379+
if (dip->di_size &&
380+
be64_to_cpu(dip->di_size) <= fork_size &&
378381
fork_format != XFS_DINODE_FMT_LOCAL)
379382
return __this_address;
380383
}
@@ -512,9 +515,19 @@ xfs_dinode_verify(
512515
if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)
513516
return __this_address;
514517

515-
/* No zero-length symlinks/dirs. */
516-
if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
517-
return __this_address;
518+
/*
519+
* No zero-length symlinks/dirs unless they're unlinked and hence being
520+
* inactivated.
521+
*/
522+
if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) {
523+
if (dip->di_version > 1) {
524+
if (dip->di_nlink)
525+
return __this_address;
526+
} else {
527+
if (dip->di_onlink)
528+
return __this_address;
529+
}
530+
}
518531

519532
fa = xfs_dinode_verify_nrext64(mp, dip);
520533
if (fa)

0 commit comments

Comments
 (0)