A lookup of ".." with SPEC_DOTDOT and LOOKUP releases the directory
only when it succeeds; its callers, checkpath and ancestors in
diskfs_rename_dir, release it themselves otherwise. diskfs_lookup_hard
released it before diskfs_cached_lookup of the parent, so when that
failed the directory was unlocked and dereferenced twice.
Hold a reference across the lookup, and give the directory back locked
when it fails.
---
ext2fs/dir.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/ext2fs/dir.c b/ext2fs/dir.c
index 09f5a7225..583232f36 100644
--- a/ext2fs/dir.c
+++ b/ext2fs/dir.c
@@ -316,10 +316,17 @@ diskfs_lookup_hard (struct node *dp, const char *name,
lookup_flags_t l_flags,
else if (type == LOOKUP)
{
+ /* Hold DP until the lookup succeeds: on failure the caller
+ still has it, locked. */
+ diskfs_nref (dp);
diskfs_nput (dp);
err = diskfs_cached_lookup (inum, &np);
if (err)
- goto out;
+ {
+ pthread_mutex_lock (&dp->lock);
+ goto out;
+ }
+ diskfs_nrele (dp);
}
else
assert_backtrace (0);
--
2.56.0