aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-08-07 10:13:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-07 10:13:14 -0400
commite9d488c3114acb6a0a93e99c02f9cd1d656f46c7 (patch)
treeb0342f47b8bb8fa6af3a6d1416e9881ccdb00144
parent337684a1746f93ae107e05d90977b070bb7e39d8 (diff)
parent4af75df6a410ce76d9f60f27b07e5645ecc2c5ed (diff)
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
-rw-r--r--Documentation/binfmt_misc.txt7
-rw-r--r--fs/binfmt_misc.c41
-rw-r--r--fs/internal.h1
-rw-r--r--fs/open.c20
4 files changed, 67 insertions, 2 deletions
diff --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt
index 6b1de7058371..ec83bbce547a 100644
--- a/Documentation/binfmt_misc.txt
+++ b/Documentation/binfmt_misc.txt
@@ -66,6 +66,13 @@ Here is what the fields mean:
66 This feature should be used with care as the interpreter 66 This feature should be used with care as the interpreter
67 will run with root permissions when a setuid binary owned by root 67 will run with root permissions when a setuid binary owned by root
68 is run with binfmt_misc. 68 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.
69 76
70 77
71There are some restrictions: 78There are some restrictions:
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 5417516f6e59..6103a6362ccd 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -26,6 +26,8 @@
26#include <linux/fs.h> 26#include <linux/fs.h>
27#include <linux/uaccess.h> 27#include <linux/uaccess.h>
28 28
29#include "internal.h"
30
29#ifdef DEBUG 31#ifdef DEBUG
30# define USE_DEBUG 1 32# define USE_DEBUG 1
31#else 33#else
@@ -43,6 +45,7 @@ enum {Enabled, Magic};
43#define MISC_FMT_PRESERVE_ARGV0 (1 << 31) 45#define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
44#define MISC_FMT_OPEN_BINARY (1 << 30) 46#define MISC_FMT_OPEN_BINARY (1 << 30)
45#define MISC_FMT_CREDENTIALS (1 << 29) 47#define MISC_FMT_CREDENTIALS (1 << 29)
48#define MISC_FMT_OPEN_FILE (1 << 28)
46 49
47typedef struct { 50typedef struct {
48 struct list_head list; 51 struct list_head list;
@@ -54,6 +57,7 @@ typedef struct {
54 char *interpreter; /* filename of interpreter */ 57 char *interpreter; /* filename of interpreter */
55 char *name; 58 char *name;
56 struct dentry *dentry; 59 struct dentry *dentry;
60 struct file *interp_file;
57} Node; 61} Node;
58 62
59static DEFINE_RWLOCK(entries_lock); 63static DEFINE_RWLOCK(entries_lock);
@@ -201,7 +205,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
201 if (retval < 0) 205 if (retval < 0)
202 goto error; 206 goto error;
203 207
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 }
205 retval = PTR_ERR(interp_file); 215 retval = PTR_ERR(interp_file);
206 if (IS_ERR(interp_file)) 216 if (IS_ERR(interp_file))
207 goto error; 217 goto error;
@@ -285,6 +295,11 @@ static char *check_special_flags(char *sfs, Node *e)
285 e->flags |= (MISC_FMT_CREDENTIALS | 295 e->flags |= (MISC_FMT_CREDENTIALS |
286 MISC_FMT_OPEN_BINARY); 296 MISC_FMT_OPEN_BINARY);
287 break; 297 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;
288 default: 303 default:
289 cont = 0; 304 cont = 0;
290 } 305 }
@@ -543,6 +558,8 @@ static void entry_status(Node *e, char *page)
543 *dp++ = 'O'; 558 *dp++ = 'O';
544 if (e->flags & MISC_FMT_CREDENTIALS) 559 if (e->flags & MISC_FMT_CREDENTIALS)
545 *dp++ = 'C'; 560 *dp++ = 'C';
561 if (e->flags & MISC_FMT_OPEN_FILE)
562 *dp++ = 'F';
546 *dp++ = '\n'; 563 *dp++ = '\n';
547 564
548 if (!test_bit(Magic, &e->flags)) { 565 if (!test_bit(Magic, &e->flags)) {
@@ -590,6 +607,11 @@ static void kill_node(Node *e)
590 } 607 }
591 write_unlock(&entries_lock); 608 write_unlock(&entries_lock);
592 609
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
593 if (dentry) { 615 if (dentry) {
594 drop_nlink(d_inode(dentry)); 616 drop_nlink(d_inode(dentry));
595 d_drop(dentry); 617 d_drop(dentry);
@@ -696,6 +718,21 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
696 goto out2; 718 goto out2;
697 } 719 }
698 720
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
699 e->dentry = dget(dentry); 736 e->dentry = dget(dentry);
700 inode->i_private = e; 737 inode->i_private = e;
701 inode->i_fop = &bm_entry_operations; 738 inode->i_fop = &bm_entry_operations;
@@ -713,7 +750,7 @@ out:
713 750
714 if (err) { 751 if (err) {
715 kfree(e); 752 kfree(e);
716 return -EINVAL; 753 return err;
717 } 754 }
718 return count; 755 return count;
719} 756}
diff --git a/fs/internal.h b/fs/internal.h
index cc5a530e4f06..ba0737649d4a 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -111,6 +111,7 @@ extern long do_handle_open(int mountdirfd,
111 struct file_handle __user *ufh, int open_flag); 111 struct file_handle __user *ufh, int open_flag);
112extern int open_check_o_direct(struct file *f); 112extern int open_check_o_direct(struct file *f);
113extern int vfs_open(const struct path *, struct file *, const struct cred *); 113extern int vfs_open(const struct path *, struct file *, const struct cred *);
114extern struct file *filp_clone_open(struct file *);
114 115
115/* 116/*
116 * inode.c 117 * inode.c
diff --git a/fs/open.c b/fs/open.c
index bf66cf1a9f5c..4fd6e256f4f4 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -998,6 +998,26 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
998} 998}
999EXPORT_SYMBOL(file_open_root); 999EXPORT_SYMBOL(file_open_root);
1000 1000
1001struct 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}
1019EXPORT_SYMBOL(filp_clone_open);
1020
1001long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) 1021long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
1002{ 1022{
1003 struct open_flags op; 1023 struct open_flags op;