patch-2.2.19 linux/fs/binfmt_misc.c
Next file: linux/fs/buffer.c
Previous file: linux/fs/binfmt_elf.c
Back to the patch index
Back to the overall index
- Lines: 591
- Date:
Sun Mar 25 11:37:38 2001
- Orig file:
v2.2.18/fs/binfmt_misc.c
- Orig date:
Sun Mar 25 11:28:33 2001
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/fs/binfmt_misc.c linux/fs/binfmt_misc.c
@@ -41,9 +41,11 @@
#error You really need /proc support for binfmt_misc. Please reconfigure!
#endif
-#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+enum {
+ VERBOSE_STATUS = 1 /* define as zero to save 400 bytes kernel memory */
+};
-struct binfmt_entry {
+typedef struct binfmt_entry {
struct binfmt_entry *next;
long id;
int flags; /* type, status, etc. */
@@ -52,16 +54,15 @@
char *magic; /* magic or filename extension */
char *mask; /* mask, NULL for exact match */
char *interpreter; /* filename of interpreter */
- char *proc_name;
+ char *name;
struct proc_dir_entry *proc_dir;
-};
+} Node;
-#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
-#define ENTRY_MAGIC 8 /* not filename detection */
+enum { Enabled, Magic };
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
-static void entry_proc_cleanup(struct binfmt_entry *e);
-static int entry_proc_setup(struct binfmt_entry *e);
+static void entry_proc_cleanup(Node *e);
+static int entry_proc_setup(Node *e);
static struct linux_binfmt misc_format = {
#ifndef MODULE
@@ -73,7 +74,7 @@
static struct proc_dir_entry *bm_dir = NULL;
-static struct binfmt_entry *entries = NULL;
+static Node *entries = NULL;
static int free_id = 1;
static int enabled = 1;
@@ -85,7 +86,7 @@
*/
static void clear_entry(int id)
{
- struct binfmt_entry **ep, *e;
+ Node **ep, *e;
write_lock(&entries_lock);
ep = &entries;
@@ -106,7 +107,7 @@
*/
static void clear_entries(void)
{
- struct binfmt_entry *e, *n;
+ Node *e, *n;
write_lock(&entries_lock);
n = entries;
@@ -123,9 +124,9 @@
/*
* Find entry through id and lock it
*/
-static struct binfmt_entry *get_entry(int id)
+static Node *get_entry(int id)
{
- struct binfmt_entry *e;
+ Node *e;
read_lock(&entries_lock);
e = entries;
@@ -139,7 +140,7 @@
/*
* unlock entry
*/
-static inline void put_entry(struct binfmt_entry *e)
+static inline void put_entry(Node *e)
{
if (e)
read_unlock(&entries_lock);
@@ -148,19 +149,19 @@
/*
* Check if we support the binfmt
- * if we do, return the binfmt_entry, else NULL
+ * if we do, return the node, else NULL
* locking is done in load_misc_binary
*/
-static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct linux_binprm *bprm)
{
- struct binfmt_entry *e;
+ Node *e;
char *p = strrchr(bprm->filename, '.');
int j;
e = entries;
while (e) {
- if (e->flags & ENTRY_ENABLED) {
- if (!(e->flags & ENTRY_MAGIC)) {
+ if (test_bit(Enabled, &e->flags)) {
+ if (!test_bit(Magic, &e->flags)) {
if (p && !strcmp(e->magic, p + 1))
return e;
} else {
@@ -183,7 +184,7 @@
*/
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
{
- struct binfmt_entry *fmt;
+ Node *fmt;
struct dentry * dentry;
char iname[128];
char *iname_addr = iname;
@@ -233,46 +234,44 @@
return retval;
}
-
-
-/*
- * /proc handling routines
- */
-
/*
* parses and copies one argument enclosed in del from *sp to *dp,
* recognising the \x special.
* returns pointer to the copied argument or NULL in case of an
* error (and sets err) or null argument length.
*/
-static char *copyarg(char **dp, const char **sp, int *count,
- char del, int special, int *err)
+static char *scanarg(char *s, char del)
{
- char c = 0, *res = *dp;
+ char c;
- while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
- switch (c) {
- case '\\':
- if (special && (**sp == 'x')) {
- if (!isxdigit(c = toupper(*(++*sp))))
- *err = -EINVAL;
- **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
- if (!isxdigit(c = toupper(*(++*sp))))
- *err = -EINVAL;
- *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
- ++*sp;
- *count -= 3;
- break;
- }
- default:
- *((*dp)++) = c;
+ while ((c = *s++) != del) {
+ if (c == '\\' && *s == 'x') {
+ s++;
+ if (!isxdigit(*s++))
+ return NULL;
+ if (!isxdigit(*s++))
+ return NULL;
+ }
+ }
+ return s;
+}
+
+static int unquote(char *from)
+{
+ char c = 0, *s = from, *p = from;
+
+ while ((c = *s++) != '\0') {
+ if (c == '\\' && *s == 'x') {
+ s++;
+ c = toupper(*s++);
+ *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
+ c = toupper(*s++);
+ *p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
+ continue;
}
+ *p++ = c;
}
- if (*err || (c != del) || (res == *dp))
- res = NULL;
- else if (!special)
- *((*dp)++) = '\0';
- return res;
+ return p - from;
}
/*
@@ -280,59 +279,197 @@
* ':name:type:offset:magic:mask:interpreter:'
* where the ':' is the IFS, that can be chosen with the first char
*/
-static int proc_write_register(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static Node *create_entry(const char *buffer, size_t count)
{
- const char *sp;
- char del, *dp;
- struct binfmt_entry *e;
- int memsize, cnt = count - 1, err;
+ Node *e;
+ int memsize, err;
+ char *buf, *p;
+ char del;
/* some sanity checks */
err = -EINVAL;
if ((count < 11) || (count > 256))
- goto _err;
+ goto out;
err = -ENOMEM;
- memsize = sizeof(struct binfmt_entry) + count;
- if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
- goto _err;
-
- err = 0;
- sp = buffer + 1;
- del = buffer[0];
- dp = (char *)e + sizeof(struct binfmt_entry);
-
- e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
-
- /* we can use bit 3 of type for ext/magic
- flag due to the nice encoding of E and M */
- if ((*sp & ~('E' | 'M')) || (sp[1] != del))
- err = -EINVAL;
- else
- e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
- cnt -= 2; sp++;
+ memsize = sizeof(Node) + count + 8;
+ e = (Node *) kmalloc(memsize, GFP_USER);
+ if (!e)
+ goto out;
- e->offset = 0;
- while (cnt-- && isdigit(*sp))
- e->offset = e->offset * 10 + *sp++ - '0';
- if (*sp++ != del)
- err = -EINVAL;
-
- e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
- e->size = dp - e->magic;
- e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
- if (e->mask && ((dp - e->mask) != e->size))
- err = -EINVAL;
- e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
- e->id = free_id++;
+ p = buf = (char *)e + sizeof(Node);
+
+ memset(e, 0, sizeof(Node));
+ if (copy_from_user(buf, buffer, count))
+ goto Efault;
+
+ del = *p++; /* delimeter */
+
+ memset(buf+count, del, 8);
+
+ e->name = p;
+ p = strchr(p, del);
+ if (!p)
+ goto Einval;
+ *p++ = '\0';
+ if (!e->name[0] ||
+ !strcmp(e->name, ".") ||
+ !strcmp(e->name, "..") ||
+ strchr(e->name, '/'))
+ goto Einval;
+ switch (*p++) {
+ case 'E': e->flags = 1<<Enabled; break;
+ case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
+ default: goto Einval;
+ }
+ if (*p++ != del)
+ goto Einval;
+ if (test_bit(Magic, &e->flags)) {
+ char *s = strchr(p, del);
+ if (!s)
+ goto Einval;
+ *s++ = '\0';
+ e->offset = simple_strtoul(p, &p, 10);
+ if (*p++)
+ goto Einval;
+ e->magic = p;
+ p = scanarg(p, del);
+ if (!p)
+ goto Einval;
+ p[-1] = '\0';
+ if (!e->magic[0])
+ goto Einval;
+ e->mask = p;
+ p = scanarg(p, del);
+ if (!p)
+ goto Einval;
+ p[-1] = '\0';
+ if (!e->mask[0])
+ e->mask = NULL;
+ e->size = unquote(e->magic);
+ if (e->mask && unquote(e->mask) != e->size)
+ goto Einval;
+ if (e->size + e->offset > 128)
+ goto Einval;
+ } else {
+ p = strchr(p, del);
+ if (!p)
+ goto Einval;
+ *p++ = '\0';
+ e->magic = p;
+ p = strchr(p, del);
+ if (!p)
+ goto Einval;
+ *p++ = '\0';
+ if (!e->magic[0] || strchr(e->magic, '/'))
+ goto Einval;
+ p = strchr(p, del);
+ if (!p)
+ goto Einval;
+ *p++ = '\0';
+ }
+ e->interpreter = p;
+ p = strchr(p, del);
+ if (!p)
+ goto Einval;
+ *p++ = '\0';
+ if (!e->interpreter[0])
+ goto Einval;
+
+ if (*p == '\n')
+ p++;
+ if (p != buf + count)
+ goto Einval;
+ return e;
+
+out:
+ return ERR_PTR(err);
+
+Efault:
+ kfree(e);
+ return ERR_PTR(-EFAULT);
+Einval:
+ kfree(e);
+ return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int parse_command(const char *buffer, size_t count)
+{
+ char s[4];
+
+ if (!count)
+ return 0;
+ if (count > 3)
+ return -EINVAL;
+ if (copy_from_user(s, buffer, count))
+ return -EFAULT;
+ if (s[count-1] == '\n')
+ count--;
+ if (count == 1 && s[0] == '0')
+ return 1;
+ if (count == 1 && s[0] == '1')
+ return 2;
+ if (count == 2 && s[0] == '-' && s[1] == '1')
+ return 3;
+ return -EINVAL;
+}
+
+static void entry_status(Node *e, char *page)
+{
+ char *dp;
+ char *status = "disabled";
- /* more sanity checks */
- if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
- (e->size < 1) || ((e->size + e->offset) > 127) ||
- !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
+ if (test_bit(Enabled, &e->flags))
+ status = "enabled";
+
+ if (!VERBOSE_STATUS) {
+ sprintf(page, "%s\n", status);
+ return;
+ }
+
+ sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
+ dp = page + strlen(page);
+ if (!test_bit(Magic, &e->flags)) {
+ sprintf(dp, "extension .%s\n", e->magic);
+ } else {
+ int i;
+
+ sprintf(dp, "offset %i\nmagic ", e->offset);
+ dp = page + strlen(page);
+ for (i = 0; i < e->size; i++) {
+ sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+ dp += 2;
+ }
+ if (e->mask) {
+ sprintf(dp, "\nmask ");
+ dp += 6;
+ for (i = 0; i < e->size; i++) {
+ sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+ dp += 2;
+ }
+ }
+ *dp++ = '\n';
+ *dp = '\0';
+ }
+}
+
+static int proc_write_register(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ Node *e = create_entry(buffer, count);
+ int err;
+
+ if (IS_ERR(e))
+ return PTR_ERR(e);
+
+ if (entry_proc_setup(e))
goto free_err;
+ e->id = free_id++;
write_lock(&entries_lock);
e->next = entries;
entries = e;
@@ -355,68 +492,24 @@
static int proc_read_status(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- struct binfmt_entry *e;
- char *dp;
- int elen, i, err;
+ Node *e;
+ int elen;
-#ifndef VERBOSE_STATUS
- if (data) {
- if (!(e = get_entry((int) data))) {
- err = -ENOENT;
- goto _err;
- }
- i = e->flags & ENTRY_ENABLED;
- put_entry(e);
- } else {
- i = enabled;
- }
- sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
-#else
- if (!data)
+ if (!data) {
sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
- else {
- if (!(e = get_entry((long) data))) {
- err = -ENOENT;
- goto _err;
- }
- sprintf(page, "%s\ninterpreter %s\n",
- (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
- e->interpreter);
- dp = page + strlen(page);
- if (!(e->flags & ENTRY_MAGIC)) {
- sprintf(dp, "extension .%s\n", e->magic);
- dp = page + strlen(page);
- } else {
- sprintf(dp, "offset %i\nmagic ", e->offset);
- dp = page + strlen(page);
- for (i = 0; i < e->size; i++) {
- sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
- dp += 2;
- }
- if (e->mask) {
- sprintf(dp, "\nmask ");
- dp += 6;
- for (i = 0; i < e->size; i++) {
- sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
- dp += 2;
- }
- }
- *dp++ = '\n';
- *dp = '\0';
- }
+ } else {
+ if (!(e = get_entry((long) data)))
+ return -ENOENT;
+ entry_status(e, page);
put_entry(e);
}
-#endif
elen = strlen(page) - off;
if (elen < 0)
elen = 0;
*eof = (elen <= count) ? 1 : 0;
*start = page + off;
- err = elen;
-
-_err:
- return err;
+ return elen;
}
/*
@@ -426,45 +519,50 @@
static int proc_write_status(struct file *file, const char *buffer,
unsigned long count, void *data)
{
- struct binfmt_entry *e;
- int res = count;
+ Node *e;
+ int res = parse_command(buffer, count);
- if (buffer[count-1] == '\n')
- count--;
- if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
- if (data) {
- if ((e = get_entry((long) data)))
- e->flags = (e->flags & ~ENTRY_ENABLED)
- | (int)(buffer[0] - '0');
- put_entry(e);
- } else {
- enabled = buffer[0] - '0';
- }
- } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
- if (data)
- clear_entry((long) data);
- else
- clear_entries();
- } else {
- res = -EINVAL;
+ switch(res) {
+ case 1: if (data) {
+ if ((e = get_entry((long) data)))
+ clear_bit(Enabled, &e->flags);
+ put_entry(e);
+ } else {
+ enabled = 0;
+ }
+ break;
+ case 2: if (data) {
+ if ((e = get_entry((long) data)))
+ set_bit(Enabled, &e->flags);
+ put_entry(e);
+ } else {
+ enabled = 1;
+ }
+ break;
+ case 3: if (data)
+ clear_entry((long) data);
+ else
+ clear_entries();
+ break;
+ default: return res;
}
- return res;
+ return count;
}
/*
* Remove the /proc-dir entries of one binfmt
*/
-static void entry_proc_cleanup(struct binfmt_entry *e)
+static void entry_proc_cleanup(Node *e)
{
- remove_proc_entry(e->proc_name, bm_dir);
+ remove_proc_entry(e->name, bm_dir);
}
/*
* Create the /proc-dir entry for binfmt
*/
-static int entry_proc_setup(struct binfmt_entry *e)
+static int entry_proc_setup(Node *e)
{
- if (!(e->proc_dir = create_proc_entry(e->proc_name,
+ if (!(e->proc_dir = create_proc_entry(e->name,
S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
{
printk(KERN_WARNING "Unable to create /proc entry.\n");
@@ -545,4 +643,3 @@
remove_proc_entry("sys/fs/binfmt_misc", NULL);
}
#endif
-#undef VERBOSE_STATUS
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)