[Linux-kernel-mentees] Syzbot analysis, WARNING in ovl_rename (log)
bnvandana at gmail.com
Sun May 12 15:24:48 UTC 2019
This is analysis of WARNING in ovl_rename (log)
The WARN_ON is hit in ovl_rename(), when the old and new inode are same.
"1176 if (WARN_ON(olddentry->d_inode == newdentry->d_inode))"
The reproducer, mounts overlay fs with ramfs mount as upperdir and lowerdir as directory on root (ext4) which has a file(file0), the overlayfs mount now has the file0 from the lowerdir, the test then creates a hardlink (file1) to file0 and then tries to rename file0 to file1. since the hard link and the original file have same inode, the above WARN_ON is triggerd.
I was able to reproduce this, with changing c reproducer a bit to take correct mount parameters.
Below is analysis from the reproduction
none on /ovl_test/syzkaller.t9H84E/upper type ramfs (rw,relatime)
none on /ovl_test/syzkaller.t9H84E/upper/file0 type overlay (rw,relatime,lowerdir=../file1,upperdir=./file0,workdir=./wd,index=off)
vfs view of lower dir
root at test:/ovl_test/syzkaller.t9H84E/file1# ls -ali
555971 d--------- 2 root root 4096 May 12 16:22 .
555969 drwxrwxrwx 4 root root 4096 May 12 16:22 ..
533455 ---------- 1 root root 0 May 12 16:22 file0 << original file
vfs view contents of upperdir/overlayfs mount
root at test:/ovl_test/syzkaller.t9H84E/upper/file0# ls -ali
239104 d--------- 1 root root 0 May 12 16:22 .
236464 drwxr-xr-x 4 root root 0 May 12 16:22 ..
533455 ---------- 2 root root 0 May 12 16:22 file0 << inode of lowerdir
236475 ---------- 2 root root 0 May 12 16:22 file1 << hard link inode created in upper dir
but in overlayfs both file0 and file1 point to same inode
olddentry file0 000000009a223589
newdentry file1 000000009a223589
The syzbot has bisected it to
ovl: fix EIO from lookup of non-indexed upper
According to man page of rename,the expected behavior of rename if old and new are existing hard links referring to the same file, is to do nothing and return success.
Even before the above syslog bisect commit,such rename would return EIO from lookup and now it returns error ESTALE from ovl rename, both of which is wrong behavior.
The vfs_rename() has below check
if (source == target)
rename doesn't exit here because vfs sees 2 different inodes for source and target, as seen above.
But overlay fs sees both as same hence the WARN_ON.
There can be 2 possible fixes
1.whenever hard link is created for a file in lower dir, copyup the original file to upperdir before creating the link, so that both original and link inode will be same w.r.t VFS, but this might create additional inodes. OR
2.Similar to vfs_rename check, ovl_rename() can check if old and new are same inodes and return success.
Please let me know your feedback.
More information about the Linux-kernel-mentees