]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
UBUNTU: SAUCE: shiftfs: prevent lower dentries from going negative during unlink
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 17 Jan 2020 15:17:06 +0000 (16:17 +0100)
committerAndrea Righi <andrea.righi@canonical.com>
Thu, 9 Mar 2023 14:57:20 +0000 (15:57 +0100)
BugLink: https://bugs.launchpad.net/bugs/1860041
All non-special files (For shiftfs this only includes fifos and - for
this case - unix sockets - since we don't allow character and block
devices to be created.) go through shiftfs_open() and have their dentry
pinned through this codepath preventing it from going negative. But
fifos don't use the shiftfs fops but rather use the pipefifo_fops which
means they do not go through shiftfs_open() and thus don't have their
dentry pinned that way. Thus, the lower dentries for such files can go
negative on unlink causing segfaults. The following C program can be
used to reproduce the crash:

 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdlib.h>

 int main(int argc, char *argv[])
 {
        struct stat stat;

        unlink("./bbb");

        int ret = mknod("./bbb", S_IFIFO|0666, 0);
        if (ret < 0)
                exit(1);

        int fd = open("./bbb", O_RDWR);
        if (fd < 0)
                exit(2);

        if (unlink("./bbb"))
                exit(4);

        fstat(fd, &stat);

        return 0;
 }

Similar to ecryptfs we need to dget() the lower dentry before calling
vfs_unlink() on it and dput() it afterwards.

Acked-by: Stefan Bader <stefan.bader@canonical.com>
Link: https://travis-ci.community/t/arm64-ppc64le-segfaults/6158/3
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
fs/shiftfs.c

index 04fba4689eb6512c5d155c8a74258c5f7728fabf..3623d02b061eae0c04a064293f88f612103a9d41 100644 (file)
@@ -583,6 +583,7 @@ static int shiftfs_rm(struct inode *dir, struct dentry *dentry, bool rmdir)
        int err;
        const struct cred *oldcred;
 
+       dget(lowerd);
        oldcred = shiftfs_override_creds(dentry->d_sb);
        inode_lock_nested(loweri, I_MUTEX_PARENT);
        if (rmdir)
@@ -602,6 +603,7 @@ static int shiftfs_rm(struct inode *dir, struct dentry *dentry, bool rmdir)
        inode_unlock(loweri);
 
        shiftfs_copyattr(loweri, dir);
+       dput(lowerd);
 
        return err;
 }