Skip to content

Commit 267ed02

Browse files
committed
hostfs: fix dev_t handling
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: [email protected] Fixes: 74ce793 ("hostfs: Fix ephemeral inodes") Link: https://patch.msgid.link/20240702092440.acc960585dd5.Id0767e12f562a69c6cd3c3262dc3d765db350cf6@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 53585f9 commit 267ed02

File tree

3 files changed

+14
-10
lines changed

3 files changed

+14
-10
lines changed

fs/hostfs/hostfs.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ struct hostfs_stat {
6363
struct hostfs_timespec atime, mtime, ctime;
6464
unsigned int blksize;
6565
unsigned long long blocks;
66-
unsigned int maj;
67-
unsigned int min;
68-
dev_t dev;
66+
struct {
67+
unsigned int maj;
68+
unsigned int min;
69+
} rdev, dev;
6970
};
7071

7172
extern int stat_file(const char *path, struct hostfs_stat *p, int fd);

fs/hostfs/hostfs_kern.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,11 @@ static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st)
530530
static int hostfs_inode_set(struct inode *ino, void *data)
531531
{
532532
struct hostfs_stat *st = data;
533-
dev_t rdev;
533+
dev_t dev, rdev;
534534

535535
/* Reencode maj and min with the kernel encoding.*/
536-
rdev = MKDEV(st->maj, st->min);
536+
rdev = MKDEV(st->rdev.maj, st->rdev.min);
537+
dev = MKDEV(st->dev.maj, st->dev.min);
537538

538539
switch (st->mode & S_IFMT) {
539540
case S_IFLNK:
@@ -559,7 +560,7 @@ static int hostfs_inode_set(struct inode *ino, void *data)
559560
return -EIO;
560561
}
561562

562-
HOSTFS_I(ino)->dev = st->dev;
563+
HOSTFS_I(ino)->dev = dev;
563564
ino->i_ino = st->ino;
564565
ino->i_mode = st->mode;
565566
return hostfs_inode_update(ino, st);
@@ -568,8 +569,9 @@ static int hostfs_inode_set(struct inode *ino, void *data)
568569
static int hostfs_inode_test(struct inode *inode, void *data)
569570
{
570571
const struct hostfs_stat *st = data;
572+
dev_t dev = MKDEV(st->dev.maj, st->dev.min);
571573

572-
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev;
574+
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == dev;
573575
}
574576

575577
static struct inode *hostfs_iget(struct super_block *sb, char *name)

fs/hostfs/hostfs_user.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
3434
p->mtime.tv_nsec = 0;
3535
p->blksize = buf->st_blksize;
3636
p->blocks = buf->st_blocks;
37-
p->maj = os_major(buf->st_rdev);
38-
p->min = os_minor(buf->st_rdev);
39-
p->dev = buf->st_dev;
37+
p->rdev.maj = os_major(buf->st_rdev);
38+
p->rdev.min = os_minor(buf->st_rdev);
39+
p->dev.maj = os_major(buf->st_dev);
40+
p->dev.min = os_minor(buf->st_dev);
4041
}
4142

4243
int stat_file(const char *path, struct hostfs_stat *p, int fd)

0 commit comments

Comments
 (0)