If the directory is corrupted and the number of nlinks is less than 2 (valid nlinks have at least 2), then when the directory is deleted, the minix_rmdir will try to reduce the nlinks(unsigned int) to a negative value.
Make nlinks validity check for directories.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Andrey Kriulin kitotavrik.s@gmail.com --- v3: Move nlinks validaty check to minix_rmdir and minix_rename per Jan Kara jack@suse.cz request. v2: Move nlinks validaty check to V[12]_minix_iget() per Jan Kara jack@suse.cz request. Change return error code to EUCLEAN. Don't block directory in r/o mode per Al Viro viro@zeniv.linux.org.uk request.
fs/minix/namei.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 8938536d8d3c..5a1e5f8ef443 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -161,8 +161,12 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry) static int minix_rmdir(struct inode * dir, struct dentry *dentry) { struct inode * inode = d_inode(dentry); - int err = -ENOTEMPTY; + int err = -EUCLEAN;
+ if (inode->i_nlink < 2) + return err; + + err = -ENOTEMPTY; if (minix_empty_dir(inode)) { err = minix_unlink(dir, dentry); if (!err) { @@ -235,6 +239,10 @@ static int minix_rename(struct mnt_idmap *idmap, mark_inode_dirty(old_inode);
if (dir_de) { + if (old_dir->i_nlink <= 2) { + err = -EUCLEAN; + goto out_dir; + } err = minix_set_link(dir_de, dir_folio, new_dir); if (!err) inode_dec_link_count(old_dir);
On Thu 15-05-25 20:54:57, Andrey Kriulin wrote:
If the directory is corrupted and the number of nlinks is less than 2 (valid nlinks have at least 2), then when the directory is deleted, the minix_rmdir will try to reduce the nlinks(unsigned int) to a negative value.
Make nlinks validity check for directories.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Andrey Kriulin kitotavrik.s@gmail.com
This patch is mostly fine (see just one nit below).
v3: Move nlinks validaty check to minix_rmdir and minix_rename per Jan Kara jack@suse.cz request. v2: Move nlinks validaty check to V[12]_minix_iget() per Jan Kara jack@suse.cz request. Change return error code to EUCLEAN. Don't block directory in r/o mode per Al Viro viro@zeniv.linux.org.uk request.
fs/minix/namei.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 8938536d8d3c..5a1e5f8ef443 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -161,8 +161,12 @@ static int minix_unlink(struct inode * dir, struct dentry *dentry) static int minix_rmdir(struct inode * dir, struct dentry *dentry) { struct inode * inode = d_inode(dentry);
- int err = -ENOTEMPTY;
- int err = -EUCLEAN;
- if (inode->i_nlink < 2)
This should be <= 2 as well?
Honza
return err;
- err = -ENOTEMPTY; if (minix_empty_dir(inode)) { err = minix_unlink(dir, dentry); if (!err) {
@@ -235,6 +239,10 @@ static int minix_rename(struct mnt_idmap *idmap, mark_inode_dirty(old_inode); if (dir_de) {
if (old_dir->i_nlink <= 2) {
err = -EUCLEAN;
goto out_dir;
err = minix_set_link(dir_de, dir_folio, new_dir); if (!err) inode_dec_link_count(old_dir);}
-- 2.47.2
No, because the live directory has nlinks = 2 when deleted. But if I understand correctly, it's worth adding a check for parent directory(dir->i_nlinks <= 2)
linux-stable-mirror@lists.linaro.org