|
@@ -26,6 +26,8 @@
|
|
|
#include <linux/fs.h>
|
|
|
#include <linux/uaccess.h>
|
|
|
|
|
|
+#include "internal.h"
|
|
|
+
|
|
|
#ifdef DEBUG
|
|
|
# define USE_DEBUG 1
|
|
|
#else
|
|
@@ -43,6 +45,7 @@ enum {Enabled, Magic};
|
|
|
#define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
|
|
|
#define MISC_FMT_OPEN_BINARY (1 << 30)
|
|
|
#define MISC_FMT_CREDENTIALS (1 << 29)
|
|
|
+#define MISC_FMT_OPEN_FILE (1 << 28)
|
|
|
|
|
|
typedef struct {
|
|
|
struct list_head list;
|
|
@@ -54,6 +57,7 @@ typedef struct {
|
|
|
char *interpreter; /* filename of interpreter */
|
|
|
char *name;
|
|
|
struct dentry *dentry;
|
|
|
+ struct file *interp_file;
|
|
|
} Node;
|
|
|
|
|
|
static DEFINE_RWLOCK(entries_lock);
|
|
@@ -201,7 +205,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
|
|
if (retval < 0)
|
|
|
goto error;
|
|
|
|
|
|
- interp_file = open_exec(iname);
|
|
|
+ if (fmt->flags & MISC_FMT_OPEN_FILE && fmt->interp_file) {
|
|
|
+ interp_file = filp_clone_open(fmt->interp_file);
|
|
|
+ if (!IS_ERR(interp_file))
|
|
|
+ deny_write_access(interp_file);
|
|
|
+ } else {
|
|
|
+ interp_file = open_exec(iname);
|
|
|
+ }
|
|
|
retval = PTR_ERR(interp_file);
|
|
|
if (IS_ERR(interp_file))
|
|
|
goto error;
|
|
@@ -285,6 +295,11 @@ static char *check_special_flags(char *sfs, Node *e)
|
|
|
e->flags |= (MISC_FMT_CREDENTIALS |
|
|
|
MISC_FMT_OPEN_BINARY);
|
|
|
break;
|
|
|
+ case 'F':
|
|
|
+ pr_debug("register: flag: F: open interpreter file now\n");
|
|
|
+ p++;
|
|
|
+ e->flags |= MISC_FMT_OPEN_FILE;
|
|
|
+ break;
|
|
|
default:
|
|
|
cont = 0;
|
|
|
}
|
|
@@ -543,6 +558,8 @@ static void entry_status(Node *e, char *page)
|
|
|
*dp++ = 'O';
|
|
|
if (e->flags & MISC_FMT_CREDENTIALS)
|
|
|
*dp++ = 'C';
|
|
|
+ if (e->flags & MISC_FMT_OPEN_FILE)
|
|
|
+ *dp++ = 'F';
|
|
|
*dp++ = '\n';
|
|
|
|
|
|
if (!test_bit(Magic, &e->flags)) {
|
|
@@ -590,6 +607,11 @@ static void kill_node(Node *e)
|
|
|
}
|
|
|
write_unlock(&entries_lock);
|
|
|
|
|
|
+ if ((e->flags & MISC_FMT_OPEN_FILE) && e->interp_file) {
|
|
|
+ filp_close(e->interp_file, NULL);
|
|
|
+ e->interp_file = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
if (dentry) {
|
|
|
drop_nlink(d_inode(dentry));
|
|
|
d_drop(dentry);
|
|
@@ -696,6 +718,21 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
|
|
goto out2;
|
|
|
}
|
|
|
|
|
|
+ if (e->flags & MISC_FMT_OPEN_FILE) {
|
|
|
+ struct file *f;
|
|
|
+
|
|
|
+ f = open_exec(e->interpreter);
|
|
|
+ if (IS_ERR(f)) {
|
|
|
+ err = PTR_ERR(f);
|
|
|
+ pr_notice("register: failed to install interpreter file %s\n", e->interpreter);
|
|
|
+ simple_release_fs(&bm_mnt, &entry_count);
|
|
|
+ iput(inode);
|
|
|
+ inode = NULL;
|
|
|
+ goto out2;
|
|
|
+ }
|
|
|
+ e->interp_file = f;
|
|
|
+ }
|
|
|
+
|
|
|
e->dentry = dget(dentry);
|
|
|
inode->i_private = e;
|
|
|
inode->i_fop = &bm_entry_operations;
|
|
@@ -713,7 +750,7 @@ out:
|
|
|
|
|
|
if (err) {
|
|
|
kfree(e);
|
|
|
- return -EINVAL;
|
|
|
+ return err;
|
|
|
}
|
|
|
return count;
|
|
|
}
|