Import 2.3.18pre1
[davej-history.git] / fs / binfmt_misc.c
blob6143bd5d0f8384f445fe43ed3562b1b5a4aa9541
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/spinlock.h>
31 #include <asm/uaccess.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 intload_misc_binary(struct linux_binprm *bprm,struct pt_regs *regs);
63 static voidentry_proc_cleanup(struct binfmt_entry *e);
64 static intentry_proc_setup(struct binfmt_entry *e);
66 static struct linux_binfmt misc_format = {
67 NULL, THIS_MODULE, load_misc_binary, NULL, NULL,0
70 static struct proc_dir_entry *bm_dir = NULL;
72 static struct binfmt_entry *entries = NULL;
73 static int free_id =1;
74 static int enabled =1;
76 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
80 * Unregister one entry
82 static voidclear_entry(int id)
84 struct binfmt_entry **ep, *e;
86 write_lock(&entries_lock);
87 ep = &entries;
88 while(*ep && ((*ep)->id != id))
89 ep = &((*ep)->next);
90 if((e = *ep))
91 *ep = e->next;
92 write_unlock(&entries_lock);
94 if(e) {
95 entry_proc_cleanup(e);
96 kfree(e);
101 * Clear all registered binary formats
103 static voidclear_entries(void)
105 struct binfmt_entry *e, *n;
107 write_lock(&entries_lock);
108 n = entries;
109 entries = NULL;
110 write_unlock(&entries_lock);
112 while((e = n)) {
113 n = e->next;
114 entry_proc_cleanup(e);
115 kfree(e);
120 * Find entry through id and lock it
122 static struct binfmt_entry *get_entry(int id)
124 struct binfmt_entry *e;
126 read_lock(&entries_lock);
127 e = entries;
128 while(e && (e->id != id))
129 e = e->next;
130 if(!e)
131 read_unlock(&entries_lock);
132 return e;
136 * unlock entry
138 staticinlinevoidput_entry(struct binfmt_entry *e)
140 if(e)
141 read_unlock(&entries_lock);
146 * Check if we support the binfmt
147 * if we do, return the binfmt_entry, else NULL
148 * locking is done in load_misc_binary
150 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
152 struct binfmt_entry *e;
153 char*p =strrchr(bprm->filename,'.');
154 int j;
156 e = entries;
157 while(e) {
158 if(e->flags & ENTRY_ENABLED) {
159 if(!(e->flags & ENTRY_MAGIC)) {
160 if(p && !strcmp(e->magic, p +1))
161 return e;
162 }else{
163 j =0;
164 while((j < e->size) &&
165 !((bprm->buf[e->offset + j] ^ e->magic[j])
166 & (e->mask ? e->mask[j] :0xff)))
167 j++;
168 if(j == e->size)
169 return e;
172 e = e->next;
174 return NULL;
178 * the loader itself
180 static intload_misc_binary(struct linux_binprm *bprm,struct pt_regs *regs)
182 struct binfmt_entry *fmt;
183 struct dentry * dentry;
184 char iname[128];
185 char*iname_addr = iname;
186 int retval;
188 MOD_INC_USE_COUNT;
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,127);
198 iname[127] ='\0';
200 read_unlock(&entries_lock);
201 if(!fmt)
202 goto _ret;
204 dput(bprm->dentry);
205 bprm->dentry = NULL;
207 /* Build args for interpreter */
208 remove_arg_zero(bprm);
209 retval =copy_strings_kernel(1, &bprm->filename, bprm);
210 if(retval <0)goto _ret;
211 bprm->argc++;
212 retval =copy_strings_kernel(1, &iname_addr, bprm);
213 if(retval <0)goto _ret;
214 bprm->argc++;
215 bprm->filename = iname;/* for binfmt_script */
217 dentry =open_namei(iname,0,0);
218 retval =PTR_ERR(dentry);
219 if(IS_ERR(dentry))
220 goto _ret;
221 bprm->dentry = dentry;
223 retval =prepare_binprm(bprm);
224 if(retval >=0)
225 retval =search_binary_handler(bprm, regs);
226 _ret:
227 MOD_DEC_USE_COUNT;
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 intproc_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) >127) ||
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 intproc_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 intproc_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 voidentry_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 intentry_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 return0;
474 #ifdef MODULE
476 * This is called as the fill_inode function when an inode
477 * is going into (fill = 1) or out of service (fill = 0).
478 * We use it here to manage the module use counts.
480 * Note: only the top-level directory needs to do this; if
481 * a lower level is referenced, the parent will be as well.
483 static voidbm_modcount(struct inode *inode,int fill)
485 if(fill)
486 MOD_INC_USE_COUNT;
487 else
488 MOD_DEC_USE_COUNT;
490 #endif
492 static int __init init_misc_binfmt(void)
494 int error = -ENOENT;
495 struct proc_dir_entry *status = NULL, *reg;
497 bm_dir =create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
498 if(!bm_dir)
499 goto out;
500 #ifdef MODULE
501 bm_dir->fill_inode = bm_modcount;
502 #endif
504 status =create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
505 bm_dir);
506 if(!status)
507 goto cleanup_bm;
508 status->read_proc = proc_read_status;
509 status->write_proc = proc_write_status;
511 reg =create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
512 if(!reg)
513 goto cleanup_status;
514 reg->write_proc = proc_write_register;
516 error =register_binfmt(&misc_format);
517 out:
518 return error;
520 cleanup_status:
521 remove_proc_entry("status", bm_dir);
522 cleanup_bm:
523 remove_proc_entry("sys/fs/binfmt_misc", NULL);
524 goto out;
527 static void __exit exit_misc_binfmt(void)
529 unregister_binfmt(&misc_format);
530 remove_proc_entry("register", bm_dir);
531 remove_proc_entry("status", bm_dir);
532 clear_entries();
533 remove_proc_entry("sys/fs/binfmt_misc", NULL);
536 EXPORT_NO_SYMBOLS;
538 module_init(init_misc_binfmt)
539 module_exit(exit_misc_binfmt)
close