mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'landlock-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mic/linux
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
This commit is contained in:
@@ -1214,13 +1214,6 @@ config COMPAT_32BIT_TIME
|
||||
config ARCH_NO_PREEMPT
|
||||
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
|
||||
bool
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ menu "UML-specific options"
|
||||
config UML
|
||||
bool
|
||||
default y
|
||||
select ARCH_EPHEMERAL_INODES
|
||||
select ARCH_HAS_CPU_FINALIZE_INIT
|
||||
select ARCH_HAS_FORTIFY_SOURCE
|
||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||
|
||||
@@ -65,6 +65,7 @@ struct hostfs_stat {
|
||||
unsigned long long blocks;
|
||||
unsigned int maj;
|
||||
unsigned int min;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
|
||||
|
||||
@@ -26,6 +26,7 @@ struct hostfs_inode_info {
|
||||
fmode_t mode;
|
||||
struct inode vfs_inode;
|
||||
struct mutex open_mutex;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@@ -228,6 +221,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
|
||||
return NULL;
|
||||
hi->fd = -1;
|
||||
hi->mode = 0;
|
||||
hi->dev = 0;
|
||||
inode_init_once(&hi->vfs_inode);
|
||||
mutex_init(&hi->open_mutex);
|
||||
return &hi->vfs_inode;
|
||||
@@ -240,6 +234,7 @@ static void hostfs_evict_inode(struct inode *inode)
|
||||
if (HOSTFS_I(inode)->fd != -1) {
|
||||
close_file(&HOSTFS_I(inode)->fd);
|
||||
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 = {
|
||||
.alloc_inode = hostfs_alloc_inode,
|
||||
.free_inode = hostfs_free_inode,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.evict_inode = hostfs_evict_inode,
|
||||
.statfs = hostfs_statfs,
|
||||
.show_options = hostfs_show_options,
|
||||
@@ -512,18 +508,31 @@ static const struct address_space_operations hostfs_aops = {
|
||||
.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;
|
||||
struct hostfs_stat st;
|
||||
int err = stat_file(name, &st, -1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* 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:
|
||||
ino->i_op = &hostfs_link_iops;
|
||||
break;
|
||||
@@ -535,7 +544,7 @@ static int read_name(struct inode *ino, char *name)
|
||||
case S_IFBLK:
|
||||
case S_IFIFO:
|
||||
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;
|
||||
break;
|
||||
case S_IFREG:
|
||||
@@ -547,17 +556,42 @@ static int read_name(struct inode *ino, char *name)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ino->i_ino = st.ino;
|
||||
ino->i_mode = st.mode;
|
||||
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;
|
||||
HOSTFS_I(ino)->dev = st->dev;
|
||||
ino->i_ino = st->ino;
|
||||
ino->i_mode = st->mode;
|
||||
return hostfs_inode_update(ino, st);
|
||||
}
|
||||
|
||||
static int hostfs_inode_test(struct inode *inode, void *data)
|
||||
{
|
||||
const struct hostfs_stat *st = data;
|
||||
|
||||
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,
|
||||
@@ -565,62 +599,48 @@ static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
|
||||
{
|
||||
struct inode *inode;
|
||||
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);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
return -ENOMEM;
|
||||
|
||||
fd = file_create(name, mode & 0777);
|
||||
if (fd < 0)
|
||||
error = fd;
|
||||
else
|
||||
error = read_name(inode, name);
|
||||
if (fd < 0) {
|
||||
__putname(name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
inode = hostfs_iget(dir->i_sb, name);
|
||||
__putname(name);
|
||||
if (error)
|
||||
goto out_put;
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
HOSTFS_I(inode)->fd = fd;
|
||||
HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
||||
out_put:
|
||||
iput(inode);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = NULL;
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
inode = hostfs_iget(ino->i_sb);
|
||||
if (IS_ERR(inode))
|
||||
goto out;
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry);
|
||||
if (name) {
|
||||
err = read_name(inode, name);
|
||||
__putname(name);
|
||||
if (name == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
inode = hostfs_iget(ino->i_sb, 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);
|
||||
}
|
||||
|
||||
@@ -704,35 +724,23 @@ static int hostfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
inode = hostfs_iget(dir->i_sb);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
return -ENOMEM;
|
||||
|
||||
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
|
||||
if (err)
|
||||
goto out_free;
|
||||
if (err) {
|
||||
__putname(name);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = read_name(inode, name);
|
||||
inode = hostfs_iget(dir->i_sb, name);
|
||||
__putname(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
__putname(name);
|
||||
out_put:
|
||||
iput(inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
err = super_setup_bdi(sb);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
/* NULL is printed as '(null)' by printf(): avoid that. */
|
||||
if (req_root == NULL)
|
||||
req_root = "";
|
||||
|
||||
err = -ENOMEM;
|
||||
sb->s_fs_info = host_root_path =
|
||||
kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
|
||||
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);
|
||||
if (err)
|
||||
goto out_put;
|
||||
root_inode = hostfs_iget(sb, host_root_path);
|
||||
if (IS_ERR(root_inode))
|
||||
return PTR_ERR(root_inode);
|
||||
|
||||
if (S_ISLNK(root_inode->i_mode)) {
|
||||
char *name = follow_link(host_root_path);
|
||||
if (IS_ERR(name)) {
|
||||
err = PTR_ERR(name);
|
||||
goto out_put;
|
||||
}
|
||||
err = read_name(root_inode, name);
|
||||
char *name;
|
||||
|
||||
iput(root_inode);
|
||||
name = follow_link(host_root_path);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
root_inode = hostfs_iget(sb, name);
|
||||
kfree(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
if (IS_ERR(root_inode))
|
||||
return PTR_ERR(root_inode);
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
sb->s_root = d_make_root(root_inode);
|
||||
if (sb->s_root == NULL)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
||||
out_put:
|
||||
iput(root_inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *hostfs_read_sb(struct file_system_type *type,
|
||||
|
||||
@@ -36,6 +36,7 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
|
||||
p->blocks = buf->st_blocks;
|
||||
p->maj = os_major(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)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
config SECURITY_LANDLOCK
|
||||
bool "Landlock support"
|
||||
depends on SECURITY && !ARCH_EPHEMERAL_INODES
|
||||
depends on SECURITY
|
||||
select SECURITY_PATH
|
||||
help
|
||||
Landlock is a sandboxing mechanism that enables processes to restrict
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_OVERLAY_FS=y
|
||||
CONFIG_SECURITY_LANDLOCK=y
|
||||
CONFIG_SECURITY_PATH=y
|
||||
CONFIG_PROC_FS=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_LANDLOCK=y
|
||||
CONFIG_SHMEM=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
CONFIG_SYSFS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
|
||||
1
tools/testing/selftests/landlock/config.um
Normal file
1
tools/testing/selftests/landlock/config.um
Normal file
@@ -0,0 +1 @@
|
||||
CONFIG_HOSTFS=y
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user