~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/binfmt_misc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  binfmt_misc.c
  3  *
  4  *  Copyright (C) 1997 Richard Günther
  5  *
  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.
  9  *
 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
 16  */
 17 
 18 #include <linux/config.h>
 19 #include <linux/module.h>
 20 
 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>
 33 
 34 /*
 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..
 40  */
 41 #ifndef CONFIG_PROC_FS
 42 #error You really need /proc support for binfmt_misc. Please reconfigure!
 43 #endif
 44 
 45 #define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
 46 
 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;
 58 };
 59 
 60 #define ENTRY_ENABLED 1         /* the old binfmt_entry.enabled */
 61 #define ENTRY_MAGIC 8           /* not filename detection */
 62 
 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);
 66 
 67 static struct linux_binfmt misc_format = {
 68         NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
 69 };
 70 
 71 static struct proc_dir_entry *bm_dir;
 72 
 73 static struct binfmt_entry *entries;
 74 static int free_id = 1;
 75 static int enabled = 1;
 76 
 77 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
 78 
 79 
 80 /*
 81  * Unregister one entry
 82  */
 83 static void clear_entry(int id)
 84 {
 85         struct binfmt_entry **ep, *e;
 86 
 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);
 94 
 95         if (e) {
 96                 entry_proc_cleanup(e);
 97                 kfree(e);
 98         }
 99 }
100 
101 /*
102  * Clear all registered binary formats
103  */
104 static void clear_entries(void)
105 {
106         struct binfmt_entry *e, *n;
107 
108         write_lock(&entries_lock);
109         n = entries;
110         entries = NULL;
111         write_unlock(&entries_lock);
112 
113         while ((e = n)) {
114                 n = e->next;
115                 entry_proc_cleanup(e);
116                 kfree(e);
117         }
118 }
119 
120 /*
121  * Find entry through id and lock it
122  */
123 static struct binfmt_entry *get_entry(int id)
124 {
125         struct binfmt_entry *e;
126 
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;
134 }
135 
136 /*
137  * unlock entry
138  */
139 static inline void put_entry(struct binfmt_entry *e)
140 {
141         if (e)
142                 read_unlock(&entries_lock);
143 }
144 
145 
146 /* 
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
150  */
151 static struct binfmt_entry *check_file(struct linux_binprm *bprm)
152 {
153         struct binfmt_entry *e;
154         char *p = strrchr(bprm->filename, '.');
155         int j;
156 
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;
171                         }
172                 }
173                 e = e->next;
174         };
175         return NULL;
176 }
177 
178 /*
179  * the loader itself
180  */
181 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
182 {
183         struct binfmt_entry *fmt;
184         struct file * file;
185         char iname[BINPRM_BUF_SIZE];
186         char *iname_addr = iname;
187         int retval;
188 
189         retval = -ENOEXEC;
190         if (!enabled)
191                 goto _ret;
192 
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';
199         }
200         read_unlock(&entries_lock);
201         if (!fmt)
202                 goto _ret;
203 
204         allow_write_access(bprm->file);
205         fput(bprm->file);
206         bprm->file = NULL;
207 
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 */
217 
218         file = open_exec(iname);
219         retval = PTR_ERR(file);
220         if (IS_ERR(file))
221                 goto _ret;
222         bprm->file = file;
223 
224         retval = prepare_binprm(bprm);
225         if (retval >= 0)
226                 retval = search_binary_handler(bprm, regs);
227 _ret:
228         return retval;
229 }
230 
231 
232 
233 /*
234  * /proc handling routines
235  */
236 
237 /*
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.
242  */
243 static char *copyarg(char **dp, const char **sp, int *count,
244                      char del, int special, int *err)
245 {
246         char c = 0, *res = *dp;
247 
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) ? '' : 'A' - 10)) * 16;
255                                 if (!isxdigit(c = toupper(*(++*sp))))
256                                         *err = -EINVAL;
257                                 *((*dp)++) += c - (isdigit(c) ? '' : 'A' - 10);
258                                 ++*sp;
259                                 *count -= 3;
260                                 break;
261                         }
262                 default:
263                         *((*dp)++) = c;
264                 }
265         }
266         if (*err || (c != del) || (res == *dp))
267                 res = NULL;
268         else if (!special)
269                 *((*dp)++) = '\0';
270         return res;
271 }
272 
273 /*
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
277  */
278 static int proc_write_register(struct file *file, const char *buffer,
279                                unsigned long count, void *data)
280 {
281         const char *sp;
282         char del, *dp;
283         struct binfmt_entry *e;
284         int memsize, cnt = count - 1, err;
285 
286         /* some sanity checks */
287         err = -EINVAL;
288         if ((count < 11) || (count > 256))
289                 goto _err;
290 
291         err = -ENOMEM;
292         memsize = sizeof(struct binfmt_entry) + count;
293         if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
294                 goto _err;
295 
296         err = 0;
297         sp = buffer + 1;
298         del = buffer[0];
299         dp = (char *)e + sizeof(struct binfmt_entry);
300 
301         e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
302 
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++;
310 
311         e->offset = 0;
312         while (cnt-- && isdigit(*sp))
313                 e->offset = e->offset * 10 + *sp++ - '';
314         if (*sp++ != del)
315                 err = -EINVAL;
316 
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++;
324 
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;
330 
331         write_lock(&entries_lock);
332         e->next = entries;
333         entries = e;
334         write_unlock(&entries_lock);
335 
336         err = count;
337 _err:
338         return err;
339 free_err:
340         kfree(e);
341         err = -EINVAL;
342         goto _err;
343 }
344 
345 /*
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?
349  */
350 static int proc_read_status(char *page, char **start, off_t off,
351                             int count, int *eof, void *data)
352 {
353         struct binfmt_entry *e;
354         char *dp;
355         int elen, i, err;
356 
357 #ifndef VERBOSE_STATUS
358         if (data) {
359                 if (!(e = get_entry((int) data))) {
360                         err = -ENOENT;
361                         goto _err;
362                 }
363                 i = e->flags & ENTRY_ENABLED;
364                 put_entry(e);
365         } else {
366                 i = enabled;
367         } 
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;
376                 }
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;
390                         }
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;
397                                 }
398                         }
399                         *dp++ = '\n';
400                         *dp = '\0';
401                 }
402                 put_entry(e);
403         }
404 #endif
405 
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;
412 
413 _err:
414         return err;
415 }
416 
417 /*
418  * Set status of entry/binfmt_misc:
419  * '1' enables, '' disables and '-1' clears entry/binfmt_misc
420  */
421 static int proc_write_status(struct file *file, const char *buffer,
422                              unsigned long count, void *data)
423 {
424         struct binfmt_entry *e;
425         int res = count;
426 
427         if (buffer[count-1] == '\n')
428                 count--;
429         if ((count == 1) && !(buffer[0] & ~('' | '1'))) {
430                 if (data) {
431                         if ((e = get_entry((long) data)))
432                                 e->flags = (e->flags & ~ENTRY_ENABLED)
433                                             | (int)(buffer[0] - '');
434                         put_entry(e);
435                 } else {
436                         enabled = buffer[0] - '';
437                 }
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;
445         }
446         return res;
447 }
448 
449 /*
450  * Remove the /proc-dir entries of one binfmt
451  */
452 static void entry_proc_cleanup(struct binfmt_entry *e)
453 {
454         remove_proc_entry(e->proc_name, bm_dir);
455 }
456 
457 /*
458  * Create the /proc-dir entry for binfmt
459  */
460 static int entry_proc_setup(struct binfmt_entry *e)
461 {
462         if (!(e->proc_dir = create_proc_entry(e->proc_name,
463                                 S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
464         {
465                 printk(KERN_WARNING "Unable to create /proc entry.\n");
466                 return -ENOENT;
467         }
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;
472 }
473 
474 static int __init init_misc_binfmt(void)
475 {
476         int error = -ENOENT;
477         struct proc_dir_entry *status = NULL, *reg;
478 
479         bm_dir = proc_mkdir("sys/fs/binfmt_misc", NULL); /* WTF??? */
480         if (!bm_dir)
481                 goto out;
482         bm_dir->owner = THIS_MODULE;
483 
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;
490 
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;
495 
496         error = register_binfmt(&misc_format);
497 out:
498         return error;
499 
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;
505 }
506 
507 static void __exit exit_misc_binfmt(void)
508 {
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);
514 }
515 
516 EXPORT_NO_SYMBOLS;
517 
518 module_init(init_misc_binfmt);
519 module_exit(exit_misc_binfmt);
520 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.