|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/exec/exec_execve.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.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 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |