root / prex-0.9.0 / usr / server / exec / exec_execve.c @ 03e9c04a
History | View | Annotate | Download (9.51 KB)
1 |
/*-
|
---|---|
2 |
* Copyright (c) 2005-2009, Kohsuke Ohtani
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions
|
7 |
* are met:
|
8 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
/*
|
31 |
* exec_execve.c - execve support
|
32 |
*/
|
33 |
|
34 |
#include <sys/prex.h> |
35 |
#include <sys/capability.h> |
36 |
#include <ipc/fs.h> |
37 |
#include <ipc/proc.h> |
38 |
#include <ipc/ipc.h> |
39 |
#include <sys/list.h> |
40 |
|
41 |
#include <limits.h> |
42 |
#include <unistd.h> |
43 |
#include <stdlib.h> |
44 |
#include <string.h> |
45 |
#include <stdio.h> |
46 |
#include <fcntl.h> |
47 |
#include <unistd.h> |
48 |
#include <assert.h> |
49 |
#include <errno.h> |
50 |
#include <libgen.h> /* for basename() */ |
51 |
|
52 |
#include "exec.h" |
53 |
|
54 |
#define SP_ALIGN(p) ((unsigned)(p) &~ _ALIGNBYTES) |
55 |
|
56 |
/* forward declarations */
|
57 |
static int build_args(task_t, void *, char *, struct exec_msg *, |
58 |
char *, char *, void **); |
59 |
static int conv_path(char *, char *, char *); |
60 |
static void notify_server(task_t, task_t, void *); |
61 |
static int read_header(char *); |
62 |
|
63 |
/*
|
64 |
* Buffer for file header
|
65 |
*/
|
66 |
static char hdrbuf[HEADER_SIZE]; |
67 |
|
68 |
/*
|
69 |
* Execute program
|
70 |
*/
|
71 |
int
|
72 |
exec_execve(struct exec_msg *msg)
|
73 |
{ |
74 |
struct exec_loader *ldr = NULL; |
75 |
int error, i;
|
76 |
task_t old_task, new_task; |
77 |
thread_t t; |
78 |
void *stack, *sp;
|
79 |
char path[PATH_MAX];
|
80 |
struct exec exec;
|
81 |
int rc;
|
82 |
|
83 |
DPRINTF(("exec_execve: path=%s task=%x\n", msg->path, msg->hdr.task));
|
84 |
|
85 |
old_task = msg->hdr.task; |
86 |
|
87 |
/*
|
88 |
* Make it full path.
|
89 |
*/
|
90 |
if ((error = conv_path(msg->cwd, msg->path, path)) != 0) { |
91 |
DPRINTF(("exec: invalid path\n"));
|
92 |
goto err1;
|
93 |
} |
94 |
|
95 |
/*
|
96 |
* Check permission.
|
97 |
*/
|
98 |
if (access(path, X_OK) == -1) { |
99 |
DPRINTF(("exec: no exec access\n"));
|
100 |
error = errno; |
101 |
goto err1;
|
102 |
} |
103 |
|
104 |
exec.path = path; |
105 |
exec.header = hdrbuf; |
106 |
exec.xarg1 = NULL;
|
107 |
exec.xarg2 = NULL;
|
108 |
|
109 |
again:
|
110 |
/*
|
111 |
* Read file header
|
112 |
*/
|
113 |
DPRINTF(("exec: read header for %s\n", exec.path));
|
114 |
if ((error = read_header(exec.path)) != 0) |
115 |
goto err1;
|
116 |
|
117 |
/*
|
118 |
* Find file loader
|
119 |
*/
|
120 |
rc = PROBE_ERROR; |
121 |
for (i = 0; i < nloader; i++) { |
122 |
ldr = &loader_table[i]; |
123 |
if ((rc = ldr->el_probe(&exec)) != PROBE_ERROR) {
|
124 |
break;
|
125 |
} |
126 |
} |
127 |
if (rc == PROBE_ERROR) {
|
128 |
DPRINTF(("exec: unsupported file format\n"));
|
129 |
error = ENOEXEC; |
130 |
goto err1;
|
131 |
} |
132 |
|
133 |
/*
|
134 |
* Check file header again if indirect case.
|
135 |
*/
|
136 |
if (rc == PROBE_INDIRECT)
|
137 |
goto again;
|
138 |
|
139 |
DPRINTF(("exec: loader=%s\n", ldr->el_name));
|
140 |
|
141 |
/*
|
142 |
* Check file permission.
|
143 |
*/
|
144 |
if (access(exec.path, X_OK) == -1) { |
145 |
DPRINTF(("exec: no exec access\n"));
|
146 |
error = errno; |
147 |
goto err1;
|
148 |
} |
149 |
|
150 |
/*
|
151 |
* Suspend old task
|
152 |
*/
|
153 |
if ((error = task_suspend(old_task)) != 0) |
154 |
goto err1;
|
155 |
|
156 |
/*
|
157 |
* Create new task
|
158 |
*/
|
159 |
if ((error = task_create(old_task, VM_NEW, &new_task)) != 0) { |
160 |
DPRINTF(("exec: failed to crete task\n"));
|
161 |
goto err1;
|
162 |
} |
163 |
|
164 |
if (*exec.path != '\0') |
165 |
task_setname(new_task, basename(exec.path)); |
166 |
|
167 |
/*
|
168 |
* Bind capabilities.
|
169 |
*/
|
170 |
bind_cap(exec.path, new_task); |
171 |
|
172 |
if ((error = thread_create(new_task, &t)) != 0) |
173 |
goto err3;
|
174 |
|
175 |
/*
|
176 |
* Allocate stack and build arguments on it.
|
177 |
*/
|
178 |
error = vm_allocate(new_task, &stack, DFLSTKSZ, 1);
|
179 |
if (error) {
|
180 |
DPRINTF(("exec: failed to allocate stack\n"));
|
181 |
goto err4;
|
182 |
} |
183 |
if ((error = build_args(new_task, stack, exec.path, msg,
|
184 |
exec.xarg1, exec.xarg2, &sp)) != 0)
|
185 |
goto err5;
|
186 |
|
187 |
/*
|
188 |
* Load file image.
|
189 |
*/
|
190 |
DPRINTF(("exec: load file image\n"));
|
191 |
exec.task = new_task; |
192 |
if ((error = ldr->el_load(&exec)) != 0) |
193 |
goto err5;
|
194 |
if ((error = thread_load(t, (void (*)(void))exec.entry, sp)) != 0) |
195 |
goto err5;
|
196 |
|
197 |
/*
|
198 |
* Notify to servers.
|
199 |
*/
|
200 |
notify_server(old_task, new_task, stack); |
201 |
|
202 |
/*
|
203 |
* Terminate old task.
|
204 |
*/
|
205 |
task_terminate(old_task); |
206 |
|
207 |
/*
|
208 |
* Set him running.
|
209 |
*/
|
210 |
thread_setpri(t, PRI_DEFAULT); |
211 |
thread_resume(t); |
212 |
|
213 |
DPRINTF(("exec done\n"));
|
214 |
return 0; |
215 |
err5:
|
216 |
vm_free(new_task, stack); |
217 |
err4:
|
218 |
thread_terminate(t); |
219 |
err3:
|
220 |
task_terminate(new_task); |
221 |
err1:
|
222 |
DPRINTF(("exec failed error=%d\n", error));
|
223 |
return error;
|
224 |
} |
225 |
|
226 |
/*
|
227 |
* Convert to full path from the cwd of task and path.
|
228 |
* @cwd: current working directory
|
229 |
* @path: target path
|
230 |
* @full: full path to be returned
|
231 |
*/
|
232 |
static int |
233 |
conv_path(char *cwd, char *path, char *full) |
234 |
{ |
235 |
char *src, *tgt, *p, *end;
|
236 |
size_t len = 0;
|
237 |
|
238 |
path[PATH_MAX - 1] = '\0'; |
239 |
len = strlen(path); |
240 |
if (len >= PATH_MAX)
|
241 |
return ENAMETOOLONG;
|
242 |
if (strlen(cwd) + len >= PATH_MAX)
|
243 |
return ENAMETOOLONG;
|
244 |
src = path; |
245 |
tgt = full; |
246 |
end = src + len; |
247 |
if (path[0] == '/') { |
248 |
*tgt++ = *src++; |
249 |
len++; |
250 |
} else {
|
251 |
strlcpy(full, cwd, PATH_MAX); |
252 |
len = strlen(cwd); |
253 |
tgt += len; |
254 |
if (len > 1 && path[0] != '.') { |
255 |
*tgt = '/';
|
256 |
tgt++; |
257 |
len++; |
258 |
} |
259 |
} |
260 |
while (*src) {
|
261 |
p = src; |
262 |
while (*p != '/' && *p != '\0') |
263 |
p++; |
264 |
*p = '\0';
|
265 |
if (!strcmp(src, "..")) { |
266 |
if (len >= 2) { |
267 |
len -= 2;
|
268 |
tgt -= 2; /* skip previous '/' */ |
269 |
while (*tgt != '/') { |
270 |
tgt--; |
271 |
len--; |
272 |
} |
273 |
if (len == 0) { |
274 |
tgt++; |
275 |
len++; |
276 |
} |
277 |
} |
278 |
} else if (!strcmp(src, ".")) { |
279 |
/* Ignore "." */
|
280 |
} else {
|
281 |
while (*src != '\0') { |
282 |
*tgt++ = *src++; |
283 |
len++; |
284 |
} |
285 |
} |
286 |
if (p == end)
|
287 |
break;
|
288 |
if (len > 0 && *(tgt - 1) != '/') { |
289 |
*tgt++ = '/';
|
290 |
len++; |
291 |
} |
292 |
src = p + 1;
|
293 |
} |
294 |
*tgt = '\0';
|
295 |
return 0; |
296 |
} |
297 |
|
298 |
/*
|
299 |
* Build argument on stack.
|
300 |
*
|
301 |
* Stack layout:
|
302 |
* file name string
|
303 |
* env string
|
304 |
* arg string
|
305 |
* NULL
|
306 |
* envp[n]
|
307 |
* NULL
|
308 |
* argv[n]
|
309 |
* argc
|
310 |
*
|
311 |
* NOTE: This may depend on processor architecture.
|
312 |
*/
|
313 |
static int |
314 |
build_args(task_t task, void *stack, char *path, struct exec_msg *msg, |
315 |
char *xarg1, char *xarg2, void **new_sp) |
316 |
{ |
317 |
int argc, envc;
|
318 |
char *file;
|
319 |
char **argv, **envp;
|
320 |
int i, error;
|
321 |
u_long arg_top, mapped, sp; |
322 |
int len;
|
323 |
|
324 |
argc = msg->argc; |
325 |
envc = msg->envc; |
326 |
DPRINTF(("exec: argc=%d envc=%d\n", argc, envc));
|
327 |
DPRINTF(("exec: xarg1=%s xarg2=%s\n", xarg1, xarg2));
|
328 |
|
329 |
/*
|
330 |
* Map target stack in current task.
|
331 |
*/
|
332 |
error = vm_map(task, stack, DFLSTKSZ, (void *)&mapped);
|
333 |
if (error)
|
334 |
return ENOMEM;
|
335 |
memset((void *)mapped, 0, DFLSTKSZ); |
336 |
sp = mapped + DFLSTKSZ - sizeof(int) * 3; |
337 |
|
338 |
/*
|
339 |
* Copy items
|
340 |
*/
|
341 |
|
342 |
/* File name */
|
343 |
*(char *)sp = '\0'; |
344 |
sp -= strlen(path); |
345 |
sp = SP_ALIGN(sp); |
346 |
strlcpy((char *)sp, path, PATH_MAX);
|
347 |
file = (char *)sp;
|
348 |
|
349 |
/* arg/env */
|
350 |
sp -= msg->bufsz; |
351 |
sp = SP_ALIGN(sp); |
352 |
memcpy((char *)sp, (char *)&msg->buf, msg->bufsz); |
353 |
arg_top = sp; |
354 |
|
355 |
/*
|
356 |
* Insert extra argument for indirect loader.
|
357 |
*/
|
358 |
if (xarg2 != NULL) { |
359 |
len = strlen(xarg2); |
360 |
sp -= (len + 1);
|
361 |
strlcpy((char *)sp, xarg2, len + 1); |
362 |
arg_top = sp; |
363 |
argc++; |
364 |
} |
365 |
if (xarg1 != NULL) { |
366 |
len = strlen(xarg1); |
367 |
sp -= (len + 1);
|
368 |
strlcpy((char *)sp, xarg1, len + 1); |
369 |
arg_top = sp; |
370 |
argc++; |
371 |
} |
372 |
|
373 |
/* envp[] */
|
374 |
sp -= ((envc + 1) * sizeof(char *)); |
375 |
envp = (char **)sp;
|
376 |
|
377 |
/* argv[] */
|
378 |
sp -= ((argc + 1) * sizeof(char *)); |
379 |
argv = (char **)sp;
|
380 |
|
381 |
/* argc */
|
382 |
sp -= sizeof(int); |
383 |
*(int *)(sp) = argc + 1; |
384 |
|
385 |
/*
|
386 |
* Build argument list
|
387 |
*/
|
388 |
argv[0] = (char *)((u_long)stack + (u_long)file - mapped); |
389 |
|
390 |
for (i = 1; i <= argc; i++) { |
391 |
argv[i] = (char *)((u_long)stack + (arg_top - mapped));
|
392 |
while ((*(char *)arg_top++) != '\0'); |
393 |
} |
394 |
argv[argc + 1] = NULL; |
395 |
|
396 |
for (i = 0; i < envc; i++) { |
397 |
envp[i] = (char *)((u_long)stack + (arg_top - mapped));
|
398 |
while ((*(char *)arg_top++) != '\0'); |
399 |
} |
400 |
envp[envc] = NULL;
|
401 |
|
402 |
*new_sp = (void *)((u_long)stack + (sp - mapped));
|
403 |
vm_free(task_self(), (void *)mapped);
|
404 |
|
405 |
return 0; |
406 |
} |
407 |
|
408 |
/*
|
409 |
* Notify exec() to servers.
|
410 |
*/
|
411 |
static void |
412 |
notify_server(task_t org_task, task_t new_task, void *stack)
|
413 |
{ |
414 |
struct msg m;
|
415 |
int error;
|
416 |
object_t fsobj, procobj; |
417 |
|
418 |
if (object_lookup("!fs", &fsobj) != 0) |
419 |
return;
|
420 |
|
421 |
if (object_lookup("!proc", &procobj) != 0) |
422 |
return;
|
423 |
|
424 |
/* Notify to file system server */
|
425 |
do {
|
426 |
m.hdr.code = FS_EXEC; |
427 |
m.data[0] = (int)org_task; |
428 |
m.data[1] = (int)new_task; |
429 |
error = msg_send(fsobj, &m, sizeof(m));
|
430 |
} while (error == EINTR);
|
431 |
|
432 |
/* Notify to process server */
|
433 |
do {
|
434 |
m.hdr.code = PS_EXEC; |
435 |
m.data[0] = (int)org_task; |
436 |
m.data[1] = (int)new_task; |
437 |
m.data[2] = (int)stack; |
438 |
error = msg_send(procobj, &m, sizeof(m));
|
439 |
} while (error == EINTR);
|
440 |
} |
441 |
|
442 |
static int |
443 |
read_header(char *path)
|
444 |
{ |
445 |
int fd;
|
446 |
struct stat st;
|
447 |
|
448 |
/*
|
449 |
* Check target file type.
|
450 |
*/
|
451 |
if ((fd = open(path, O_RDONLY)) == -1) |
452 |
return ENOENT;
|
453 |
|
454 |
if (fstat(fd, &st) == -1) { |
455 |
close(fd); |
456 |
return EIO;
|
457 |
} |
458 |
if (!S_ISREG(st.st_mode)) {
|
459 |
DPRINTF(("exec: not regular file\n"));
|
460 |
close(fd); |
461 |
return EACCES; /* must be regular file */ |
462 |
} |
463 |
/*
|
464 |
* Read file header.
|
465 |
*/
|
466 |
memset(hdrbuf, 0, HEADER_SIZE);
|
467 |
if (read(fd, hdrbuf, HEADER_SIZE) == -1) { |
468 |
close(fd); |
469 |
return EIO;
|
470 |
} |
471 |
close(fd); |
472 |
return 0; |
473 |
} |