hostfs: fix dev_t handling
commit 267ed02c2121b75e0eaaa338240453b576039e4a upstream.
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: 74ce793bcb
("hostfs: Fix ephemeral inodes")
Link: https://patch.msgid.link/20240702092440.acc960585dd5.Id0767e12f562a69c6cd3c3262dc3d765db350cf6@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b579ea3516
commit
ea4f779462
|
@ -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);
|
||||
|
|
|
@ -526,10 +526,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:
|
||||
|
@ -555,7 +556,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);
|
||||
|
@ -564,8 +565,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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue