linux/fs/binfmt_misc.c
<<
>>
Prefs
   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#include <linux/sched.h>
  22#include <linux/magic.h>
  23#include <linux/binfmts.h>
  24#include <linux/slab.h>
  25#include <linux/ctype.h>
  26#include <linux/file.h>
  27#include <linux/pagemap.h>
  28#include <linux/namei.h>
  29#include <linux/mount.h>
  30#include <linux/syscalls.h>
  31#include <linux/fs.h>
  32
  33#include <asm/uaccess.h>
  34
  35enum {
  36        VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
  37};
  38
  39static LIST_HEAD(entries);
  40static int enabled = 1;
  41
  42enum {Enabled, Magic};
  43#define MISC_FMT_PRESERVE_ARGV0 (1<<31)
  44#define MISC_FMT_OPEN_BINARY (1<<30)
  45#define MISC_FMT_CREDENTIALS (1<<29)
  46
  47typedef struct {
  48        struct list_head list;
  49        unsigned long 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 *name;
  56        struct dentry *dentry;
  57} Node;
  58
  59static DEFINE_RWLOCK(entries_lock);
  60static struct file_system_type bm_fs_type;
  61static struct vfsmount *bm_mnt;
  62static int entry_count;
  63
  64/* 
  65 * Check if we support the binfmt
  66 * if we do, return the node, else NULL
  67 * locking is done in load_misc_binary
  68 */
  69static Node *check_file(struct linux_binprm *bprm)
  70{
  71        char *p = strrchr(bprm->interp, '.');
  72        struct list_head *l;
  73
  74        list_for_each(l, &entries) {
  75                Node *e = list_entry(l, Node, list);
  76                char *s;
  77                int j;
  78
  79                if (!test_bit(Enabled, &e->flags))
  80                        continue;
  81
  82                if (!test_bit(Magic, &e->flags)) {
  83                        if (p && !strcmp(e->magic, p + 1))
  84                                return e;
  85                        continue;
  86                }
  87
  88                s = bprm->buf + e->offset;
  89                if (e->mask) {
  90                        for (j = 0; j < e->size; j++)
  91                                if ((*s++ ^ e->magic[j]) & e->mask[j])
  92                                        break;
  93                } else {
  94                        for (j = 0; j < e->size; j++)
  95                                if ((*s++ ^ e->magic[j]))
  96                                        break;
  97                }
  98                if (j == e->size)
  99                        return e;
 100        }
 101        return NULL;
 102}
 103
 104/*
 105 * the loader itself
 106 */
 107static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 108{
 109        Node *fmt;
 110        struct file * interp_file = NULL;
 111        char iname[BINPRM_BUF_SIZE];
 112        const char *iname_addr = iname;
 113        int retval;
 114        int fd_binary = -1;
 115
 116        retval = -ENOEXEC;
 117        if (!enabled)
 118                goto _ret;
 119
 120        retval = -ENOEXEC;
 121        if (bprm->recursion_depth > BINPRM_MAX_RECURSION)
 122                goto _ret;
 123
 124        /* to keep locking time low, we copy the interpreter string */
 125        read_lock(&entries_lock);
 126        fmt = check_file(bprm);
 127        if (fmt)
 128                strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
 129        read_unlock(&entries_lock);
 130        if (!fmt)
 131                goto _ret;
 132
 133        if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
 134                retval = remove_arg_zero(bprm);
 135                if (retval)
 136                        goto _ret;
 137        }
 138
 139        if (fmt->flags & MISC_FMT_OPEN_BINARY) {
 140
 141                /* if the binary should be opened on behalf of the
 142                 * interpreter than keep it open and assign descriptor
 143                 * to it */
 144                fd_binary = get_unused_fd();
 145                if (fd_binary < 0) {
 146                        retval = fd_binary;
 147                        goto _ret;
 148                }
 149                fd_install(fd_binary, bprm->file);
 150
 151                /* if the binary is not readable than enforce mm->dumpable=0
 152                   regardless of the interpreter's permissions */
 153                would_dump(bprm, bprm->file);
 154
 155                allow_write_access(bprm->file);
 156                bprm->file = NULL;
 157
 158                /* mark the bprm that fd should be passed to interp */
 159                bprm->interp_flags |= BINPRM_FLAGS_EXECFD;
 160                bprm->interp_data = fd_binary;
 161
 162        } else {
 163                allow_write_access(bprm->file);
 164                fput(bprm->file);
 165                bprm->file = NULL;
 166        }
 167        /* make argv[1] be the path to the binary */
 168        retval = copy_strings_kernel (1, &bprm->interp, bprm);
 169        if (retval < 0)
 170                goto _error;
 171        bprm->argc++;
 172
 173        /* add the interp as argv[0] */
 174        retval = copy_strings_kernel (1, &iname_addr, bprm);
 175        if (retval < 0)
 176                goto _error;
 177        bprm->argc ++;
 178
 179        /* Update interp in case binfmt_script needs it. */
 180        retval = bprm_change_interp(iname, bprm);
 181        if (retval < 0)
 182                goto _error;
 183
 184        interp_file = open_exec (iname);
 185        retval = PTR_ERR (interp_file);
 186        if (IS_ERR (interp_file))
 187                goto _error;
 188
 189        bprm->file = interp_file;
 190        if (fmt->flags & MISC_FMT_CREDENTIALS) {
 191                /*
 192                 * No need to call prepare_binprm(), it's already been
 193                 * done.  bprm->buf is stale, update from interp_file.
 194                 */
 195                memset(bprm->buf, 0, BINPRM_BUF_SIZE);
 196                retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
 197        } else
 198                retval = prepare_binprm (bprm);
 199
 200        if (retval < 0)
 201                goto _error;
 202
 203        bprm->recursion_depth++;
 204
 205        retval = search_binary_handler (bprm, regs);
 206        if (retval < 0)
 207                goto _error;
 208
 209_ret:
 210        return retval;
 211_error:
 212        if (fd_binary > 0)
 213                sys_close(fd_binary);
 214        bprm->interp_flags = 0;
 215        bprm->interp_data = 0;
 216        goto _ret;
 217}
 218
 219/* Command parsers */
 220
 221/*
 222 * parses and copies one argument enclosed in del from *sp to *dp,
 223 * recognising the \x special.
 224 * returns pointer to the copied argument or NULL in case of an
 225 * error (and sets err) or null argument length.
 226 */
 227static char *scanarg(char *s, char del)
 228{
 229        char c;
 230
 231        while ((c = *s++) != del) {
 232                if (c == '\\' && *s == 'x') {
 233                        s++;
 234                        if (!isxdigit(*s++))
 235                                return NULL;
 236                        if (!isxdigit(*s++))
 237                                return NULL;
 238                }
 239        }
 240        return s;
 241}
 242
 243static int unquote(char *from)
 244{
 245        char c = 0, *s = from, *p = from;
 246
 247        while ((c = *s++) != '\0') {
 248                if (c == '\\' && *s == 'x') {
 249                        s++;
 250                        c = toupper(*s++);
 251                        *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
 252                        c = toupper(*s++);
 253                        *p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
 254                        continue;
 255                }
 256                *p++ = c;
 257        }
 258        return p - from;
 259}
 260
 261static char * check_special_flags (char * sfs, Node * e)
 262{
 263        char * p = sfs;
 264        int cont = 1;
 265
 266        /* special flags */
 267        while (cont) {
 268                switch (*p) {
 269                        case 'P':
 270                                p++;
 271                                e->flags |= MISC_FMT_PRESERVE_ARGV0;
 272                                break;
 273                        case 'O':
 274                                p++;
 275                                e->flags |= MISC_FMT_OPEN_BINARY;
 276                                break;
 277                        case 'C':
 278                                p++;
 279                                /* this flags also implies the
 280                                   open-binary flag */
 281                                e->flags |= (MISC_FMT_CREDENTIALS |
 282                                                MISC_FMT_OPEN_BINARY);
 283                                break;
 284                        default:
 285                                cont = 0;
 286                }
 287        }
 288
 289        return p;
 290}
 291/*
 292 * This registers a new binary format, it recognises the syntax
 293 * ':name:type:offset:magic:mask:interpreter:flags'
 294 * where the ':' is the IFS, that can be chosen with the first char
 295 */
 296static Node *create_entry(const char __user *buffer, size_t count)
 297{
 298        Node *e;
 299        int memsize, err;
 300        char *buf, *p;
 301        char del;
 302
 303        /* some sanity checks */
 304        err = -EINVAL;
 305        if ((count < 11) || (count > 256))
 306                goto out;
 307
 308        err = -ENOMEM;
 309        memsize = sizeof(Node) + count + 8;
 310        e = kmalloc(memsize, GFP_USER);
 311        if (!e)
 312                goto out;
 313
 314        p = buf = (char *)e + sizeof(Node);
 315
 316        memset(e, 0, sizeof(Node));
 317        if (copy_from_user(buf, buffer, count))
 318                goto Efault;
 319
 320        del = *p++;     /* delimeter */
 321
 322        memset(buf+count, del, 8);
 323
 324        e->name = p;
 325        p = strchr(p, del);
 326        if (!p)
 327                goto Einval;
 328        *p++ = '\0';
 329        if (!e->name[0] ||
 330            !strcmp(e->name, ".") ||
 331            !strcmp(e->name, "..") ||
 332            strchr(e->name, '/'))
 333                goto Einval;
 23="L233"> 234        switch (*p{
 235                case &E39;C'e->flags<= 10)) <oto  236                case &M39;C'e->flags<= (10)) <oto  237                defa     goto Einval;
 238    }
pdel}
Einval;
e->flags)a>{
s = strchr(p, del);
s}
Einval;
s++ = '\0';
e->s = pp - 10);
p}
 248                        goto Einval;
 249                e->p;
 250                p = scanarg(p, del);
 251                if (!p)
 252                        goto Einval;
 253            f (!p[-1]a>++ = '\0';
 254                if (!e-> 255                        goto Einval;
 256            f (!e->p;
p = scanarg(p, del);
p)
Einval;
p[-1]a>++ = '\0';
e->e->NULL;
e->unquotee->e->unquotee->e->Einval;
e->e->s &>BINPRM_BUF_SIZE;
Einval;
 268        } >{
 269                p = strchr(p, del);
 270                if (!p)
 271                        goto Einval;
 272                *p++ = '\0';
 273                e->p;
 274                p = strchr(p, del);
 275                if (!p)
 276                        goto Einval;
 277                *p++ = '\0';
 278                if (!e->strchr(e->'/'))
 279                        goto Einval;
p = strchr(p, del);
 281                if (!p)
 282                        goto Einval;
 283                *p++ = '\0';
 284    }
 285    /a>(e->p;
p = strchr(p, del);
p)
Einval;
 289        *p++ = '\0';
e->Einval;
p = check_special_flags(p, e);
p == &#n39;/'
p++;
 298            p<++) != buf) + countp
Einval;
 300        return e;
 302>outault:
 303        return err);
 304a>);
 305urn Efaultault:
e);
e);
 308oto Einvalault:
 309        e);
EINVAL);
/*
uscaseate_e="fs/binfmt_:">/*
'0& disdumpsrses 39;0&-139;:&#clearseate_e="fs/binfmt_">/*
 */
(const char __user *buffer, size_t count)
s[4]/a>);
count)
count &3)
EINVAL;
 325        if (copy_from_user(s, buffer, count))
e;
s[a>, count-1]a>a> == &#n39;/'
count--;
 329        f (!count<>a>1 &&a>s[0]a>a> == &039;/'
 330                ret> = 1;
count<>a>1 &&a>s[0]a>a> == &139;/'
 332                ret2 = 1;
count<>a>2 &&a>s[0]a>a> == &-9;\\' &&a>s[1]a>a> == &139;/'
 24="L2343> 274                ret3 = 1;
 235        ret> = -EINVAL;
 236}
 238    nt"> */
usde=e" class="srete_e_ususer(Node *e, /a>(char *p;
usde=e" class="srususera>++ = flags<= + = f: t;..";
e->flags)a
usde=e" class="srususera>++ =  250                (&q39;7;s#n3;..",  251                re/a>);
 252    }
(&q39;7;s#nask:interpr 39;7;s#n3;..", e->p =  256a>);
p, &q39;7;s3;..", flags)/a>);
p<+/a> = flags)/a>);
e->flags amp;&a>MISC_FMT_PRESERVE_ARGV0)>{
p ++ = &P9;\0';
e->flags amp;&a>MISC_FMT_OPEN_BINARY<>{
p ++ = &O9;\0';
e->flags amp;&a>MISC_FMT_CREDENTIALS<>{
p ++ = &C9;\0';
p ++ = &#n39;/';
 272        if (!e->flags)a>{
 273                (p, &qextension .39;7;s#n3;..", e-> 274        } >{
 275                int p;
 277                (p, &qepe:of 39;7;i\nmet:m 3;..", e->s);
 278            /a>(p =  279            for  r * pp &a>, e->p{
(p, &q39;7;02x3;.."e->p]));
 281                    /a>(p<+=t2 = 1;
 282            }
 283                    e->(p, &q\nmesk 3;.."));
p<+=t6a>));
pp &a>, e->p{
(p, &q39;7;02x3;.."e->p]));
p<+=t2 = 1;
p++ = &#n39;/';
p = '\0';
p
 298    ss=uc  int p/a>));
se=name" class="sra_a>se= 283 = se=name" class="sra_m>se= 283 = se=name" class="sra_c>se= 283));
se=name" class="srcurrent_fs_>se=rchr(p/a>));
 309stavoidturn Node *ea
e->e->e->NULL;
 325         330               *p));
 25="L2353> 304a>);
 ote_y/a> &ags */
size_ta>);
__userbuf, size_t ea
Node *e = size_t     ea)a
usde=e" class="srete_e_ususer(e, buf, e,  252        return size_t     __user *buffer);
size_t count, ea
Node *e =  *buffer, count));
e->flags)a>));
e->flags)a>));
p->eaa>));
 273                    > 275            def">Ef:     return counta>));
 278}
sa>(Node" class="srfil=_opera>sa>(ze_t      281    ./a>( 282    ./a>( 283    ./a>(Ef_llseekread" class="srdef">Ef_llseekrchr);

size_t     __user *buffer);
size_t count, ea
Node *ea>));
p = pa>));
p = 0;
e = buffer, count));
eaa
eaa>));
p->e->, e->);
pp = -p,<>p = -pyp=Node" class="srom_fs_>yp=f">p,<(1, &p));
pa>{
NULL;
e->ea>));
sa>(Node" class="srom_ete_y_opera>sa>(>bufa>));
e-> 26="L2363> 304a>);
p = 0;
pa>{
eaa>));
counta>));
sa>(Node" class="srfil=_opera>sa>(ze_t     p{
 252}a>));
us ags */
size_ta>);
us_rea_read" class="srom_us_rea_rchr__user *buf, size_t ea
&qendump_\n3;..", &qdisdump_\n3;.."));
buf, e, size_t     __userbuffer);
size_t count, ea
 *buffer, count));
 273            case 3:     p->Node, Ef:     return  282    }
 283        return counta>));
sa>(Node" class="srfil=_opera>sa>(ze_t     p{
us_rea_read" class="srom_us_rea_rchr);
us_writeread" class="srom_us_writerchr);
Ef_llseekread" class="srdef">Ef_llseekrchr);

sa>(Node" class="srsuper_opera>sa>(ze_t     p{
fsde=e" class="srfsrchr         /a> = p,p,<    int ea
&qus3;.."p,<>p|>&qregisrpr3;.."p,<>p});
, &q3;.."));
p = p,<>p,<>pa>));
p->ppa>));
pa>));
yp=Node" class="srfil=_sysrpm_>yp=Node *p,
flags,ona>(const c/a> *p,pa>));
 *p, int flags,oint p,p{
p = p,
p = p,
yp=Node" class="srfil=_sysrpm_>yp=Nodep{
p,
, &q"fs/binfmt_3;.."
));
p = yp=Node" class="srom_fs_>yp=f">p)a>));
pa>));
 27="L2373> 254            p)a>));
pa>));
));
p)a>));
yp=Node" class="srom_fs_>yp=f">p)a>));
));
));
&qGPL3;.."));

The original LXR software by the ));
LXR ss="unsdeNode,lxr@li=ux.noNode.
lxr.li=ux.no kindly hosrpd by )); Redpill Li=pro ASNode,(ults=g and opera>sa>( service( since 1995.