- pre4:
[davej-history.git] / fs / binfmt_misc.c
blobc1653647946aff0116ada39469b193bb7982916e
1 /*
2 * binfmt_misc.c
4 * Copyright (C) 1997 Richard Günther
6 * binfmt_misc detects binaries via a magic or filename extension and invokes
7 * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
8 * binfmt_mz.
10 * 1997-04-25 first version
11 * [...]
12 * 1997-05-19 cleanup
13 * 1997-06-26 hpa: pass the real filename rather than argv[0]
14 * 1997-06-30 minor cleanup
15 * 1997-08-09 removed extension stripping, locking cleanup
18 #include <linux/config.h>
19 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/fs.h>
24 #include <linux/malloc.h>
25 #include <linux/binfmts.h>
26 #include <linux/init.h>
27 #include <linux/proc_fs.h>
28 #include <linux/string.h>
29 #include <linux/ctype.h>
30 #include <linux/file.h>
31 #include <linux/spinlock.h>
32 #include <asm/uaccess.h>
35 * We should make this work with a "stub-only" /proc,
36 * which would just not be able to be configured.
37 * Right now the /proc-fs support is too black and white,
38 * though, so just remind people that this should be
39 * fixed..
41 #ifndef CONFIG_PROC_FS
42 #error You really need /proc support for binfmt_misc. Please reconfigure!
43 #endif
45 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
47 struct binfmt_entry {
48 struct binfmt_entry *next;
49 long id;
50 int flags; /* type, status, etc. */
51 int offset; /* offset of magic */
52 int size; /* size of magic/mask */
53 char *magic; /* magic or filename extension */
54 char *mask; /* mask, NULL for exact match */
55 char *interpreter; /* filename of interpreter */
56 char *proc_name;
57 struct proc_dir_entry *proc_dir;
60 #define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
61 #define ENTRY_MAGIC 8 /* not filename detection */
63 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
64 static void entry_proc_cleanup(struct binfmt_entry *e);
65 static int entry_proc_setup(struct binfmt_entry *e);
67 static struct linux_binfmt misc_format = {
68 NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
71 static struct proc_dir_entry *bm_dir;
73 static struct binfmt_entry *entries;
74 static int free_id = 1;
75 static int enabled = 1;
77 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
81 * Unregister one entry
83 static void clear_entry(int id)
85 struct binfmt_entry **ep, *e;
87 write_lock(&entries_lock);
88 ep = &entries;
89 while (*ep && ((*ep)->id != id))
90 ep = &((*ep)->next);
91 if ((e = *ep))
92 *ep = e->next;
93 write_unlock(&entries_lock);
95 if (e) {
96 entry_proc_cleanup(e);
97 kfree(e);
102 * Clear all registered binary formats
104 static void clear_entries(void)
106 struct binfmt_entry *e, *n;
108 write_lock(&entries_lock);
109 n = entries;
110 entries = NULL;
111 write_unlock(&entries_lock);
113 while ((e = n)) {
114 n = e->next;
115 entry_proc_cleanup(e);
116 kfree(e);
121 * Find entry through id and lock it
123 static struct binfmt_entry *get_entry(int id)
125 struct binfmt_entry *e;
127 read_lock(&entries_lock);
128 e = entries;
129 while (e && (e->id != id))
130 e = e->next;
131 if (!e)
132 read_unlock(&entries_lock);
133 return e;
137 * unlock entry
139 static inline void put_entry(struct binfmt_entry *e)
141 if (e)
142 read_unlock(&entries_lock);
147 * Check if we support the binfmt
148 * if we do, return the binfmt_entry, else NULL
149 * locking is done in load_misc_binary
151 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
153 struct binfmt_entry *e;
154 char *p = strrchr(bprm->filename, '.');
155 int j;
157 e = entries;
158 while (e) {
159 if (e->flags & ENTRY_ENABLED) {
160 if (!(e->flags & ENTRY_MAGIC)) {
161 if (p && !strcmp(e->magic, p + 1))
162 return e;
163 } else {
164 j = 0;
165 while ((j < e->size) &&
166 !((bprm->buf[e->offset + j] ^ e->magic[j])
167 & (e->mask ? e->mask[j] : 0xff)))
168 j++;
169 if (j == e->size)
170 return e;
173 e = e->next;
175 return NULL;
179 * the loader itself
181 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
183 struct binfmt_entry *fmt;
184 struct file * file;
185 char iname[BINPRM_BUF_SIZE];
186 char *iname_addr = iname;
187 int retval;
189 retval = -ENOEXEC;
190 if (!enabled)
191 goto _ret;
193 /* to keep locking time low, we copy the interpreter string */
194 read_lock(&entries_lock);
195 fmt = check_file(bprm);
196 if (fmt) {
197 strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1);
198 iname[BINPRM_BUF_SIZE - 1] = '\0';
200 read_unlock(&entries_lock);
201 if (!fmt)
202 goto _ret;
204 allow_write_access(bprm->file);
205 fput(bprm->file);
206 bprm->file = NULL;
208 /* Build args for interpreter */
209 remove_arg_zero(bprm);
210 retval = copy_strings_kernel(1, &bprm->filename, bprm);
211 if (retval < 0) goto _ret;
212 bprm->argc++;
213 retval = copy_strings_kernel(1, &iname_addr, bprm);
214 if (retval < 0) goto _ret;
215 bprm->argc++;
216 bprm->filename = iname; /* for binfmt_script */
218 file = open_exec(iname);
219 retval = PTR_ERR(file);
220 if (IS_ERR(file))
221 goto _ret;
222 bprm->file = file;
224 retval = prepare_binprm(bprm);
225 if (retval >= 0)
226 retval = search_binary_handler(bprm, regs);
227 _ret:
228 return retval;
234 * /proc handling routines
238 * parses and copies one argument enclosed in del from *sp to *dp,
239 * recognising the \x special.
240 * returns pointer to the copied argument or NULL in case of an
241 * error (and sets err) or null argument length.
243 static char *copyarg(char **dp, const char **sp, int *count,
244 char del, int special, int *err)
246 char c = 0, *res = *dp;
248 while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
249 switch (c) {
250 case '\\':
251 if (special && (**sp == 'x')) {
252 if (!isxdigit(c = toupper(*(++*sp))))
253 *err = -EINVAL;
254 **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
255 if (!isxdigit(c = toupper(*(++*sp))))
256 *err = -EINVAL;
257 *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
258 ++*sp;
259 *count -= 3;
260 break;
262 default:
263 *((*dp)++) = c;
266 if (*err || (c != del) || (res == *dp))
267 res = NULL;
268 else if (!special)
269 *((*dp)++) = '\0';
270 return res;
274 * This registers a new binary format, it recognises the syntax
275 * ':name:type:offset:magic:mask:interpreter:'
276 * where the ':' is the IFS, that can be chosen with the first char
278 static int proc_write_register(struct file *file, const char *buffer,
279 unsigned long count, void *data)
281 const char *sp;
282 char del, *dp;
283 struct binfmt_entry *e;
284 int memsize, cnt = count - 1, err;
286 /* some sanity checks */
287 err = -EINVAL;
288 if ((count < 11) || (count > 256))
289 goto _err;
291 err = -ENOMEM;
292 memsize = sizeof(struct binfmt_entry) + count;
293 if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
294 goto _err;
296 err = 0;
297 sp = buffer + 1;
298 del = buffer[0];
299 dp = (char *)e + sizeof(struct binfmt_entry);
301 e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
303 /* we can use bit 3 of type for ext/magic
304 flag due to the nice encoding of E and M */
305 if ((*sp & ~('E' | 'M')) || (sp[1] != del))
306 err = -EINVAL;
307 else
308 e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
309 cnt -= 2; sp++;
311 e->offset = 0;
312 while (cnt-- && isdigit(*sp))
313 e->offset = e->offset * 10 + *sp++ - '0';
314 if (*sp++ != del)
315 err = -EINVAL;
317 e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
318 e->size = dp - e->magic;
319 e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
320 if (e->mask && ((dp - e->mask) != e->size))
321 err = -EINVAL;
322 e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
323 e->id = free_id++;
325 /* more sanity checks */
326 if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
327 (e->size < 1) || ((e->size + e->offset) > (BINPRM_BUF_SIZE - 1)) ||
328 !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
329 goto free_err;
331 write_lock(&entries_lock);
332 e->next = entries;
333 entries = e;
334 write_unlock(&entries_lock);
336 err = count;
337 _err:
338 return err;
339 free_err:
340 kfree(e);
341 err = -EINVAL;
342 goto _err;
346 * Get status of entry/binfmt_misc
347 * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
348 * entry is enabled?
350 static int proc_read_status(char *page, char **start, off_t off,
351 int count, int *eof, void *data)
353 struct binfmt_entry *e;
354 char *dp;
355 int elen, i, err;
357 #ifndef VERBOSE_STATUS
358 if (data) {
359 if (!(e = get_entry((int) data))) {
360 err = -ENOENT;
361 goto _err;
363 i = e->flags & ENTRY_ENABLED;
364 put_entry(e);
365 } else {
366 i = enabled;
368 sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
369 #else
370 if (!data)
371 sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
372 else {
373 if (!(e = get_entry((long) data))) {
374 err = -ENOENT;
375 goto _err;
377 sprintf(page, "%s\ninterpreter %s\n",
378 (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
379 e->interpreter);
380 dp = page + strlen(page);
381 if (!(e->flags & ENTRY_MAGIC)) {
382 sprintf(dp, "extension .%s\n", e->magic);
383 dp = page + strlen(page);
384 } else {
385 sprintf(dp, "offset %i\nmagic ", e->offset);
386 dp = page + strlen(page);
387 for (i = 0; i < e->size; i++) {
388 sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
389 dp += 2;
391 if (e->mask) {
392 sprintf(dp, "\nmask ");
393 dp += 6;
394 for (i = 0; i < e->size; i++) {
395 sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
396 dp += 2;
399 *dp++ = '\n';
400 *dp = '\0';
402 put_entry(e);
404 #endif
406 elen = strlen(page) - off;
407 if (elen < 0)
408 elen = 0;
409 *eof = (elen <= count) ? 1 : 0;
410 *start = page + off;
411 err = elen;
413 _err:
414 return err;
418 * Set status of entry/binfmt_misc:
419 * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
421 static int proc_write_status(struct file *file, const char *buffer,
422 unsigned long count, void *data)
424 struct binfmt_entry *e;
425 int res = count;
427 if (buffer[count-1] == '\n')
428 count--;
429 if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
430 if (data) {
431 if ((e = get_entry((long) data)))
432 e->flags = (e->flags & ~ENTRY_ENABLED)
433 | (int)(buffer[0] - '0');
434 put_entry(e);
435 } else {
436 enabled = buffer[0] - '0';
438 } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
439 if (data)
440 clear_entry((long) data);
441 else
442 clear_entries();
443 } else {
444 res = -EINVAL;
446 return res;
450 * Remove the /proc-dir entries of one binfmt
452 static void entry_proc_cleanup(struct binfmt_entry *e)
454 remove_proc_entry(e->proc_name, bm_dir);
458 * Create the /proc-dir entry for binfmt
460 static int entry_proc_setup(struct binfmt_entry *e)
462 if (!(e->proc_dir = create_proc_entry(e->proc_name,
463 S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
465 printk(KERN_WARNING "Unable to create /proc entry.\n");
466 return -ENOENT;
468 e->proc_dir->data = (void *) (e->id);
469 e->proc_dir->read_proc = proc_read_status;
470 e->proc_dir->write_proc = proc_write_status;
471 return 0;
474 static int __init init_misc_binfmt(void)
476 int error = -ENOENT;
477 struct proc_dir_entry *status = NULL, *reg;
479 bm_dir = proc_mkdir("sys/fs/binfmt_misc", NULL); /* WTF??? */
480 if (!bm_dir)
481 goto out;
482 bm_dir->owner = THIS_MODULE;
484 status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
485 bm_dir);
486 if (!status)
487 goto cleanup_bm;
488 status->read_proc = proc_read_status;
489 status->write_proc = proc_write_status;
491 reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
492 if (!reg)
493 goto cleanup_status;
494 reg->write_proc = proc_write_register;
496 error = register_binfmt(&misc_format);
497 out:
498 return error;
500 cleanup_status:
501 remove_proc_entry("status", bm_dir);
502 cleanup_bm:
503 remove_proc_entry("sys/fs/binfmt_misc", NULL);
504 goto out;
507 static void __exit exit_misc_binfmt(void)
509 unregister_binfmt(&misc_format);
510 remove_proc_entry("register", bm_dir);
511 remove_proc_entry("status", bm_dir);
512 clear_entries();
513 remove_proc_entry("sys/fs/binfmt_misc", NULL);
516 EXPORT_NO_SYMBOLS;
518 module_init(init_misc_binfmt);
519 module_exit(exit_misc_binfmt);