]>
Commit | Line | Data |
---|---|---|
b211b368 WL |
1 | /* |
2 | * Load BSD executables. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
84778508 | 17 | |
2231197c | 18 | #include "qemu/osdep.h" |
84778508 BS |
19 | |
20 | #include "qemu.h" | |
21 | ||
e99a22cc | 22 | #define TARGET_NGROUPS 32 |
84778508 BS |
23 | |
24 | /* ??? This should really be somewhere else. */ | |
25 | abi_long memcpy_to_target(abi_ulong dest, const void *src, | |
26 | unsigned long len) | |
27 | { | |
28 | void *host_ptr; | |
29 | ||
30 | host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); | |
58b3beb4 | 31 | if (!host_ptr) { |
84778508 | 32 | return -TARGET_EFAULT; |
58b3beb4 | 33 | } |
84778508 BS |
34 | memcpy(host_ptr, src, len); |
35 | unlock_user(host_ptr, dest, 1); | |
36 | return 0; | |
37 | } | |
38 | ||
ca0fd2e3 | 39 | static int count(char **vec) |
84778508 BS |
40 | { |
41 | int i; | |
42 | ||
ca0fd2e3 | 43 | for (i = 0; *vec; i++) { |
84778508 BS |
44 | vec++; |
45 | } | |
46 | ||
fa054637 | 47 | return i; |
84778508 BS |
48 | } |
49 | ||
afcbcff8 | 50 | static int prepare_binprm(struct bsd_binprm *bprm) |
84778508 BS |
51 | { |
52 | struct stat st; | |
53 | int mode; | |
4a65a86a | 54 | int retval; |
84778508 | 55 | |
ca0fd2e3 | 56 | if (fstat(bprm->fd, &st) < 0) { |
fa054637 | 57 | return -errno; |
84778508 BS |
58 | } |
59 | ||
60 | mode = st.st_mode; | |
ca0fd2e3 | 61 | if (!S_ISREG(mode)) { /* Must be regular file */ |
fa054637 | 62 | return -EACCES; |
84778508 | 63 | } |
ca0fd2e3 | 64 | if (!(mode & 0111)) { /* Must have at least one execute bit set */ |
fa054637 | 65 | return -EACCES; |
84778508 BS |
66 | } |
67 | ||
68 | bprm->e_uid = geteuid(); | |
69 | bprm->e_gid = getegid(); | |
84778508 BS |
70 | |
71 | /* Set-uid? */ | |
ca0fd2e3 | 72 | if (mode & S_ISUID) { |
84778508 | 73 | bprm->e_uid = st.st_uid; |
84778508 BS |
74 | } |
75 | ||
76 | /* Set-gid? */ | |
77 | /* | |
78 | * If setgid is set but no group execute bit then this | |
79 | * is a candidate for mandatory locking, not a setgid | |
80 | * executable. | |
81 | */ | |
82 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | |
83 | bprm->e_gid = st.st_gid; | |
84778508 BS |
84 | } |
85 | ||
86 | memset(bprm->buf, 0, sizeof(bprm->buf)); | |
87 | retval = lseek(bprm->fd, 0L, SEEK_SET); | |
ca0fd2e3 | 88 | if (retval >= 0) { |
84778508 BS |
89 | retval = read(bprm->fd, bprm->buf, 128); |
90 | } | |
ca0fd2e3 | 91 | if (retval < 0) { |
84778508 BS |
92 | perror("prepare_binprm"); |
93 | exit(-1); | |
58b3beb4 | 94 | } else { |
fa054637 | 95 | return retval; |
84778508 BS |
96 | } |
97 | } | |
98 | ||
99 | /* Construct the envp and argv tables on the target stack. */ | |
100 | abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | |
101 | abi_ulong stringp, int push_ptr) | |
102 | { | |
103 | int n = sizeof(abi_ulong); | |
104 | abi_ulong envp; | |
105 | abi_ulong argv; | |
106 | ||
107 | sp -= (envc + 1) * n; | |
108 | envp = sp; | |
109 | sp -= (argc + 1) * n; | |
110 | argv = sp; | |
111 | if (push_ptr) { | |
112 | /* FIXME - handle put_user() failures */ | |
113 | sp -= n; | |
114 | put_user_ual(envp, sp); | |
115 | sp -= n; | |
116 | put_user_ual(argv, sp); | |
117 | } | |
118 | sp -= n; | |
119 | /* FIXME - handle put_user() failures */ | |
120 | put_user_ual(argc, sp); | |
121 | ||
122 | while (argc-- > 0) { | |
123 | /* FIXME - handle put_user() failures */ | |
124 | put_user_ual(stringp, argv); | |
125 | argv += n; | |
126 | stringp += target_strlen(stringp) + 1; | |
127 | } | |
128 | /* FIXME - handle put_user() failures */ | |
129 | put_user_ual(0, argv); | |
130 | while (envc-- > 0) { | |
131 | /* FIXME - handle put_user() failures */ | |
132 | put_user_ual(stringp, envp); | |
133 | envp += n; | |
134 | stringp += target_strlen(stringp) + 1; | |
135 | } | |
136 | /* FIXME - handle put_user() failures */ | |
137 | put_user_ual(0, envp); | |
138 | ||
139 | return sp; | |
140 | } | |
141 | ||
ca0fd2e3 | 142 | int loader_exec(const char *filename, char **argv, char **envp, |
d37853f9 WL |
143 | struct target_pt_regs *regs, struct image_info *infop, |
144 | struct bsd_binprm *bprm) | |
84778508 | 145 | { |
223005f0 | 146 | int retval, i; |
84778508 | 147 | |
223005f0 | 148 | bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; |
d37853f9 WL |
149 | for (i = 0; i < MAX_ARG_PAGES; i++) { /* clear page-table */ |
150 | bprm->page[i] = NULL; | |
58b3beb4 | 151 | } |
84778508 | 152 | retval = open(filename, O_RDONLY); |
58b3beb4 | 153 | if (retval < 0) { |
84778508 | 154 | return retval; |
58b3beb4 | 155 | } |
84778508 | 156 | |
d37853f9 WL |
157 | bprm->fd = retval; |
158 | bprm->filename = (char *)filename; | |
159 | bprm->argc = count(argv); | |
160 | bprm->argv = argv; | |
161 | bprm->envc = count(envp); | |
162 | bprm->envp = envp; | |
163 | ||
164 | retval = prepare_binprm(bprm); | |
84778508 | 165 | |
ca0fd2e3 | 166 | if (retval >= 0) { |
d37853f9 WL |
167 | if (bprm->buf[0] == 0x7f |
168 | && bprm->buf[1] == 'E' | |
169 | && bprm->buf[2] == 'L' | |
170 | && bprm->buf[3] == 'F') { | |
171 | retval = load_elf_binary(bprm, regs, infop); | |
84778508 | 172 | } else { |
9bb93180 | 173 | fprintf(stderr, "Unknown binary format\n"); |
84778508 BS |
174 | return -1; |
175 | } | |
176 | } | |
177 | ||
ca0fd2e3 | 178 | if (retval >= 0) { |
84778508 BS |
179 | /* success. Initialize important registers */ |
180 | do_init_thread(regs, infop); | |
181 | return retval; | |
182 | } | |
183 | ||
184 | /* Something went wrong, return the inode and free the argument pages*/ | |
ca0fd2e3 | 185 | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { |
d37853f9 | 186 | g_free(bprm->page[i]); |
84778508 | 187 | } |
fa054637 | 188 | return retval; |
84778508 | 189 | } |