Statistics
| Branch: | Revision:

root / linux-user / linuxload.c @ 5fafdf24

History | View | Annotate | Download (4.4 kB)

1
/* Code for loading Linux executables.  Mostly linux kernel code.  */
2

    
3
#include <sys/types.h>
4
#include <sys/stat.h>
5
#include <fcntl.h>
6
#include <errno.h>
7
#include <unistd.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10

    
11
#include "qemu.h"
12

    
13
#define NGROUPS 32
14

    
15
/* ??? This should really be somewhere else.  */
16
void memcpy_to_target(target_ulong dest, const void *src,
17
                      unsigned long len)
18
{
19
    void *host_ptr;
20

    
21
    host_ptr = lock_user(dest, len, 0);
22
    memcpy(host_ptr, src, len);
23
    unlock_user(host_ptr, dest, 1);
24
}
25

    
26
static int in_group_p(gid_t g)
27
{
28
    /* return TRUE if we're in the specified group, FALSE otherwise */
29
    int                ngroup;
30
    int                i;
31
    gid_t        grouplist[NGROUPS];
32

    
33
    ngroup = getgroups(NGROUPS, grouplist);
34
    for(i = 0; i < ngroup; i++) {
35
        if(grouplist[i] == g) {
36
            return 1;
37
        }
38
    }
39
    return 0;
40
}
41

    
42
static int count(char ** vec)
43
{
44
    int                i;
45

    
46
    for(i = 0; *vec; i++) {
47
        vec++;
48
    }
49

    
50
    return(i);
51
}
52

    
53
static int prepare_binprm(struct linux_binprm *bprm)
54
{
55
    struct stat                st;
56
    int mode;
57
    int retval, id_change;
58

    
59
    if(fstat(bprm->fd, &st) < 0) {
60
        return(-errno);
61
    }
62

    
63
    mode = st.st_mode;
64
    if(!S_ISREG(mode)) {        /* Must be regular file */
65
        return(-EACCES);
66
    }
67
    if(!(mode & 0111)) {        /* Must have at least one execute bit set */
68
        return(-EACCES);
69
    }
70

    
71
    bprm->e_uid = geteuid();
72
    bprm->e_gid = getegid();
73
    id_change = 0;
74

    
75
    /* Set-uid? */
76
    if(mode & S_ISUID) {
77
            bprm->e_uid = st.st_uid;
78
        if(bprm->e_uid != geteuid()) {
79
            id_change = 1;
80
        }
81
    }
82

    
83
    /* Set-gid? */
84
    /*
85
     * If setgid is set but no group execute bit then this
86
     * is a candidate for mandatory locking, not a setgid
87
     * executable.
88
     */
89
    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
90
        bprm->e_gid = st.st_gid;
91
        if (!in_group_p(bprm->e_gid)) {
92
                id_change = 1;
93
        }
94
    }
95

    
96
    memset(bprm->buf, 0, sizeof(bprm->buf));
97
    retval = lseek(bprm->fd, 0L, SEEK_SET);
98
    if(retval >= 0) {
99
        retval = read(bprm->fd, bprm->buf, 128);
100
    }
101
    if(retval < 0) {
102
        perror("prepare_binprm");
103
        exit(-1);
104
        /* return(-errno); */
105
    }
106
    else {
107
        return(retval);
108
    }
109
}
110

    
111
/* Construct the envp and argv tables on the target stack.  */
112
target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
113
                                 target_ulong stringp, int push_ptr)
114
{
115
    int n = sizeof(target_ulong);
116
    target_ulong envp;
117
    target_ulong argv;
118

    
119
    sp -= (envc + 1) * n;
120
    envp = sp;
121
    sp -= (argc + 1) * n;
122
    argv = sp;
123
    if (push_ptr) {
124
        sp -= n; tputl(sp, envp);
125
        sp -= n; tputl(sp, argv);
126
    }
127
    sp -= n; tputl(sp, argc);
128

    
129
    while (argc-- > 0) {
130
        tputl(argv, stringp); argv += n;
131
        stringp += target_strlen(stringp) + 1;
132
    }
133
    tputl(argv, 0);
134
    while (envc-- > 0) {
135
        tputl(envp, stringp); envp += n;
136
        stringp += target_strlen(stringp) + 1;
137
    }
138
    tputl(envp, 0);
139

    
140
    return sp;
141
}
142

    
143
int loader_exec(const char * filename, char ** argv, char ** envp,
144
             struct target_pt_regs * regs, struct image_info *infop)
145
{
146
    struct linux_binprm bprm;
147
    int retval;
148
    int i;
149

    
150
    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
151
    for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
152
            bprm.page[i] = 0;
153
    retval = open(filename, O_RDONLY);
154
    if (retval < 0)
155
        return retval;
156
    bprm.fd = retval;
157
    bprm.filename = (char *)filename;
158
    bprm.argc = count(argv);
159
    bprm.argv = argv;
160
    bprm.envc = count(envp);
161
    bprm.envp = envp;
162

    
163
    retval = prepare_binprm(&bprm);
164

    
165
    infop->host_argv = argv;
166

    
167
    if(retval>=0) {
168
        if (bprm.buf[0] == 0x7f
169
                && bprm.buf[1] == 'E'
170
                && bprm.buf[2] == 'L'
171
                && bprm.buf[3] == 'F') {
172
            retval = load_elf_binary(&bprm,regs,infop);
173
#if defined(TARGET_HAS_BFLT)
174
        } else if (bprm.buf[0] == 'b'
175
                && bprm.buf[1] == 'F'
176
                && bprm.buf[2] == 'L'
177
                && bprm.buf[3] == 'T') {
178
            retval = load_flt_binary(&bprm,regs,infop);
179
#endif
180
        } else {
181
            fprintf(stderr, "Unknown binary format\n");
182
            return -1;
183
        }
184
    }
185
   
186
    if(retval>=0) {
187
        /* success.  Initialize important registers */
188
        do_init_thread(regs, infop);
189
        return retval;
190
    }
191

    
192
    /* Something went wrong, return the inode and free the argument pages*/
193
    for (i=0 ; i<MAX_ARG_PAGES ; i++) {
194
        free(bprm.page[i]);
195
    }
196
    return(retval);
197
}