Skip to content

Commit 0bc754d

Browse files
benzeajmberg-intel
authored andcommitted
um: hostfs: avoid issues on inode number reuse by host
Some file systems (e.g. ext4) may reuse inode numbers once the inode is not in use anymore. Usually hostfs will keep an FD open for each inode, but this is not always the case. In the case of sockets, this cannot even be done properly. As such, the following sequence of events was possible: * application creates and deletes a socket * hostfs creates/deletes the socket on the host * inode is still in the hostfs cache * hostfs creates a new file * ext4 on the outside reuses the inode number * hostfs finds the socket inode for the newly created file * application receives -ENXIO when opening the file As mentioned, this can only happen if the deleted file is a special file that is never opened on the host (i.e. no .open fop). As such, to prevent issues, it is sufficient to check that the inode has the expected type. That said, also add a check for the inode birth time, just to be on the safe side. Fixes: 74ce793 ("hostfs: Fix ephemeral inodes") Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Reviewed-by: Mickaël Salaün <mic@digikod.net> Tested-by: Mickaël Salaün <mic@digikod.net> Link: https://patch.msgid.link/20250214092822.1241575-1-benjamin@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 1fc350e commit 0bc754d

File tree

3 files changed

+41
-27
lines changed

3 files changed

+41
-27
lines changed

fs/hostfs/hostfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct hostfs_stat {
6060
unsigned int uid;
6161
unsigned int gid;
6262
unsigned long long size;
63-
struct hostfs_timespec atime, mtime, ctime;
63+
struct hostfs_timespec atime, mtime, ctime, btime;
6464
unsigned int blksize;
6565
unsigned long long blocks;
6666
struct {

fs/hostfs/hostfs_kern.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct hostfs_inode_info {
3333
struct inode vfs_inode;
3434
struct mutex open_mutex;
3535
dev_t dev;
36+
struct hostfs_timespec btime;
3637
};
3738

3839
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
@@ -547,6 +548,7 @@ static int hostfs_inode_set(struct inode *ino, void *data)
547548
}
548549

549550
HOSTFS_I(ino)->dev = dev;
551+
HOSTFS_I(ino)->btime = st->btime;
550552
ino->i_ino = st->ino;
551553
ino->i_mode = st->mode;
552554
return hostfs_inode_update(ino, st);
@@ -557,7 +559,10 @@ static int hostfs_inode_test(struct inode *inode, void *data)
557559
const struct hostfs_stat *st = data;
558560
dev_t dev = MKDEV(st->dev.maj, st->dev.min);
559561

560-
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == dev;
562+
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == dev &&
563+
(inode->i_mode & S_IFMT) == (st->mode & S_IFMT) &&
564+
HOSTFS_I(inode)->btime.tv_sec == st->btime.tv_sec &&
565+
HOSTFS_I(inode)->btime.tv_nsec == st->btime.tv_nsec;
561566
}
562567

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

fs/hostfs/hostfs_user.c

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,48 @@
1818
#include "hostfs.h"
1919
#include <utime.h>
2020

21-
static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
21+
static void statx_to_hostfs(const struct statx *buf, struct hostfs_stat *p)
2222
{
23-
p->ino = buf->st_ino;
24-
p->mode = buf->st_mode;
25-
p->nlink = buf->st_nlink;
26-
p->uid = buf->st_uid;
27-
p->gid = buf->st_gid;
28-
p->size = buf->st_size;
29-
p->atime.tv_sec = buf->st_atime;
30-
p->atime.tv_nsec = 0;
31-
p->ctime.tv_sec = buf->st_ctime;
32-
p->ctime.tv_nsec = 0;
33-
p->mtime.tv_sec = buf->st_mtime;
34-
p->mtime.tv_nsec = 0;
35-
p->blksize = buf->st_blksize;
36-
p->blocks = buf->st_blocks;
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);
23+
p->ino = buf->stx_ino;
24+
p->mode = buf->stx_mode;
25+
p->nlink = buf->stx_nlink;
26+
p->uid = buf->stx_uid;
27+
p->gid = buf->stx_gid;
28+
p->size = buf->stx_size;
29+
p->atime.tv_sec = buf->stx_atime.tv_sec;
30+
p->atime.tv_nsec = buf->stx_atime.tv_nsec;
31+
p->ctime.tv_sec = buf->stx_ctime.tv_sec;
32+
p->ctime.tv_nsec = buf->stx_ctime.tv_nsec;
33+
p->mtime.tv_sec = buf->stx_mtime.tv_sec;
34+
p->mtime.tv_nsec = buf->stx_mtime.tv_nsec;
35+
if (buf->stx_mask & STATX_BTIME) {
36+
p->btime.tv_sec = buf->stx_btime.tv_sec;
37+
p->btime.tv_nsec = buf->stx_btime.tv_nsec;
38+
} else {
39+
memset(&p->btime, 0, sizeof(p->btime));
40+
}
41+
p->blksize = buf->stx_blksize;
42+
p->blocks = buf->stx_blocks;
43+
p->rdev.maj = buf->stx_rdev_major;
44+
p->rdev.min = buf->stx_rdev_minor;
45+
p->dev.maj = buf->stx_dev_major;
46+
p->dev.min = buf->stx_dev_minor;
4147
}
4248

4349
int stat_file(const char *path, struct hostfs_stat *p, int fd)
4450
{
45-
struct stat64 buf;
51+
struct statx buf;
52+
int flags = AT_SYMLINK_NOFOLLOW;
4653

4754
if (fd >= 0) {
48-
if (fstat64(fd, &buf) < 0)
49-
return -errno;
50-
} else if (lstat64(path, &buf) < 0) {
51-
return -errno;
55+
flags |= AT_EMPTY_PATH;
56+
path = "";
5257
}
53-
stat64_to_hostfs(&buf, p);
58+
59+
if ((statx(fd, path, flags, STATX_BASIC_STATS | STATX_BTIME, &buf)) < 0)
60+
return -errno;
61+
62+
statx_to_hostfs(&buf, p);
5463
return 0;
5564
}
5665

0 commit comments

Comments
 (0)