~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to bsd-user/bsdload.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Code for loading BSD 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 TARGET_NGROUPS 32
 
14
 
 
15
/* ??? This should really be somewhere else.  */
 
16
abi_long memcpy_to_target(abi_ulong dest, const void *src,
 
17
                          unsigned long len)
 
18
{
 
19
    void *host_ptr;
 
20
 
 
21
    host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
 
22
    if (!host_ptr)
 
23
        return -TARGET_EFAULT;
 
24
    memcpy(host_ptr, src, len);
 
25
    unlock_user(host_ptr, dest, 1);
 
26
    return 0;
 
27
}
 
28
 
 
29
static int in_group_p(gid_t g)
 
30
{
 
31
    /* return TRUE if we're in the specified group, FALSE otherwise */
 
32
    int         ngroup;
 
33
    int         i;
 
34
    gid_t       grouplist[TARGET_NGROUPS];
 
35
 
 
36
    ngroup = getgroups(TARGET_NGROUPS, grouplist);
 
37
    for(i = 0; i < ngroup; i++) {
 
38
        if(grouplist[i] == g) {
 
39
            return 1;
 
40
        }
 
41
    }
 
42
    return 0;
 
43
}
 
44
 
 
45
static int count(char ** vec)
 
46
{
 
47
    int         i;
 
48
 
 
49
    for(i = 0; *vec; i++) {
 
50
        vec++;
 
51
    }
 
52
 
 
53
    return(i);
 
54
}
 
55
 
 
56
static int prepare_binprm(struct linux_binprm *bprm)
 
57
{
 
58
    struct stat         st;
 
59
    int mode;
 
60
    int retval, id_change;
 
61
 
 
62
    if(fstat(bprm->fd, &st) < 0) {
 
63
        return(-errno);
 
64
    }
 
65
 
 
66
    mode = st.st_mode;
 
67
    if(!S_ISREG(mode)) {        /* Must be regular file */
 
68
        return(-EACCES);
 
69
    }
 
70
    if(!(mode & 0111)) {        /* Must have at least one execute bit set */
 
71
        return(-EACCES);
 
72
    }
 
73
 
 
74
    bprm->e_uid = geteuid();
 
75
    bprm->e_gid = getegid();
 
76
    id_change = 0;
 
77
 
 
78
    /* Set-uid? */
 
79
    if(mode & S_ISUID) {
 
80
        bprm->e_uid = st.st_uid;
 
81
        if(bprm->e_uid != geteuid()) {
 
82
            id_change = 1;
 
83
        }
 
84
    }
 
85
 
 
86
    /* Set-gid? */
 
87
    /*
 
88
     * If setgid is set but no group execute bit then this
 
89
     * is a candidate for mandatory locking, not a setgid
 
90
     * executable.
 
91
     */
 
92
    if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
 
93
        bprm->e_gid = st.st_gid;
 
94
        if (!in_group_p(bprm->e_gid)) {
 
95
                id_change = 1;
 
96
        }
 
97
    }
 
98
 
 
99
    memset(bprm->buf, 0, sizeof(bprm->buf));
 
100
    retval = lseek(bprm->fd, 0L, SEEK_SET);
 
101
    if(retval >= 0) {
 
102
        retval = read(bprm->fd, bprm->buf, 128);
 
103
    }
 
104
    if(retval < 0) {
 
105
        perror("prepare_binprm");
 
106
        exit(-1);
 
107
        /* return(-errno); */
 
108
    }
 
109
    else {
 
110
        return(retval);
 
111
    }
 
112
}
 
113
 
 
114
/* Construct the envp and argv tables on the target stack.  */
 
115
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
 
116
                              abi_ulong stringp, int push_ptr)
 
117
{
 
118
    int n = sizeof(abi_ulong);
 
119
    abi_ulong envp;
 
120
    abi_ulong argv;
 
121
 
 
122
    sp -= (envc + 1) * n;
 
123
    envp = sp;
 
124
    sp -= (argc + 1) * n;
 
125
    argv = sp;
 
126
    if (push_ptr) {
 
127
        /* FIXME - handle put_user() failures */
 
128
        sp -= n;
 
129
        put_user_ual(envp, sp);
 
130
        sp -= n;
 
131
        put_user_ual(argv, sp);
 
132
    }
 
133
    sp -= n;
 
134
    /* FIXME - handle put_user() failures */
 
135
    put_user_ual(argc, sp);
 
136
 
 
137
    while (argc-- > 0) {
 
138
        /* FIXME - handle put_user() failures */
 
139
        put_user_ual(stringp, argv);
 
140
        argv += n;
 
141
        stringp += target_strlen(stringp) + 1;
 
142
    }
 
143
    /* FIXME - handle put_user() failures */
 
144
    put_user_ual(0, argv);
 
145
    while (envc-- > 0) {
 
146
        /* FIXME - handle put_user() failures */
 
147
        put_user_ual(stringp, envp);
 
148
        envp += n;
 
149
        stringp += target_strlen(stringp) + 1;
 
150
    }
 
151
    /* FIXME - handle put_user() failures */
 
152
    put_user_ual(0, envp);
 
153
 
 
154
    return sp;
 
155
}
 
156
 
 
157
int loader_exec(const char * filename, char ** argv, char ** envp,
 
158
             struct target_pt_regs * regs, struct image_info *infop)
 
159
{
 
160
    struct linux_binprm bprm;
 
161
    int retval;
 
162
    int i;
 
163
 
 
164
    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
 
165
    for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
 
166
            bprm.page[i] = NULL;
 
167
    retval = open(filename, O_RDONLY);
 
168
    if (retval < 0)
 
169
        return retval;
 
170
    bprm.fd = retval;
 
171
    bprm.filename = (char *)filename;
 
172
    bprm.argc = count(argv);
 
173
    bprm.argv = argv;
 
174
    bprm.envc = count(envp);
 
175
    bprm.envp = envp;
 
176
 
 
177
    retval = prepare_binprm(&bprm);
 
178
 
 
179
    if(retval>=0) {
 
180
        if (bprm.buf[0] == 0x7f
 
181
                && bprm.buf[1] == 'E'
 
182
                && bprm.buf[2] == 'L'
 
183
                && bprm.buf[3] == 'F') {
 
184
            retval = load_elf_binary(&bprm,regs,infop);
 
185
        } else {
 
186
            fprintf(stderr, "Unknown binary format\n");
 
187
            return -1;
 
188
        }
 
189
    }
 
190
 
 
191
    if(retval>=0) {
 
192
        /* success.  Initialize important registers */
 
193
        do_init_thread(regs, infop);
 
194
        return retval;
 
195
    }
 
196
 
 
197
    /* Something went wrong, return the inode and free the argument pages*/
 
198
    for (i=0 ; i<MAX_ARG_PAGES ; i++) {
 
199
        free(bprm.page[i]);
 
200
    }
 
201
    return(retval);
 
202
}