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
10 * 1997-04-25 first version
13 * 1997-06-26 hpa: pass the real filename rather than argv[0]
14 * 1997-06-30 minor cleanup
17 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
22 #include <linux/malloc.h>
23 #include <linux/binfmts.h>
24 #include <linux/init.h>
25 #include <linux/proc_fs.h>
26 #include <linux/string.h>
27 #include <linux/ctype.h>
28 #include <asm/uaccess.h>
29 #include <asm/spinlock.h>
32 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
35 #define MIN(x,y) (((x)<(y))?(x):(y))
39 struct binfmt_entry
*next
;
41 int flags
; /* type, status, etc. */
42 int offset
; /* offset of magic */
43 int size
; /* size of magic/mask */
44 char *magic
; /* magic or filename extension */
45 char *mask
; /* mask, NULL for exact match */
46 char *interpreter
; /* filename of interpreter */
48 struct proc_dir_entry
*proc_dir
;
51 #define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
52 #define ENTRY_MAGIC 8 /* not filename detection */
53 #define ENTRY_STRIP_EXT 32 /* strip off last filename extension */
55 static int load_misc_binary(struct linux_binprm
*bprm
, struct pt_regs
*regs
);
56 static void entry_proc_cleanup(struct binfmt_entry
*e
);
57 static int entry_proc_setup(struct binfmt_entry
*e
);
59 static struct linux_binfmt misc_format
= {
61 NULL
, 0, load_misc_binary
, NULL
, NULL
63 NULL
, &__this_module
, load_misc_binary
, NULL
, NULL
67 static struct proc_dir_entry
*bm_dir
= NULL
;
69 static struct binfmt_entry
*entries
= NULL
;
70 static int free_id
= 1;
71 static int enabled
= 1;
73 static rwlock_t entries_lock
= RW_LOCK_UNLOCKED
;
77 * Unregister one entry
79 static void clear_entry(int id
)
81 struct binfmt_entry
**ep
, *e
;
83 write_lock(&entries_lock
);
85 while (*ep
&& ((*ep
)->id
!= id
))
89 entry_proc_cleanup(e
);
92 write_unlock(&entries_lock
);
96 * Clear all registered binary formats
98 static void clear_entries(void)
100 struct binfmt_entry
*e
;
102 write_lock(&entries_lock
);
103 while ((e
= entries
)) {
104 entries
= entries
->next
;
105 entry_proc_cleanup(e
);
108 write_unlock(&entries_lock
);
112 * Find entry through id - caller has to do locking
114 static struct binfmt_entry
*get_entry(int id
)
116 struct binfmt_entry
*e
= entries
;
118 while (e
&& (e
->id
!= id
))
125 * Check if we support the binfmt
126 * if we do, return the binfmt_entry, else NULL
127 * locking is done in load_misc_binary
129 static struct binfmt_entry
*check_file(struct linux_binprm
*bprm
)
131 struct binfmt_entry
*e
= entries
;
132 char *p
= strrchr(bprm
->filename
, '.');
136 if (e
->flags
& ENTRY_ENABLED
) {
137 if (!(e
->flags
& ENTRY_MAGIC
)) {
138 if (p
&& !strcmp(e
->magic
, p
+ 1))
142 while ((j
< e
->size
) &&
143 !((bprm
->buf
[e
->offset
+ j
] ^ e
->magic
[j
])
144 & (e
->mask
? e
->mask
[j
] : 0xff)))
158 static int load_misc_binary(struct linux_binprm
*bprm
, struct pt_regs
*regs
)
160 struct binfmt_entry
*fmt
;
161 struct dentry
* dentry
;
163 char *iname_addr
= iname
, *p
;
164 int retval
, fmt_flags
= 0;
172 /* to keep locking time low, we copy the interpreter string */
173 read_lock(&entries_lock
);
174 if ((fmt
= check_file(bprm
))) {
175 strncpy(iname
, fmt
->interpreter
, 127);
177 fmt_flags
= fmt
->flags
;
179 read_unlock(&entries_lock
);
188 /* Build args for interpreter */
189 if ((fmt_flags
& ENTRY_STRIP_EXT
) &&
190 (p
= strrchr(bprm
->filename
, '.')))
192 remove_arg_zero(bprm
);
193 bprm
->p
= copy_strings(1, &bprm
->filename
, bprm
->page
, bprm
->p
, 2);
195 bprm
->p
= copy_strings(1, &iname_addr
, bprm
->page
, bprm
->p
, 2);
201 bprm
->filename
= iname
; /* for binfmt_script */
203 dentry
= open_namei(iname
, 0, 0);
204 retval
= PTR_ERR(dentry
);
207 bprm
->dentry
= dentry
;
209 retval
= prepare_binprm(bprm
);
211 retval
= search_binary_handler(bprm
, regs
);
220 * /proc handling routines
224 * parses and copies one argument enclosed in del from *sp to *dp,
225 * recognising the \x special.
226 * returns pointer to the copied argument or NULL in case of an
227 * error (and sets err) or null argument length.
229 static char *copyarg(char **dp
, const char **sp
, int *count
,
230 char del
, int special
, int *err
)
234 while (!*err
&& ((c
= *((*sp
)++)), (*count
)--) && (c
!= del
)) {
237 if (special
&& (**sp
== 'x')) {
238 if (!isxdigit(c
= toupper(*(++*sp
))))
240 **dp
= (c
- (isdigit(c
) ? '0' : 'A' - 10)) * 16;
241 if (!isxdigit(c
= toupper(*(++*sp
))))
243 *((*dp
)++) += c
- (isdigit(c
) ? '0' : 'A' - 10);
252 if (*err
|| (c
!= del
) || (res
== *dp
))
260 * This registers a new binary format, it recognises the syntax
261 * ':name:type:offset:magic:mask:interpreter:'
262 * where the ':' is the IFS, that can be chosen with the first char
264 static int proc_write_register(struct file
*file
, const char *buffer
,
265 unsigned long count
, void *data
)
269 struct binfmt_entry
*e
;
270 int memsize
, cnt
= count
- 1, err
= 0;
273 /* some sanity checks */
274 if ((count
< 11) || (count
> 256)) {
279 memsize
= sizeof(struct binfmt_entry
) + count
;
280 if (!(e
= (struct binfmt_entry
*) kmalloc(memsize
, GFP_USER
))) {
287 dp
= (char *)e
+ sizeof(struct binfmt_entry
);
289 e
->proc_name
= copyarg(&dp
, &sp
, &cnt
, del
, 0, &err
);
291 /* we can use bit 3 and 5 of type for ext/magic and ext-strip
292 flag due to the nice encoding of E, M, e and m */
293 if ((*sp
& 0x92) || (sp
[1] != del
))
296 e
->flags
= (*sp
++ & (ENTRY_MAGIC
| ENTRY_STRIP_EXT
))
301 while (cnt
-- && isdigit(*sp
))
302 e
->offset
= e
->offset
* 10 + *sp
++ - '0';
306 e
->magic
= copyarg(&dp
, &sp
, &cnt
, del
, (e
->flags
& ENTRY_MAGIC
), &err
);
307 e
->size
= dp
- e
->magic
;
308 e
->mask
= copyarg(&dp
, &sp
, &cnt
, del
, 1, &err
);
309 if (e
->mask
&& ((dp
- e
->mask
) != e
->size
))
311 e
->interpreter
= copyarg(&dp
, &sp
, &cnt
, del
, 0, &err
);
314 /* more sanity checks */
315 if (err
|| !(!cnt
|| (!(--cnt
) && (*sp
== '\n'))) ||
316 (e
->size
< 1) || ((e
->size
+ e
->offset
) > 127) ||
317 !(e
->proc_name
) || !(e
->interpreter
) ||
318 entry_proc_setup(e
)) {
324 write_lock(&entries_lock
);
327 write_unlock(&entries_lock
);
336 * Get status of entry/binfmt_misc
337 * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
340 static int proc_read_status(char *page
, char **start
, off_t off
,
341 int count
, int *eof
, void *data
)
343 struct binfmt_entry
*e
;
348 #ifndef VERBOSE_STATUS
350 read_lock(&entries_lock
);
351 if (!(e
= get_entry((int) data
)))
354 i
= e
->flags
& ENTRY_ENABLED
;
355 read_unlock(&entries_lock
);
359 sprintf(page
, "%s\n", (i
? "enabled" : "disabled"));
362 sprintf(page
, "%s\n", (enabled
? "enabled" : "disabled"));
364 read_lock(&entries_lock
);
365 if (!(e
= get_entry((int) data
))) {
369 sprintf(page
, "%s\ninterpreter %s\n",
370 (e
->flags
& ENTRY_ENABLED
? "enabled" : "disabled"),
372 dp
= page
+ strlen(page
);
373 if (!(e
->flags
& ENTRY_MAGIC
)) {
374 sprintf(dp
, "extension .%s\n", e
->magic
);
375 dp
= page
+ strlen(page
);
377 sprintf(dp
, "offset %i\nmagic ", e
->offset
);
378 dp
= page
+ strlen(page
);
379 for (i
= 0; i
< e
->size
; i
++) {
380 sprintf(dp
, "%02x", 0xff & (int) (e
->magic
[i
]));
384 sprintf(dp
, "\nmask ");
386 for (i
= 0; i
< e
->size
; i
++) {
387 sprintf(dp
, "%02x", 0xff & (int) (e
->mask
[i
]));
394 if (e
->flags
& ENTRY_STRIP_EXT
)
395 sprintf(dp
, "extension stripped\n");
397 read_unlock(&entries_lock
);
401 elen
= strlen(page
) - off
;
404 *eof
= (elen
<= count
) ? 1 : 0;
412 * Set status of entry/binfmt_misc:
413 * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
415 static int proc_write_status(struct file
*file
, const char *buffer
,
416 unsigned long count
, void *data
)
418 struct binfmt_entry
*e
;
422 if (((buffer
[0] == '1') || (buffer
[0] == '0')) &&
423 ((count
== 1) || ((count
== 2) && (buffer
[1] == '\n')))) {
425 read_lock(&entries_lock
);
426 if ((e
= get_entry((int) data
)))
427 e
->flags
= (e
->flags
& -2) | (int) (buffer
[0] - '0');
428 read_unlock(&entries_lock
);
430 enabled
= buffer
[0] - '0';
432 } else if ((buffer
[0] == '-') && (buffer
[1] == '1') &&
433 ((count
== 2) || ((count
== 3) && (buffer
[2] == '\n')))) {
435 clear_entry((int) data
);
446 * Remove the /proc-dir entries of one binfmt
448 static void entry_proc_cleanup(struct binfmt_entry
*e
)
450 remove_proc_entry(e
->proc_name
, bm_dir
);
454 * Create the /proc-dir entry for binfmt
456 static int entry_proc_setup(struct binfmt_entry
*e
)
458 if (!(e
->proc_dir
= create_proc_entry(e
->proc_name
,
459 S_IFREG
| S_IRUGO
| S_IWUSR
, bm_dir
)))
462 e
->proc_dir
->data
= (void *) (e
->id
);
463 e
->proc_dir
->read_proc
= proc_read_status
;
464 e
->proc_dir
->write_proc
= proc_write_status
;
470 __initfunc(int init_misc_binfmt(void))
472 struct proc_dir_entry
*status
= NULL
, *reg
;
474 if (!(bm_dir
= create_proc_entry("sys/fs/binfmt_misc", S_IFDIR
,
476 !(status
= create_proc_entry("status", S_IFREG
| S_IRUGO
| S_IWUSR
,
478 !(reg
= create_proc_entry("register", S_IFREG
| S_IWUSR
,
481 remove_proc_entry("status", bm_dir
);
483 remove_proc_entry("sys/fs/binfmt_misc", NULL
);
486 status
->read_proc
= proc_read_status
;
487 status
->write_proc
= proc_write_status
;
489 reg
->write_proc
= proc_write_register
;
491 return register_binfmt(&misc_format
);
496 int init_module(void)
498 return init_misc_binfmt();
501 void cleanup_module(void)
503 unregister_binfmt(&misc_format
);
504 remove_proc_entry("register", bm_dir
);
505 remove_proc_entry("status", bm_dir
);
507 remove_proc_entry("sys/fs/binfmt_misc", NULL
);
510 #undef VERBOSE_STATUS