| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Sun, 6 May 2018 12:15:20 -0400 |
| Subject: affs_lookup(): close a race with affs_remove_link() |
| |
| commit 30da870ce4a4e007c901858a96e9e394a1daa74a upstream. |
| |
| we unlock the directory hash too early - if we are looking at secondary |
| link and primary (in another directory) gets removed just as we unlock, |
| we could have the old primary moved in place of the secondary, leaving |
| us to look into freed entry (and leaving our dentry with ->d_fsdata |
| pointing to a freed entry). |
| |
| Acked-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/affs/namei.c | 10 +++++++--- |
| 1 file changed, 7 insertions(+), 3 deletions(-) |
| |
| --- a/fs/affs/namei.c |
| +++ b/fs/affs/namei.c |
| @@ -224,9 +224,10 @@ affs_lookup(struct inode *dir, struct de |
| |
| affs_lock_dir(dir); |
| bh = affs_find_entry(dir, dentry); |
| - affs_unlock_dir(dir); |
| - if (IS_ERR(bh)) |
| + if (IS_ERR(bh)) { |
| + affs_unlock_dir(dir); |
| return ERR_CAST(bh); |
| + } |
| if (bh) { |
| u32 ino = bh->b_blocknr; |
| |
| @@ -240,10 +241,13 @@ affs_lookup(struct inode *dir, struct de |
| } |
| affs_brelse(bh); |
| inode = affs_iget(sb, ino); |
| - if (IS_ERR(inode)) |
| + if (IS_ERR(inode)) { |
| + affs_unlock_dir(dir); |
| return ERR_CAST(inode); |
| + } |
| } |
| d_add(dentry, inode); |
| + affs_unlock_dir(dir); |
| return NULL; |
| } |
| |