]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hostfs: fix dev_t handling
authorJohannes Berg <johannes.berg@intel.com>
Tue, 2 Jul 2024 07:24:41 +0000 (09:24 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 3 Jul 2024 10:23:50 +0000 (12:23 +0200)
dev_t is a kernel type and may have different definitions
in kernel and userspace. On 32-bit x86 this currently makes
the stat structure being 4 bytes longer in the user code,
causing stack corruption.

However, this is (potentially) not the only problem, since
dev_t is a different type on user/kernel side, so we don't
know that the major/minor encoding isn't also different.
Decode/encode it instead to address both problems.

Cc: stable@vger.kernel.org
Fixes: 74ce793bcbde ("hostfs: Fix ephemeral inodes")
Link: https://patch.msgid.link/20240702092440.acc960585dd5.Id0767e12f562a69c6cd3c3262dc3d765db350cf6@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
fs/hostfs/hostfs.h
fs/hostfs/hostfs_kern.c
fs/hostfs/hostfs_user.c

index 0239e3af394551b216ed8e29e57a3f40b3a95402..8b39c15c408ccd8562768ad7effe43f1a3de3b42 100644 (file)
@@ -63,9 +63,10 @@ struct hostfs_stat {
        struct hostfs_timespec atime, mtime, ctime;
        unsigned int blksize;
        unsigned long long blocks;
-       unsigned int maj;
-       unsigned int min;
-       dev_t dev;
+       struct {
+               unsigned int maj;
+               unsigned int min;
+       } rdev, dev;
 };
 
 extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
index a73d27c4dd583becba8b81ce9047113b53f5ea83..2c4d503a62e023cd095a66ef727b53e0d9f623ca 100644 (file)
@@ -530,10 +530,11 @@ static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st)
 static int hostfs_inode_set(struct inode *ino, void *data)
 {
        struct hostfs_stat *st = data;
-       dev_t rdev;
+       dev_t dev, rdev;
 
        /* Reencode maj and min with the kernel encoding.*/
-       rdev = MKDEV(st->maj, st->min);
+       rdev = MKDEV(st->rdev.maj, st->rdev.min);
+       dev = MKDEV(st->dev.maj, st->dev.min);
 
        switch (st->mode & S_IFMT) {
        case S_IFLNK:
@@ -559,7 +560,7 @@ static int hostfs_inode_set(struct inode *ino, void *data)
                return -EIO;
        }
 
-       HOSTFS_I(ino)->dev = st->dev;
+       HOSTFS_I(ino)->dev = dev;
        ino->i_ino = st->ino;
        ino->i_mode = st->mode;
        return hostfs_inode_update(ino, st);
@@ -568,8 +569,9 @@ static int hostfs_inode_set(struct inode *ino, void *data)
 static int hostfs_inode_test(struct inode *inode, void *data)
 {
        const struct hostfs_stat *st = data;
+       dev_t dev = MKDEV(st->dev.maj, st->dev.min);
 
-       return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev;
+       return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == dev;
 }
 
 static struct inode *hostfs_iget(struct super_block *sb, char *name)
index 840619e39a1a69d254d88110579d236615b0ad38..97e9c40a944883a93d10fea4c6a812c7416b9f41 100644 (file)
@@ -34,9 +34,10 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
        p->mtime.tv_nsec = 0;
        p->blksize = buf->st_blksize;
        p->blocks = buf->st_blocks;
-       p->maj = os_major(buf->st_rdev);
-       p->min = os_minor(buf->st_rdev);
-       p->dev = buf->st_dev;
+       p->rdev.maj = os_major(buf->st_rdev);
+       p->rdev.min = os_minor(buf->st_rdev);
+       p->dev.maj = os_major(buf->st_dev);
+       p->dev.min = os_minor(buf->st_dev);
 }
 
 int stat_file(const char *path, struct hostfs_stat *p, int fd)