Skip to content

Commit 2664286

Browse files
committed
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
2 parents 6e2332e + 35ca423 commit 2664286

9 files changed

Lines changed: 478 additions & 144 deletions

File tree

arch/Kconfig

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,13 +1214,6 @@ config COMPAT_32BIT_TIME
12141214
config ARCH_NO_PREEMPT
12151215
bool
12161216

1217-
config ARCH_EPHEMERAL_INODES
1218-
def_bool n
1219-
help
1220-
An arch should select this symbol if it doesn't keep track of inode
1221-
instances on its own, but instead relies on something else (e.g. the
1222-
host kernel for an UML kernel).
1223-
12241217
config ARCH_SUPPORTS_RT
12251218
bool
12261219

arch/um/Kconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ menu "UML-specific options"
55
config UML
66
bool
77
default y
8-
select ARCH_EPHEMERAL_INODES
98
select ARCH_HAS_CPU_FINALIZE_INIT
109
select ARCH_HAS_FORTIFY_SOURCE
1110
select ARCH_HAS_GCOV_PROFILE_ALL

fs/hostfs/hostfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct hostfs_stat {
6565
unsigned long long blocks;
6666
unsigned int maj;
6767
unsigned int min;
68+
dev_t dev;
6869
};
6970

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

fs/hostfs/hostfs_kern.c

Lines changed: 106 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct hostfs_inode_info {
2626
fmode_t mode;
2727
struct inode vfs_inode;
2828
struct mutex open_mutex;
29+
dev_t dev;
2930
};
3031

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

185-
static struct inode *hostfs_iget(struct super_block *sb)
186-
{
187-
struct inode *inode = new_inode(sb);
188-
if (!inode)
189-
return ERR_PTR(-ENOMEM);
190-
return inode;
191-
}
192-
193186
static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
194187
{
195188
/*
@@ -228,6 +221,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
228221
return NULL;
229222
hi->fd = -1;
230223
hi->mode = 0;
224+
hi->dev = 0;
231225
inode_init_once(&hi->vfs_inode);
232226
mutex_init(&hi->open_mutex);
233227
return &hi->vfs_inode;
@@ -240,6 +234,7 @@ static void hostfs_evict_inode(struct inode *inode)
240234
if (HOSTFS_I(inode)->fd != -1) {
241235
close_file(&HOSTFS_I(inode)->fd);
242236
HOSTFS_I(inode)->fd = -1;
237+
HOSTFS_I(inode)->dev = 0;
243238
}
244239
}
245240

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

515-
static int read_name(struct inode *ino, char *name)
511+
static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st)
512+
{
513+
set_nlink(ino, st->nlink);
514+
i_uid_write(ino, st->uid);
515+
i_gid_write(ino, st->gid);
516+
ino->i_atime =
517+
(struct timespec64){ st->atime.tv_sec, st->atime.tv_nsec };
518+
ino->i_mtime =
519+
(struct timespec64){ st->mtime.tv_sec, st->mtime.tv_nsec };
520+
ino->i_ctime =
521+
(struct timespec64){ st->ctime.tv_sec, st->ctime.tv_nsec };
522+
ino->i_size = st->size;
523+
ino->i_blocks = st->blocks;
524+
return 0;
525+
}
526+
527+
static int hostfs_inode_set(struct inode *ino, void *data)
516528
{
529+
struct hostfs_stat *st = data;
517530
dev_t rdev;
518-
struct hostfs_stat st;
519-
int err = stat_file(name, &st, -1);
520-
if (err)
521-
return err;
522531

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

526-
switch (st.mode & S_IFMT) {
535+
switch (st->mode & S_IFMT) {
527536
case S_IFLNK:
528537
ino->i_op = &hostfs_link_iops;
529538
break;
@@ -535,7 +544,7 @@ static int read_name(struct inode *ino, char *name)
535544
case S_IFBLK:
536545
case S_IFIFO:
537546
case S_IFSOCK:
538-
init_special_inode(ino, st.mode & S_IFMT, rdev);
547+
init_special_inode(ino, st->mode & S_IFMT, rdev);
539548
ino->i_op = &hostfs_iops;
540549
break;
541550
case S_IFREG:
@@ -547,80 +556,91 @@ static int read_name(struct inode *ino, char *name)
547556
return -EIO;
548557
}
549558

550-
ino->i_ino = st.ino;
551-
ino->i_mode = st.mode;
552-
set_nlink(ino, st.nlink);
553-
i_uid_write(ino, st.uid);
554-
i_gid_write(ino, st.gid);
555-
ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
556-
ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
557-
ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
558-
ino->i_size = st.size;
559-
ino->i_blocks = st.blocks;
560-
return 0;
559+
HOSTFS_I(ino)->dev = st->dev;
560+
ino->i_ino = st->ino;
561+
ino->i_mode = st->mode;
562+
return hostfs_inode_update(ino, st);
563+
}
564+
565+
static int hostfs_inode_test(struct inode *inode, void *data)
566+
{
567+
const struct hostfs_stat *st = data;
568+
569+
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev;
570+
}
571+
572+
static struct inode *hostfs_iget(struct super_block *sb, char *name)
573+
{
574+
struct inode *inode;
575+
struct hostfs_stat st;
576+
int err = stat_file(name, &st, -1);
577+
578+
if (err)
579+
return ERR_PTR(err);
580+
581+
inode = iget5_locked(sb, st.ino, hostfs_inode_test, hostfs_inode_set,
582+
&st);
583+
if (!inode)
584+
return ERR_PTR(-ENOMEM);
585+
586+
if (inode->i_state & I_NEW) {
587+
unlock_new_inode(inode);
588+
} else {
589+
spin_lock(&inode->i_lock);
590+
hostfs_inode_update(inode, &st);
591+
spin_unlock(&inode->i_lock);
592+
}
593+
594+
return inode;
561595
}
562596

563597
static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
564598
struct dentry *dentry, umode_t mode, bool excl)
565599
{
566600
struct inode *inode;
567601
char *name;
568-
int error, fd;
569-
570-
inode = hostfs_iget(dir->i_sb);
571-
if (IS_ERR(inode)) {
572-
error = PTR_ERR(inode);
573-
goto out;
574-
}
602+
int fd;
575603

576-
error = -ENOMEM;
577604
name = dentry_name(dentry);
578605
if (name == NULL)
579-
goto out_put;
606+
return -ENOMEM;
580607

581608
fd = file_create(name, mode & 0777);
582-
if (fd < 0)
583-
error = fd;
584-
else
585-
error = read_name(inode, name);
609+
if (fd < 0) {
610+
__putname(name);
611+
return fd;
612+
}
586613

614+
inode = hostfs_iget(dir->i_sb, name);
587615
__putname(name);
588-
if (error)
589-
goto out_put;
616+
if (IS_ERR(inode))
617+
return PTR_ERR(inode);
590618

591619
HOSTFS_I(inode)->fd = fd;
592620
HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
593621
d_instantiate(dentry, inode);
594622
return 0;
595-
596-
out_put:
597-
iput(inode);
598-
out:
599-
return error;
600623
}
601624

602625
static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
603626
unsigned int flags)
604627
{
605-
struct inode *inode;
628+
struct inode *inode = NULL;
606629
char *name;
607-
int err;
608-
609-
inode = hostfs_iget(ino->i_sb);
610-
if (IS_ERR(inode))
611-
goto out;
612630

613-
err = -ENOMEM;
614631
name = dentry_name(dentry);
615-
if (name) {
616-
err = read_name(inode, name);
617-
__putname(name);
618-
}
619-
if (err) {
620-
iput(inode);
621-
inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
632+
if (name == NULL)
633+
return ERR_PTR(-ENOMEM);
634+
635+
inode = hostfs_iget(ino->i_sb, name);
636+
__putname(name);
637+
if (IS_ERR(inode)) {
638+
if (PTR_ERR(inode) == -ENOENT)
639+
inode = NULL;
640+
else
641+
return ERR_CAST(inode);
622642
}
623-
out:
643+
624644
return d_splice_alias(inode, dentry);
625645
}
626646

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

707-
inode = hostfs_iget(dir->i_sb);
708-
if (IS_ERR(inode)) {
709-
err = PTR_ERR(inode);
710-
goto out;
711-
}
712-
713-
err = -ENOMEM;
714727
name = dentry_name(dentry);
715728
if (name == NULL)
716-
goto out_put;
729+
return -ENOMEM;
717730

718731
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
719-
if (err)
720-
goto out_free;
732+
if (err) {
733+
__putname(name);
734+
return err;
735+
}
721736

722-
err = read_name(inode, name);
737+
inode = hostfs_iget(dir->i_sb, name);
723738
__putname(name);
724-
if (err)
725-
goto out_put;
739+
if (IS_ERR(inode))
740+
return PTR_ERR(inode);
726741

727742
d_instantiate(dentry, inode);
728743
return 0;
729-
730-
out_free:
731-
__putname(name);
732-
out_put:
733-
iput(inode);
734-
out:
735-
return err;
736744
}
737745

738746
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)
929937
sb->s_maxbytes = MAX_LFS_FILESIZE;
930938
err = super_setup_bdi(sb);
931939
if (err)
932-
goto out;
940+
return err;
933941

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

938-
err = -ENOMEM;
939946
sb->s_fs_info = host_root_path =
940947
kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
941948
if (host_root_path == NULL)
942-
goto out;
943-
944-
root_inode = new_inode(sb);
945-
if (!root_inode)
946-
goto out;
949+
return -ENOMEM;
947950

948-
err = read_name(root_inode, host_root_path);
949-
if (err)
950-
goto out_put;
951+
root_inode = hostfs_iget(sb, host_root_path);
952+
if (IS_ERR(root_inode))
953+
return PTR_ERR(root_inode);
951954

952955
if (S_ISLNK(root_inode->i_mode)) {
953-
char *name = follow_link(host_root_path);
954-
if (IS_ERR(name)) {
955-
err = PTR_ERR(name);
956-
goto out_put;
957-
}
958-
err = read_name(root_inode, name);
956+
char *name;
957+
958+
iput(root_inode);
959+
name = follow_link(host_root_path);
960+
if (IS_ERR(name))
961+
return PTR_ERR(name);
962+
963+
root_inode = hostfs_iget(sb, name);
959964
kfree(name);
960-
if (err)
961-
goto out_put;
965+
if (IS_ERR(root_inode))
966+
return PTR_ERR(root_inode);
962967
}
963968

964-
err = -ENOMEM;
965969
sb->s_root = d_make_root(root_inode);
966970
if (sb->s_root == NULL)
967-
goto out;
971+
return -ENOMEM;
968972

969973
return 0;
970-
971-
out_put:
972-
iput(root_inode);
973-
out:
974-
return err;
975974
}
976975

977976
static struct dentry *hostfs_read_sb(struct file_system_type *type,

fs/hostfs/hostfs_user.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
3636
p->blocks = buf->st_blocks;
3737
p->maj = os_major(buf->st_rdev);
3838
p->min = os_minor(buf->st_rdev);
39+
p->dev = buf->st_dev;
3940
}
4041

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

security/landlock/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
config SECURITY_LANDLOCK
44
bool "Landlock support"
5-
depends on SECURITY && !ARCH_EPHEMERAL_INODES
5+
depends on SECURITY
66
select SECURITY_PATH
77
help
88
Landlock is a sandboxing mechanism that enables processes to restrict

0 commit comments

Comments
 (0)