OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [binfmt_misc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.