Linux 2.2.0
[davej-history.git] / fs / binfmt_misc.c
blobcb062d5b10769fa2b48d9ef9d6ef9c19c50282d5
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 <asm/uaccess.h>
31 #include <asm/spinlock.h>
34 * We should make this work with a "stub-only" /proc,
35 * which would just not be able to be configured.
36 * Right now the /proc-fs support is too black and white,
37 * though, so just remind people that this should be
38 * fixed..
40 #ifndef CONFIG_PROC_FS
41 #error You really need /proc support for binfmt_misc. Please reconfigure!
42 #endif
44 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
46 struct binfmt_entry {
47 struct binfmt_entry *next;
48 long id;
49 int flags; /* type, status, etc. */
50 int offset; /* offset of magic */
51 int size; /* size of magic/mask */
52 char *magic; /* magic or filename extension */
53 char *mask; /* mask, NULL for exact match */
54 char *interpreter; /* filename of interpreter */
55 char *proc_name;
56 struct proc_dir_entry *proc_dir;
59 #define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
60 #define ENTRY_MAGIC 8 /* not filename detection */
62 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
63 static void entry_proc_cleanup(struct binfmt_entry *e);
64 static int entry_proc_setup(struct binfmt_entry *e);
66 static struct linux_binfmt misc_format = {
67 #ifndef MODULE
68 NULL, 0, load_misc_binary, NULL, NULL
69 #else
70 NULL, &__this_module, load_misc_binary, NULL, NULL
71 #endif
74 static struct proc_dir_entry *bm_dir = NULL;
76 static struct binfmt_entry *entries = NULL;
77 static int free_id = 1;
78 static int enabled = 1;
80 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
84 * Unregister one entry
86 static void clear_entry(int id)
88 struct binfmt_entry **ep, *e;
90 write_lock(&entries_lock);
91 ep = &entries;
92 while (*ep && ((*ep)->id != id))
93 ep = &((*ep)->next);
94 if ((e = *ep))
95 *ep = e->next;
96 write_unlock(&entries_lock);
98 if (e) {
99 entry_proc_cleanup(e);
100 kfree(e);
105 * Clear all registered binary formats
107 static void clear_entries(void)
109 struct binfmt_entry *e, *n;
111 write_lock(&entries_lock);
112 n = entries;
113 entries = NULL;
114 write_unlock(&entries_lock);
116 while ((e = n)) {
117 n = e->next;
118 entry_proc_cleanup(e);
119 kfree(e);
124 * Find entry through id and lock it
126 static struct binfmt_entry *get_entry(int id)
128 struct binfmt_entry *e;
130 read_lock(&entries_lock);
131 e = entries;
132 while (e && (e->id != id))
133 e = e->next;
134 if (!e)
135 read_unlock(&entries_lock);
136 return e;
140 * unlock entry
142 static inline void put_entry(struct binfmt_entry *e)
144 if (e)
145 read_unlock(&entries_lock);
150 * Check if we support the binfmt
151 * if we do, return the binfmt_entry, else NULL
152 * locking is done in load_misc_binary
154 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
156 struct binfmt_entry *e;
157 char *p = strrchr(bprm->filename, '.');
158 int j;
160 e = entries;
161 while (e) {
162 if (e->flags & ENTRY_ENABLED) {
163 if (!(e->flags & ENTRY_MAGIC)) {
164 if (p && !strcmp(e->magic, p + 1))
165 return e;
166 } else {
167 j = 0;
168 while ((j < e->size) &&
169 !((bprm->buf[e->offset + j] ^ e->magic[j])
170 & (e->mask ? e->mask[j] : 0xff)))
171 j++;
172 if (j == e->size)
173 return e;
176 e = e->next;
178 return NULL;
182 * the loader itself
184 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
186 struct binfmt_entry *fmt;
187 struct dentry * dentry;
188 char iname[128];
189 char *iname_addr = iname;
190 int retval;
192 MOD_INC_USE_COUNT;
193 retval = -ENOEXEC;
194 if (!enabled)
195 goto _ret;
197 /* to keep locking time low, we copy the interpreter string */
198 read_lock(&entries_lock);
199 fmt = check_file(bprm);
200 if (fmt) {
201 strncpy(iname, fmt->interpreter, 127);
202 iname[127] = '\0';
204 read_unlock(&entries_lock);
205 if (!fmt)
206 goto _ret;
208 dput(bprm->dentry);
209 bprm->dentry = NULL;
211 /* Build args for interpreter */
212 remove_arg_zero(bprm);
213 bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
214 bprm->argc++;
215 bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
216 bprm->argc++;
217 retval = -E2BIG;
218 if (!bprm->p)
219 goto _ret;
220 bprm->filename = iname; /* for binfmt_script */
222 dentry = open_namei(iname, 0, 0);
223 retval = PTR_ERR(dentry);
224 if (IS_ERR(dentry))
225 goto _ret;
226 bprm->dentry = dentry;
228 retval = prepare_binprm(bprm);
229 if (retval >= 0)
230 retval = search_binary_handler(bprm, regs);
231 _ret:
232 MOD_DEC_USE_COUNT;
233 return retval;
239 * /proc handling routines
243 * parses and copies one argument enclosed in del from *sp to *dp,
244 * recognising the \x special.
245 * returns pointer to the copied argument or NULL in case of an
246 * error (and sets err) or null argument length.
248 static char *copyarg(char **dp, const char **sp, int *count,
249 char del, int special, int *err)
251 char c = 0, *res = *dp;
253 while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
254 switch (c) {
255 case '\\':
256 if (special && (**sp == 'x')) {
257 if (!isxdigit(c = toupper(*(++*sp))))
258 *err = -EINVAL;
259 **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
260 if (!isxdigit(c = toupper(*(++*sp))))
261 *err = -EINVAL;
262 *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
263 ++*sp;
264 *count -= 3;
265 break;
267 default:
268 *((*dp)++) = c;
271 if (*err || (c != del) || (res == *dp))
272 res = NULL;
273 else if (!special)
274 *((*dp)++) = '\0';
275 return res;
279 * This registers a new binary format, it recognises the syntax
280 * ':name:type:offset:magic:mask:interpreter:'
281 * where the ':' is the IFS, that can be chosen with the first char
283 static int proc_write_register(struct file *file, const char *buffer,
284 unsigned long count, void *data)
286 const char *sp;
287 char del, *dp;
288 struct binfmt_entry *e;
289 int memsize, cnt = count - 1, err;
291 /* some sanity checks */
292 err = -EINVAL;
293 if ((count < 11) || (count > 256))
294 goto _err;
296 err = -ENOMEM;
297 memsize = sizeof(struct binfmt_entry) + count;
298 if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
299 goto _err;
301 err = 0;
302 sp = buffer + 1;
303 del = buffer[0];
304 dp = (char *)e + sizeof(struct binfmt_entry);
306 e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
308 /* we can use bit 3 of type for ext/magic
309 flag due to the nice encoding of E and M */
310 if ((*sp & ~('E' | 'M')) || (sp[1] != del))
311 err = -EINVAL;
312 else
313 e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
314 cnt -= 2; sp++;
316 e->offset = 0;
317 while (cnt-- && isdigit(*sp))
318 e->offset = e->offset * 10 + *sp++ - '0';
319 if (*sp++ != del)
320 err = -EINVAL;
322 e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
323 e->size = dp - e->magic;
324 e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
325 if (e->mask && ((dp - e->mask) != e->size))
326 err = -EINVAL;
327 e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
328 e->id = free_id++;
330 /* more sanity checks */
331 if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
332 (e->size < 1) || ((e->size + e->offset) > 127) ||
333 !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
334 goto free_err;
336 write_lock(&entries_lock);
337 e->next = entries;
338 entries = e;
339 write_unlock(&entries_lock);
341 err = count;
342 _err:
343 return err;
344 free_err:
345 kfree(e);
346 err = -EINVAL;
347 goto _err;
351 * Get status of entry/binfmt_misc
352 * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
353 * entry is enabled?
355 static int proc_read_status(char *page, char **start, off_t off,
356 int count, int *eof, void *data)
358 struct binfmt_entry *e;
359 char *dp;
360 int elen, i, err;
362 #ifndef VERBOSE_STATUS
363 if (data) {
364 if (!(e = get_entry((int) data))) {
365 err = -ENOENT;
366 goto _err;
368 i = e->flags & ENTRY_ENABLED;
369 put_entry(e);
370 } else {
371 i = enabled;
373 sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
374 #else
375 if (!data)
376 sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
377 else {
378 if (!(e = get_entry((long) data))) {
379 err = -ENOENT;
380 goto _err;
382 sprintf(page, "%s\ninterpreter %s\n",
383 (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
384 e->interpreter);
385 dp = page + strlen(page);
386 if (!(e->flags & ENTRY_MAGIC)) {
387 sprintf(dp, "extension .%s\n", e->magic);
388 dp = page + strlen(page);
389 } else {
390 sprintf(dp, "offset %i\nmagic ", e->offset);
391 dp = page + strlen(page);
392 for (i = 0; i < e->size; i++) {
393 sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
394 dp += 2;
396 if (e->mask) {
397 sprintf(dp, "\nmask ");
398 dp += 6;
399 for (i = 0; i < e->size; i++) {
400 sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
401 dp += 2;
404 *dp++ = '\n';
405 *dp = '\0';
407 put_entry(e);
409 #endif
411 elen = strlen(page) - off;
412 if (elen < 0)
413 elen = 0;
414 *eof = (elen <= count) ? 1 : 0;
415 *start = page + off;
416 err = elen;
418 _err:
419 return err;
423 * Set status of entry/binfmt_misc:
424 * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
426 static int proc_write_status(struct file *file, const char *buffer,
427 unsigned long count, void *data)
429 struct binfmt_entry *e;
430 int res = count;
432 if (buffer[count-1] == '\n')
433 count--;
434 if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
435 if (data) {
436 if ((e = get_entry((long) data)))
437 e->flags = (e->flags & ~ENTRY_ENABLED)
438 | (int)(buffer[0] - '0');
439 put_entry(e);
440 } else {
441 enabled = buffer[0] - '0';
443 } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
444 if (data)
445 clear_entry((long) data);
446 else
447 clear_entries();
448 } else {
449 res = -EINVAL;
451 return res;
455 * Remove the /proc-dir entries of one binfmt
457 static void entry_proc_cleanup(struct binfmt_entry *e)
459 remove_proc_entry(e->proc_name, bm_dir);
463 * Create the /proc-dir entry for binfmt
465 static int entry_proc_setup(struct binfmt_entry *e)
467 if (!(e->proc_dir = create_proc_entry(e->proc_name,
468 S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
470 printk(KERN_WARNING "Unable to create /proc entry.\n");
471 return -ENOENT;
473 e->proc_dir->data = (void *) (e->id);
474 e->proc_dir->read_proc = proc_read_status;
475 e->proc_dir->write_proc = proc_write_status;
476 return 0;
479 #ifdef MODULE
481 * This is called as the fill_inode function when an inode
482 * is going into (fill = 1) or out of service (fill = 0).
483 * We use it here to manage the module use counts.
485 * Note: only the top-level directory needs to do this; if
486 * a lower level is referenced, the parent will be as well.
488 static void bm_modcount(struct inode *inode, int fill)
490 if (fill)
491 MOD_INC_USE_COUNT;
492 else
493 MOD_DEC_USE_COUNT;
495 #endif
497 int __init init_misc_binfmt(void)
499 int error = -ENOENT;
500 struct proc_dir_entry *status = NULL, *reg;
502 bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
503 if (!bm_dir)
504 goto out;
505 #ifdef MODULE
506 bm_dir->fill_inode = bm_modcount;
507 #endif
509 status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
510 bm_dir);
511 if (!status)
512 goto cleanup_bm;
513 status->read_proc = proc_read_status;
514 status->write_proc = proc_write_status;
516 reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
517 if (!reg)
518 goto cleanup_status;
519 reg->write_proc = proc_write_register;
521 error = register_binfmt(&misc_format);
522 out:
523 return error;
525 cleanup_status:
526 remove_proc_entry("status", bm_dir);
527 cleanup_bm:
528 remove_proc_entry("sys/fs/binfmt_misc", NULL);
529 goto out;
532 #ifdef MODULE
533 EXPORT_NO_SYMBOLS;
534 int init_module(void)
536 return init_misc_binfmt();
539 void cleanup_module(void)
541 unregister_binfmt(&misc_format);
542 remove_proc_entry("register", bm_dir);
543 remove_proc_entry("status", bm_dir);
544 clear_entries();
545 remove_proc_entry("sys/fs/binfmt_misc", NULL);
547 #endif
548 #undef VERBOSE_STATUS