patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / binfmt_misc.c
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  *  2001-02-28 AV: rewritten into something that resembles C. Original didn't.
17  */
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21
22 #include <linux/binfmts.h>
23 #include <linux/slab.h>
24 #include <linux/ctype.h>
25 #include <linux/file.h>
26 #include <linux/pagemap.h>
27 #include <linux/namei.h>
28 #include <linux/mount.h>
29 #include <linux/syscalls.h>
30
31 #include <asm/uaccess.h>
32
33 enum {
34         VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
35 };
36
37 static LIST_HEAD(entries);
38 static int enabled = 1;
39
40 enum {Enabled, Magic};
41 #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
42
43 typedef struct {
44         struct list_head list;
45         unsigned long flags;            /* type, status, etc. */
46         int offset;                     /* offset of magic */
47         int size;                       /* size of magic/mask */
48         char *magic;                    /* magic or filename extension */
49         char *mask;                     /* mask, NULL for exact match */
50         char *interpreter;              /* filename of interpreter */
51         char *name;
52         struct dentry *dentry;
53 } Node;
54
55 static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
56 static struct vfsmount *bm_mnt;
57 static int entry_count;
58
59 /* 
60  * Check if we support the binfmt
61  * if we do, return the node, else NULL
62  * locking is done in load_misc_binary
63  */
64 static Node *check_file(struct linux_binprm *bprm)
65 {
66         char *p = strrchr(bprm->interp, '.');
67         struct list_head *l;
68
69         list_for_each(l, &entries) {
70                 Node *e = list_entry(l, Node, list);
71                 char *s;
72                 int j;
73
74                 if (!test_bit(Enabled, &e->flags))
75                         continue;
76
77                 if (!test_bit(Magic, &e->flags)) {
78                         if (p && !strcmp(e->magic, p + 1))
79                                 return e;
80                         continue;
81                 }
82
83                 s = bprm->buf + e->offset;
84                 if (e->mask) {
85                         for (j = 0; j < e->size; j++)
86                                 if ((*s++ ^ e->magic[j]) & e->mask[j])
87                                         break;
88                 } else {
89                         for (j = 0; j < e->size; j++)
90                                 if ((*s++ ^ e->magic[j]))
91                                         break;
92                 }
93                 if (j == e->size)
94                         return e;
95         }
96         return NULL;
97 }
98
99 /*
100  * the loader itself
101  */
102 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
103 {
104         Node *fmt;
105         struct file * file;
106         char iname[BINPRM_BUF_SIZE];
107         char *iname_addr = iname;
108         int retval;
109
110         retval = -ENOEXEC;
111         if (!enabled)
112                 goto _ret;
113
114         /* to keep locking time low, we copy the interpreter string */
115         read_lock(&entries_lock);
116         fmt = check_file(bprm);
117         if (fmt)
118                 strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
119         read_unlock(&entries_lock);
120         if (!fmt)
121                 goto _ret;
122
123         allow_write_access(bprm->file);
124         fput(bprm->file);
125         bprm->file = NULL;
126
127         /* Build args for interpreter */
128         if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
129                 remove_arg_zero(bprm);
130         }
131         retval = copy_strings_kernel(1, &bprm->interp, bprm);
132         if (retval < 0) goto _ret; 
133         bprm->argc++;
134         retval = copy_strings_kernel(1, &iname_addr, bprm);
135         if (retval < 0) goto _ret; 
136         bprm->argc++;
137         bprm->interp = iname;   /* for binfmt_script */
138
139         file = open_exec(iname);
140         retval = PTR_ERR(file);
141         if (IS_ERR(file))
142                 goto _ret;
143         bprm->file = file;
144
145         retval = prepare_binprm(bprm);
146         if (retval >= 0)
147                 retval = search_binary_handler(bprm, regs);
148 _ret:
149         return retval;
150 }
151
152 /* Command parsers */
153
154 /*
155  * parses and copies one argument enclosed in del from *sp to *dp,
156  * recognising the \x special.
157  * returns pointer to the copied argument or NULL in case of an
158  * error (and sets err) or null argument length.
159  */
160 static char *scanarg(char *s, char del)
161 {
162         char c;
163
164         while ((c = *s++) != del) {
165                 if (c == '\\' && *s == 'x') {
166                         s++;
167                         if (!isxdigit(*s++))
168                                 return NULL;
169                         if (!isxdigit(*s++))
170                                 return NULL;
171                 }
172         }
173         return s;
174 }
175
176 static int unquote(char *from)
177 {
178         char c = 0, *s = from, *p = from;
179
180         while ((c = *s++) != '\0') {
181                 if (c == '\\' && *s == 'x') {
182                         s++;
183                         c = toupper(*s++);
184                         *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
185                         c = toupper(*s++);
186                         *p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
187                         continue;
188                 }
189                 *p++ = c;
190         }
191         return p - from;
192 }
193
194 /*
195  * This registers a new binary format, it recognises the syntax
196  * ':name:type:offset:magic:mask:interpreter:'
197  * where the ':' is the IFS, that can be chosen with the first char
198  */
199 static Node *create_entry(const char __user *buffer, size_t count)
200 {
201         Node *e;
202         int memsize, err;
203         char *buf, *p;
204         char del;
205
206         /* some sanity checks */
207         err = -EINVAL;
208         if ((count < 11) || (count > 256))
209                 goto out;
210
211         err = -ENOMEM;
212         memsize = sizeof(Node) + count + 8;
213         e = (Node *) kmalloc(memsize, GFP_USER);
214         if (!e)
215                 goto out;
216
217         p = buf = (char *)e + sizeof(Node);
218
219         memset(e, 0, sizeof(Node));
220         if (copy_from_user(buf, buffer, count))
221                 goto Efault;
222
223         del = *p++;     /* delimeter */
224
225         memset(buf+count, del, 8);
226
227         e->name = p;
228         p = strchr(p, del);
229         if (!p)
230                 goto Einval;
231         *p++ = '\0';
232         if (!e->name[0] ||
233             !strcmp(e->name, ".") ||
234             !strcmp(e->name, "..") ||
235             strchr(e->name, '/'))
236                 goto Einval;
237         switch (*p++) {
238                 case 'E': e->flags = 1<<Enabled; break;
239                 case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
240                 default: goto Einval;
241         }
242         if (*p++ != del)
243                 goto Einval;
244         if (test_bit(Magic, &e->flags)) {
245                 char *s = strchr(p, del);
246                 if (!s)
247                         goto Einval;
248                 *s++ = '\0';
249                 e->offset = simple_strtoul(p, &p, 10);
250                 if (*p++)
251                         goto Einval;
252                 e->magic = p;
253                 p = scanarg(p, del);
254                 if (!p)
255                         goto Einval;
256                 p[-1] = '\0';
257                 if (!e->magic[0])
258                         goto Einval;
259                 e->mask = p;
260                 p = scanarg(p, del);
261                 if (!p)
262                         goto Einval;
263                 p[-1] = '\0';
264                 if (!e->mask[0])
265                         e->mask = NULL;
266                 e->size = unquote(e->magic);
267                 if (e->mask && unquote(e->mask) != e->size)
268                         goto Einval;
269                 if (e->size + e->offset > BINPRM_BUF_SIZE)
270                         goto Einval;
271         } else {
272                 p = strchr(p, del);
273                 if (!p)
274                         goto Einval;
275                 *p++ = '\0';
276                 e->magic = p;
277                 p = strchr(p, del);
278                 if (!p)
279                         goto Einval;
280                 *p++ = '\0';
281                 if (!e->magic[0] || strchr(e->magic, '/'))
282                         goto Einval;
283                 p = strchr(p, del);
284                 if (!p)
285                         goto Einval;
286                 *p++ = '\0';
287         }
288         e->interpreter = p;
289         p = strchr(p, del);
290         if (!p)
291                 goto Einval;
292         *p++ = '\0';
293         if (!e->interpreter[0])
294                 goto Einval;
295
296         if (*p == 'P') {
297                 p++;
298                 e->flags |= MISC_FMT_PRESERVE_ARGV0;
299         }
300
301         if (*p == '\n')
302                 p++;
303         if (p != buf + count)
304                 goto Einval;
305         return e;
306
307 out:
308         return ERR_PTR(err);
309
310 Efault:
311         kfree(e);
312         return ERR_PTR(-EFAULT);
313 Einval:
314         kfree(e);
315         return ERR_PTR(-EINVAL);
316 }
317
318 /*
319  * Set status of entry/binfmt_misc:
320  * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
321  */
322 static int parse_command(const char __user *buffer, size_t count)
323 {
324         char s[4];
325
326         if (!count)
327                 return 0;
328         if (count > 3)
329                 return -EINVAL;
330         if (copy_from_user(s, buffer, count))
331                 return -EFAULT;
332         if (s[count-1] == '\n')
333                 count--;
334         if (count == 1 && s[0] == '0')
335                 return 1;
336         if (count == 1 && s[0] == '1')
337                 return 2;
338         if (count == 2 && s[0] == '-' && s[1] == '1')
339                 return 3;
340         return -EINVAL;
341 }
342
343 /* generic stuff */
344
345 static void entry_status(Node *e, char *page)
346 {
347         char *dp;
348         char *status = "disabled";
349
350         if (test_bit(Enabled, &e->flags))
351                 status = "enabled";
352
353         if (!VERBOSE_STATUS) {
354                 sprintf(page, "%s\n", status);
355                 return;
356         }
357
358         sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
359         dp = page + strlen(page);
360         if (!test_bit(Magic, &e->flags)) {
361                 sprintf(dp, "extension .%s\n", e->magic);
362         } else {
363                 int i;
364
365                 sprintf(dp, "offset %i\nmagic ", e->offset);
366                 dp = page + strlen(page);
367                 for (i = 0; i < e->size; i++) {
368                         sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
369                         dp += 2;
370                 }
371                 if (e->mask) {
372                         sprintf(dp, "\nmask ");
373                         dp += 6;
374                         for (i = 0; i < e->size; i++) {
375                                 sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
376                                 dp += 2;
377                         }
378                 }
379                 *dp++ = '\n';
380                 *dp = '\0';
381         }
382 }
383
384 static struct inode *bm_get_inode(struct super_block *sb, int mode)
385 {
386         struct inode * inode = new_inode(sb);
387
388         if (inode) {
389                 inode->i_mode = mode;
390                 inode->i_uid = 0;
391                 inode->i_gid = 0;
392                 inode->i_blksize = PAGE_CACHE_SIZE;
393                 inode->i_blocks = 0;
394                 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
395         }
396         return inode;
397 }
398
399 static void bm_clear_inode(struct inode *inode)
400 {
401         kfree(inode->u.generic_ip);
402 }
403
404 static void kill_node(Node *e)
405 {
406         struct dentry *dentry;
407
408         write_lock(&entries_lock);
409         dentry = e->dentry;
410         if (dentry) {
411                 list_del_init(&e->list);
412                 e->dentry = NULL;
413         }
414         write_unlock(&entries_lock);
415
416         if (dentry) {
417                 dentry->d_inode->i_nlink--;
418                 d_drop(dentry);
419                 dput(dentry);
420                 simple_release_fs(&bm_mnt, &entry_count);
421         }
422 }
423
424 /* /<entry> */
425
426 static ssize_t
427 bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
428 {
429         Node *e = file->f_dentry->d_inode->u.generic_ip;
430         loff_t pos = *ppos;
431         ssize_t res;
432         char *page;
433         int len;
434
435         if (!(page = (char*) __get_free_page(GFP_KERNEL)))
436                 return -ENOMEM;
437
438         entry_status(e, page);
439         len = strlen(page);
440
441         res = -EINVAL;
442         if (pos < 0)
443                 goto out;
444         res = 0;
445         if (pos >= len)
446                 goto out;
447         if (len < pos + nbytes)
448                 nbytes = len - pos;
449         res = -EFAULT;
450         if (copy_to_user(buf, page + pos, nbytes))
451                 goto out;
452         *ppos = pos + nbytes;
453         res = nbytes;
454 out:
455         free_page((unsigned long) page);
456         return res;
457 }
458
459 static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
460                                 size_t count, loff_t *ppos)
461 {
462         struct dentry *root;
463         Node *e = file->f_dentry->d_inode->u.generic_ip;
464         int res = parse_command(buffer, count);
465
466         switch (res) {
467                 case 1: clear_bit(Enabled, &e->flags);
468                         break;
469                 case 2: set_bit(Enabled, &e->flags);
470                         break;
471                 case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
472                         down(&root->d_inode->i_sem);
473
474                         kill_node(e);
475
476                         up(&root->d_inode->i_sem);
477                         dput(root);
478                         break;
479                 default: return res;
480         }
481         return count;
482 }
483
484 static struct file_operations bm_entry_operations = {
485         .read           = bm_entry_read,
486         .write          = bm_entry_write,
487 };
488
489 /* /register */
490
491 static ssize_t bm_register_write(struct file *file, const char __user *buffer,
492                                size_t count, loff_t *ppos)
493 {
494         Node *e;
495         struct inode *inode;
496         struct dentry *root, *dentry;
497         struct super_block *sb = file->f_vfsmnt->mnt_sb;
498         int err = 0;
499
500         e = create_entry(buffer, count);
501
502         if (IS_ERR(e))
503                 return PTR_ERR(e);
504
505         root = dget(sb->s_root);
506         down(&root->d_inode->i_sem);
507         dentry = lookup_one_len(e->name, root, strlen(e->name));
508         err = PTR_ERR(dentry);
509         if (IS_ERR(dentry))
510                 goto out;
511
512         err = -EEXIST;
513         if (dentry->d_inode)
514                 goto out2;
515
516         inode = bm_get_inode(sb, S_IFREG | 0644);
517
518         err = -ENOMEM;
519         if (!inode)
520                 goto out2;
521
522         err = simple_pin_fs("binfmt_misc", &bm_mnt, &entry_count);
523         if (err) {
524                 iput(inode);
525                 inode = NULL;
526                 goto out2;
527         }
528
529         e->dentry = dget(dentry);
530         inode->u.generic_ip = e;
531         inode->i_fop = &bm_entry_operations;
532
533         d_instantiate(dentry, inode);
534         write_lock(&entries_lock);
535         list_add(&e->list, &entries);
536         write_unlock(&entries_lock);
537
538         err = 0;
539 out2:
540         dput(dentry);
541 out:
542         up(&root->d_inode->i_sem);
543         dput(root);
544
545         if (err) {
546                 kfree(e);
547                 return -EINVAL;
548         }
549         return count;
550 }
551
552 static struct file_operations bm_register_operations = {
553         .write          = bm_register_write,
554 };
555
556 /* /status */
557
558 static ssize_t
559 bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
560 {
561         char *s = enabled ? "enabled" : "disabled";
562         int len = strlen(s);
563         loff_t pos = *ppos;
564
565         if (pos < 0)
566                 return -EINVAL;
567         if (pos >= len)
568                 return 0;
569         if (len < pos + nbytes)
570                 nbytes = len - pos;
571         if (copy_to_user(buf, s + pos, nbytes))
572                 return -EFAULT;
573         *ppos = pos + nbytes;
574         return nbytes;
575 }
576
577 static ssize_t bm_status_write(struct file * file, const char __user * buffer,
578                 size_t count, loff_t *ppos)
579 {
580         int res = parse_command(buffer, count);
581         struct dentry *root;
582
583         switch (res) {
584                 case 1: enabled = 0; break;
585                 case 2: enabled = 1; break;
586                 case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
587                         down(&root->d_inode->i_sem);
588
589                         while (!list_empty(&entries))
590                                 kill_node(list_entry(entries.next, Node, list));
591
592                         up(&root->d_inode->i_sem);
593                         dput(root);
594                 default: return res;
595         }
596         return count;
597 }
598
599 static struct file_operations bm_status_operations = {
600         .read           = bm_status_read,
601         .write          = bm_status_write,
602 };
603
604 /* Superblock handling */
605
606 static struct super_operations s_ops = {
607         .statfs         = simple_statfs,
608         .clear_inode    = bm_clear_inode,
609 };
610
611 static int bm_fill_super(struct super_block * sb, void * data, int silent)
612 {
613         static struct tree_descr bm_files[] = {
614                 [1] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
615                 [2] = {"register", &bm_register_operations, S_IWUSR},
616                 /* last one */ {""}
617         };
618         int err = simple_fill_super(sb, 0x42494e4d, bm_files);
619         if (!err)
620                 sb->s_op = &s_ops;
621         return err;
622 }
623
624 static struct super_block *bm_get_sb(struct file_system_type *fs_type,
625         int flags, const char *dev_name, void *data)
626 {
627         return get_sb_single(fs_type, flags, data, bm_fill_super);
628 }
629
630 static struct linux_binfmt misc_format = {
631         .module = THIS_MODULE,
632         .load_binary = load_misc_binary,
633 };
634
635 static struct file_system_type bm_fs_type = {
636         .owner          = THIS_MODULE,
637         .name           = "binfmt_misc",
638         .get_sb         = bm_get_sb,
639         .kill_sb        = kill_litter_super,
640 };
641
642 static int __init init_misc_binfmt(void)
643 {
644         int err = register_filesystem(&bm_fs_type);
645         if (!err) {
646                 err = register_binfmt(&misc_format);
647                 if (err)
648                         unregister_filesystem(&bm_fs_type);
649         }
650         return err;
651 }
652
653 static void __exit exit_misc_binfmt(void)
654 {
655         unregister_binfmt(&misc_format);
656         unregister_filesystem(&bm_fs_type);
657 }
658
659 core_initcall(init_misc_binfmt);
660 module_exit(exit_misc_binfmt);
661 MODULE_LICENSE("GPL");