diff options
-rw-r--r-- | fs/binfmt_misc.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 3a3ced779fc7..8a108c435bc6 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 | ||
47 | typedef struct { | 50 | typedef 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 | ||
59 | static DEFINE_RWLOCK(entries_lock); | 63 | static 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); |
@@ -698,6 +720,21 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer, | |||
698 | goto out2; | 720 | goto out2; |
699 | } | 721 | } |
700 | 722 | ||
723 | if (e->flags & MISC_FMT_OPEN_FILE) { | ||
724 | struct file *f; | ||
725 | |||
726 | f = open_exec(e->interpreter); | ||
727 | if (IS_ERR(f)) { | ||
728 | err = PTR_ERR(f); | ||
729 | pr_notice("register: failed to install interpreter file %s\n", e->interpreter); | ||
730 | simple_release_fs(&bm_mnt, &entry_count); | ||
731 | iput(inode); | ||
732 | inode = NULL; | ||
733 | goto out2; | ||
734 | } | ||
735 | e->interp_file = f; | ||
736 | } | ||
737 | |||
701 | e->dentry = dget(dentry); | 738 | e->dentry = dget(dentry); |
702 | inode->i_private = e; | 739 | inode->i_private = e; |
703 | inode->i_fop = &bm_entry_operations; | 740 | inode->i_fop = &bm_entry_operations; |
@@ -716,7 +753,7 @@ out: | |||
716 | 753 | ||
717 | if (err) { | 754 | if (err) { |
718 | kfree(e); | 755 | kfree(e); |
719 | return -EINVAL; | 756 | return err; |
720 | } | 757 | } |
721 | return count; | 758 | return count; |
722 | } | 759 | } |