Commit 26642864 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull landlock updates from Mickaël Salaün:
 "Add support for Landlock to UML.

  To do this, this fixes the way hostfs manages inodes according to the
  underlying filesystem [1]. They are now properly handled as for other
  filesystems, which enables Landlock support (and probably other
  features).

  This also extends Landlock's tests with 6 pseudo filesystems,
  including hostfs"

[1] https://lore.kernel.org/all/20230612191430.339153-1-mic@digikod.net/

* tag 'landlock-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux:
  selftests/landlock: Add hostfs tests
  selftests/landlock: Add tests for pseudo filesystems
  selftests/landlock: Make mounts configurable
  selftests/landlock: Add supports_filesystem() helper
  selftests/landlock: Don't create useless file layouts
  hostfs: Fix ephemeral inodes
parents 6e2332e0 35ca4239
Loading
Loading
Loading
Loading
+0 −7
Original line number Original line Diff line number Diff line
@@ -1214,13 +1214,6 @@ config COMPAT_32BIT_TIME
config ARCH_NO_PREEMPT
config ARCH_NO_PREEMPT
	bool
	bool


config ARCH_EPHEMERAL_INODES
	def_bool n
	help
	  An arch should select this symbol if it doesn't keep track of inode
	  instances on its own, but instead relies on something else (e.g. the
	  host kernel for an UML kernel).

config ARCH_SUPPORTS_RT
config ARCH_SUPPORTS_RT
	bool
	bool


+0 −1
Original line number Original line Diff line number Diff line
@@ -5,7 +5,6 @@ menu "UML-specific options"
config UML
config UML
	bool
	bool
	default y
	default y
	select ARCH_EPHEMERAL_INODES
	select ARCH_HAS_CPU_FINALIZE_INIT
	select ARCH_HAS_CPU_FINALIZE_INIT
	select ARCH_HAS_FORTIFY_SOURCE
	select ARCH_HAS_FORTIFY_SOURCE
	select ARCH_HAS_GCOV_PROFILE_ALL
	select ARCH_HAS_GCOV_PROFILE_ALL
+1 −0
Original line number Original line Diff line number Diff line
@@ -65,6 +65,7 @@ struct hostfs_stat {
	unsigned long long blocks;
	unsigned long long blocks;
	unsigned int maj;
	unsigned int maj;
	unsigned int min;
	unsigned int min;
	dev_t dev;
};
};


extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
+106 −107
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ struct hostfs_inode_info {
	fmode_t mode;
	fmode_t mode;
	struct inode vfs_inode;
	struct inode vfs_inode;
	struct mutex open_mutex;
	struct mutex open_mutex;
	dev_t dev;
};
};


static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
@@ -182,14 +183,6 @@ static char *follow_link(char *link)
	return ERR_PTR(n);
	return ERR_PTR(n);
}
}


static struct inode *hostfs_iget(struct super_block *sb)
{
	struct inode *inode = new_inode(sb);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;
}

static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
{
{
	/*
	/*
@@ -228,6 +221,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
		return NULL;
		return NULL;
	hi->fd = -1;
	hi->fd = -1;
	hi->mode = 0;
	hi->mode = 0;
	hi->dev = 0;
	inode_init_once(&hi->vfs_inode);
	inode_init_once(&hi->vfs_inode);
	mutex_init(&hi->open_mutex);
	mutex_init(&hi->open_mutex);
	return &hi->vfs_inode;
	return &hi->vfs_inode;
@@ -240,6 +234,7 @@ static void hostfs_evict_inode(struct inode *inode)
	if (HOSTFS_I(inode)->fd != -1) {
	if (HOSTFS_I(inode)->fd != -1) {
		close_file(&HOSTFS_I(inode)->fd);
		close_file(&HOSTFS_I(inode)->fd);
		HOSTFS_I(inode)->fd = -1;
		HOSTFS_I(inode)->fd = -1;
		HOSTFS_I(inode)->dev = 0;
	}
	}
}
}


@@ -265,6 +260,7 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
static const struct super_operations hostfs_sbops = {
static const struct super_operations hostfs_sbops = {
	.alloc_inode	= hostfs_alloc_inode,
	.alloc_inode	= hostfs_alloc_inode,
	.free_inode	= hostfs_free_inode,
	.free_inode	= hostfs_free_inode,
	.drop_inode	= generic_delete_inode,
	.evict_inode	= hostfs_evict_inode,
	.evict_inode	= hostfs_evict_inode,
	.statfs		= hostfs_statfs,
	.statfs		= hostfs_statfs,
	.show_options	= hostfs_show_options,
	.show_options	= hostfs_show_options,
@@ -512,18 +508,31 @@ static const struct address_space_operations hostfs_aops = {
	.write_end	= hostfs_write_end,
	.write_end	= hostfs_write_end,
};
};


static int read_name(struct inode *ino, char *name)
static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st)
{
	set_nlink(ino, st->nlink);
	i_uid_write(ino, st->uid);
	i_gid_write(ino, st->gid);
	ino->i_atime =
		(struct timespec64){ st->atime.tv_sec, st->atime.tv_nsec };
	ino->i_mtime =
		(struct timespec64){ st->mtime.tv_sec, st->mtime.tv_nsec };
	ino->i_ctime =
		(struct timespec64){ st->ctime.tv_sec, st->ctime.tv_nsec };
	ino->i_size = st->size;
	ino->i_blocks = st->blocks;
	return 0;
}

static int hostfs_inode_set(struct inode *ino, void *data)
{
{
	struct hostfs_stat *st = data;
	dev_t rdev;
	dev_t rdev;
	struct hostfs_stat st;
	int err = stat_file(name, &st, -1);
	if (err)
		return err;


	/* Reencode maj and min with the kernel encoding.*/
	/* Reencode maj and min with the kernel encoding.*/
	rdev = MKDEV(st.maj, st.min);
	rdev = MKDEV(st->maj, st->min);


	switch (st.mode & S_IFMT) {
	switch (st->mode & S_IFMT) {
	case S_IFLNK:
	case S_IFLNK:
		ino->i_op = &hostfs_link_iops;
		ino->i_op = &hostfs_link_iops;
		break;
		break;
@@ -535,7 +544,7 @@ static int read_name(struct inode *ino, char *name)
	case S_IFBLK:
	case S_IFBLK:
	case S_IFIFO:
	case S_IFIFO:
	case S_IFSOCK:
	case S_IFSOCK:
		init_special_inode(ino, st.mode & S_IFMT, rdev);
		init_special_inode(ino, st->mode & S_IFMT, rdev);
		ino->i_op = &hostfs_iops;
		ino->i_op = &hostfs_iops;
		break;
		break;
	case S_IFREG:
	case S_IFREG:
@@ -547,17 +556,42 @@ static int read_name(struct inode *ino, char *name)
		return -EIO;
		return -EIO;
	}
	}


	ino->i_ino = st.ino;
	HOSTFS_I(ino)->dev = st->dev;
	ino->i_mode = st.mode;
	ino->i_ino = st->ino;
	set_nlink(ino, st.nlink);
	ino->i_mode = st->mode;
	i_uid_write(ino, st.uid);
	return hostfs_inode_update(ino, st);
	i_gid_write(ino, st.gid);
}
	ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };

	ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
static int hostfs_inode_test(struct inode *inode, void *data)
	ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
{
	ino->i_size = st.size;
	const struct hostfs_stat *st = data;
	ino->i_blocks = st.blocks;

	return 0;
	return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev;
}

static struct inode *hostfs_iget(struct super_block *sb, char *name)
{
	struct inode *inode;
	struct hostfs_stat st;
	int err = stat_file(name, &st, -1);

	if (err)
		return ERR_PTR(err);

	inode = iget5_locked(sb, st.ino, hostfs_inode_test, hostfs_inode_set,
			     &st);
	if (!inode)
		return ERR_PTR(-ENOMEM);

	if (inode->i_state & I_NEW) {
		unlock_new_inode(inode);
	} else {
		spin_lock(&inode->i_lock);
		hostfs_inode_update(inode, &st);
		spin_unlock(&inode->i_lock);
	}

	return inode;
}
}


static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
@@ -565,62 +599,48 @@ static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
{
{
	struct inode *inode;
	struct inode *inode;
	char *name;
	char *name;
	int error, fd;
	int fd;

	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
		goto out;
	}


	error = -ENOMEM;
	name = dentry_name(dentry);
	name = dentry_name(dentry);
	if (name == NULL)
	if (name == NULL)
		goto out_put;
		return -ENOMEM;


	fd = file_create(name, mode & 0777);
	fd = file_create(name, mode & 0777);
	if (fd < 0)
	if (fd < 0) {
		error = fd;
		__putname(name);
	else
		return fd;
		error = read_name(inode, name);
	}


	inode = hostfs_iget(dir->i_sb, name);
	__putname(name);
	__putname(name);
	if (error)
	if (IS_ERR(inode))
		goto out_put;
		return PTR_ERR(inode);


	HOSTFS_I(inode)->fd = fd;
	HOSTFS_I(inode)->fd = fd;
	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
	d_instantiate(dentry, inode);
	d_instantiate(dentry, inode);
	return 0;
	return 0;

 out_put:
	iput(inode);
 out:
	return error;
}
}


static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
				    unsigned int flags)
				    unsigned int flags)
{
{
	struct inode *inode;
	struct inode *inode = NULL;
	char *name;
	char *name;
	int err;

	inode = hostfs_iget(ino->i_sb);
	if (IS_ERR(inode))
		goto out;


	err = -ENOMEM;
	name = dentry_name(dentry);
	name = dentry_name(dentry);
	if (name) {
	if (name == NULL)
		err = read_name(inode, name);
		return ERR_PTR(-ENOMEM);

	inode = hostfs_iget(ino->i_sb, name);
	__putname(name);
	__putname(name);
	if (IS_ERR(inode)) {
		if (PTR_ERR(inode) == -ENOENT)
			inode = NULL;
		else
			return ERR_CAST(inode);
	}
	}
	if (err) {

		iput(inode);
		inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
	}
 out:
	return d_splice_alias(inode, dentry);
	return d_splice_alias(inode, dentry);
}
}


@@ -704,35 +724,23 @@ static int hostfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
	char *name;
	char *name;
	int err;
	int err;


	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto out;
	}

	err = -ENOMEM;
	name = dentry_name(dentry);
	name = dentry_name(dentry);
	if (name == NULL)
	if (name == NULL)
		goto out_put;
		return -ENOMEM;


	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
	if (err)
	if (err) {
		goto out_free;
		__putname(name);
		return err;
	}


	err = read_name(inode, name);
	inode = hostfs_iget(dir->i_sb, name);
	__putname(name);
	__putname(name);
	if (err)
	if (IS_ERR(inode))
		goto out_put;
		return PTR_ERR(inode);


	d_instantiate(dentry, inode);
	d_instantiate(dentry, inode);
	return 0;
	return 0;

 out_free:
	__putname(name);
 out_put:
	iput(inode);
 out:
	return err;
}
}


static int hostfs_rename2(struct mnt_idmap *idmap,
static int hostfs_rename2(struct mnt_idmap *idmap,
@@ -929,49 +937,40 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	err = super_setup_bdi(sb);
	err = super_setup_bdi(sb);
	if (err)
	if (err)
		goto out;
		return err;


	/* NULL is printed as '(null)' by printf(): avoid that. */
	/* NULL is printed as '(null)' by printf(): avoid that. */
	if (req_root == NULL)
	if (req_root == NULL)
		req_root = "";
		req_root = "";


	err = -ENOMEM;
	sb->s_fs_info = host_root_path =
	sb->s_fs_info = host_root_path =
		kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
		kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
	if (host_root_path == NULL)
	if (host_root_path == NULL)
		goto out;
		return -ENOMEM;

	root_inode = new_inode(sb);
	if (!root_inode)
		goto out;


	err = read_name(root_inode, host_root_path);
	root_inode = hostfs_iget(sb, host_root_path);
	if (err)
	if (IS_ERR(root_inode))
		goto out_put;
		return PTR_ERR(root_inode);


	if (S_ISLNK(root_inode->i_mode)) {
	if (S_ISLNK(root_inode->i_mode)) {
		char *name = follow_link(host_root_path);
		char *name;
		if (IS_ERR(name)) {

			err = PTR_ERR(name);
		iput(root_inode);
			goto out_put;
		name = follow_link(host_root_path);
		}
		if (IS_ERR(name))
		err = read_name(root_inode, name);
			return PTR_ERR(name);

		root_inode = hostfs_iget(sb, name);
		kfree(name);
		kfree(name);
		if (err)
		if (IS_ERR(root_inode))
			goto out_put;
			return PTR_ERR(root_inode);
	}
	}


	err = -ENOMEM;
	sb->s_root = d_make_root(root_inode);
	sb->s_root = d_make_root(root_inode);
	if (sb->s_root == NULL)
	if (sb->s_root == NULL)
		goto out;
		return -ENOMEM;


	return 0;
	return 0;

out_put:
	iput(root_inode);
out:
	return err;
}
}


static struct dentry *hostfs_read_sb(struct file_system_type *type,
static struct dentry *hostfs_read_sb(struct file_system_type *type,
+1 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
	p->blocks = buf->st_blocks;
	p->blocks = buf->st_blocks;
	p->maj = os_major(buf->st_rdev);
	p->maj = os_major(buf->st_rdev);
	p->min = os_minor(buf->st_rdev);
	p->min = os_minor(buf->st_rdev);
	p->dev = buf->st_dev;
}
}


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