Skip to content

Commit e9d488c

Browse files
committed
Merge tag 'binfmt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/binfmt_misc
Pull binfmt_misc update from James Bottomley: "This update is to allow architecture emulation containers to function such that the emulation binary can be housed outside the container itself. The container and fs parts both have acks from relevant experts. To use the new feature you have to add an F option to your binfmt_misc configuration" From the docs: "The usual behaviour of binfmt_misc is to spawn the binary lazily when the misc format file is invoked. However, this doesn't work very well in the face of mount namespaces and changeroots, so the F mode opens the binary as soon as the emulation is installed and uses the opened image to spawn the emulator, meaning it is always available once installed, regardless of how the environment changes" * tag 'binfmt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/binfmt_misc: binfmt_misc: add F option description to documentation binfmt_misc: add persistent opened binary handler for containers fs: add filp_clone_open API
2 parents 337684a + 4af75df commit e9d488c

File tree

4 files changed

+67
-2
lines changed

4 files changed

+67
-2
lines changed

Documentation/binfmt_misc.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ Here is what the fields mean:
6666
This feature should be used with care as the interpreter
6767
will run with root permissions when a setuid binary owned by root
6868
is run with binfmt_misc.
69+
'F' - fix binary. The usual behaviour of binfmt_misc is to spawn the
70+
binary lazily when the misc format file is invoked. However,
71+
this doesn't work very well in the face of mount namespaces and
72+
changeroots, so the F mode opens the binary as soon as the
73+
emulation is installed and uses the opened image to spawn the
74+
emulator, meaning it is always available once installed,
75+
regardless of how the environment changes.
6976

7077

7178
There are some restrictions:

fs/binfmt_misc.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <linux/fs.h>
2727
#include <linux/uaccess.h>
2828

29+
#include "internal.h"
30+
2931
#ifdef DEBUG
3032
# define USE_DEBUG 1
3133
#else
@@ -43,6 +45,7 @@ enum {Enabled, Magic};
4345
#define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
4446
#define MISC_FMT_OPEN_BINARY (1 << 30)
4547
#define MISC_FMT_CREDENTIALS (1 << 29)
48+
#define MISC_FMT_OPEN_FILE (1 << 28)
4649

4750
typedef struct {
4851
struct list_head list;
@@ -54,6 +57,7 @@ typedef struct {
5457
char *interpreter; /* filename of interpreter */
5558
char *name;
5659
struct dentry *dentry;
60+
struct file *interp_file;
5761
} Node;
5862

5963
static DEFINE_RWLOCK(entries_lock);
@@ -201,7 +205,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
201205
if (retval < 0)
202206
goto error;
203207

204-
interp_file = open_exec(iname);
208+
if (fmt->flags & MISC_FMT_OPEN_FILE && fmt->interp_file) {
209+
interp_file = filp_clone_open(fmt->interp_file);
210+
if (!IS_ERR(interp_file))
211+
deny_write_access(interp_file);
212+
} else {
213+
interp_file = open_exec(iname);
214+
}
205215
retval = PTR_ERR(interp_file);
206216
if (IS_ERR(interp_file))
207217
goto error;
@@ -285,6 +295,11 @@ static char *check_special_flags(char *sfs, Node *e)
285295
e->flags |= (MISC_FMT_CREDENTIALS |
286296
MISC_FMT_OPEN_BINARY);
287297
break;
298+
case 'F':
299+
pr_debug("register: flag: F: open interpreter file now\n");
300+
p++;
301+
e->flags |= MISC_FMT_OPEN_FILE;
302+
break;
288303
default:
289304
cont = 0;
290305
}
@@ -543,6 +558,8 @@ static void entry_status(Node *e, char *page)
543558
*dp++ = 'O';
544559
if (e->flags & MISC_FMT_CREDENTIALS)
545560
*dp++ = 'C';
561+
if (e->flags & MISC_FMT_OPEN_FILE)
562+
*dp++ = 'F';
546563
*dp++ = '\n';
547564

548565
if (!test_bit(Magic, &e->flags)) {
@@ -590,6 +607,11 @@ static void kill_node(Node *e)
590607
}
591608
write_unlock(&entries_lock);
592609

610+
if ((e->flags & MISC_FMT_OPEN_FILE) && e->interp_file) {
611+
filp_close(e->interp_file, NULL);
612+
e->interp_file = NULL;
613+
}
614+
593615
if (dentry) {
594616
drop_nlink(d_inode(dentry));
595617
d_drop(dentry);
@@ -696,6 +718,21 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
696718
goto out2;
697719
}
698720

721+
if (e->flags & MISC_FMT_OPEN_FILE) {
722+
struct file *f;
723+
724+
f = open_exec(e->interpreter);
725+
if (IS_ERR(f)) {
726+
err = PTR_ERR(f);
727+
pr_notice("register: failed to install interpreter file %s\n", e->interpreter);
728+
simple_release_fs(&bm_mnt, &entry_count);
729+
iput(inode);
730+
inode = NULL;
731+
goto out2;
732+
}
733+
e->interp_file = f;
734+
}
735+
699736
e->dentry = dget(dentry);
700737
inode->i_private = e;
701738
inode->i_fop = &bm_entry_operations;
@@ -713,7 +750,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
713750

714751
if (err) {
715752
kfree(e);
716-
return -EINVAL;
753+
return err;
717754
}
718755
return count;
719756
}

fs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ extern long do_handle_open(int mountdirfd,
111111
struct file_handle __user *ufh, int open_flag);
112112
extern int open_check_o_direct(struct file *f);
113113
extern int vfs_open(const struct path *, struct file *, const struct cred *);
114+
extern struct file *filp_clone_open(struct file *);
114115

115116
/*
116117
* inode.c

fs/open.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,26 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
998998
}
999999
EXPORT_SYMBOL(file_open_root);
10001000

1001+
struct file *filp_clone_open(struct file *oldfile)
1002+
{
1003+
struct file *file;
1004+
int retval;
1005+
1006+
file = get_empty_filp();
1007+
if (IS_ERR(file))
1008+
return file;
1009+
1010+
file->f_flags = oldfile->f_flags;
1011+
retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred);
1012+
if (retval) {
1013+
put_filp(file);
1014+
return ERR_PTR(retval);
1015+
}
1016+
1017+
return file;
1018+
}
1019+
EXPORT_SYMBOL(filp_clone_open);
1020+
10011021
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
10021022
{
10031023
struct open_flags op;

0 commit comments

Comments
 (0)