source: mainline/uspace/srv/loader/main.c@ 5d96851b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5d96851b was 5d96851b, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Pass task ID to NS from loader. This prevents ID spoofing by user apps.

  • Property mode set to 100644
File size: 9.7 KB
RevLine 
[c98e6ee]1/*
2 * Copyright (c) 2008 Jiri Svoboda
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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup loader
[2f57690]30 * @brief Loads and runs programs from VFS.
[c98e6ee]31 * @{
[2f57690]32 */
[c98e6ee]33/**
34 * @file
[2f57690]35 * @brief Loads and runs programs from VFS.
[c98e6ee]36 *
37 * The program loader is a special init binary. Its image is used
38 * to create a new task upon a @c task_spawn syscall. The syscall
39 * returns the id of a phone connected to the newly created task.
40 *
41 * The caller uses this phone to send the pathname and various other
42 * information to the loader. This is normally done by the C library
43 * and completely hidden from applications.
44 */
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <unistd.h>
[4470e26]49#include <bool.h>
[c98e6ee]50#include <fcntl.h>
51#include <sys/types.h>
52#include <ipc/ipc.h>
[bfd1546]53#include <ipc/services.h>
[c98e6ee]54#include <ipc/loader.h>
[5d96851b]55#include <ipc/ns.h>
56#include <macros.h>
[c98e6ee]57#include <loader/pcb.h>
58#include <errno.h>
59#include <async.h>
[bbdbf86]60#include <string.h>
[c98e6ee]61#include <as.h>
62
63#include <elf.h>
64#include <elf_load.h>
65
[06b2b7f]66#define DPRINTF(...)
67
[c98e6ee]68/** Pathname of the file that will be loaded */
69static char *pathname = NULL;
70
71/** The Program control block */
72static pcb_t pcb;
73
74/** Number of arguments */
75static int argc = 0;
76/** Argument vector */
77static char **argv = NULL;
78/** Buffer holding all arguments */
79static char *arg_buf = NULL;
80
[bbdbf86]81/** Number of preset files */
82static int filc = 0;
83/** Preset files vector */
[08c9f7d5]84static fdi_node_t **filv = NULL;
[bbdbf86]85/** Buffer holding all preset files */
[99272a3]86static fdi_node_t *fil_buf = NULL;
[bbdbf86]87
[4470e26]88static elf_info_t prog_info;
89static elf_info_t interp_info;
90
91static bool is_dyn_linked;
92
[bfd1546]93/** Used to limit number of connections to one. */
94static bool connected;
[4470e26]95
[bbdbf86]96static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]97{
98 ipc_callid_t callid;
99 task_id_t task_id;
100 size_t len;
[2f57690]101
[47e0a05b]102 task_id = task_get_id();
[2f57690]103
[47e0a05b]104 if (!ipc_data_read_receive(&callid, &len)) {
105 ipc_answer_0(callid, EINVAL);
106 ipc_answer_0(rid, EINVAL);
107 return;
108 }
[2f57690]109
110 if (len > sizeof(task_id))
111 len = sizeof(task_id);
112
[0993087]113 ipc_data_read_finalize(callid, &task_id, len);
[47e0a05b]114 ipc_answer_0(rid, EOK);
115}
116
117
[c98e6ee]118/** Receive a call setting pathname of the program to execute.
119 *
120 * @param rid
121 * @param request
122 */
[bbdbf86]123static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]124{
125 ipc_callid_t callid;
126 size_t len;
127 char *name_buf;
[2f57690]128
[c98e6ee]129 if (!ipc_data_write_receive(&callid, &len)) {
130 ipc_answer_0(callid, EINVAL);
131 ipc_answer_0(rid, EINVAL);
132 return;
133 }
[2f57690]134
[c98e6ee]135 name_buf = malloc(len + 1);
136 if (!name_buf) {
137 ipc_answer_0(callid, ENOMEM);
138 ipc_answer_0(rid, ENOMEM);
139 return;
140 }
[2f57690]141
[c98e6ee]142 ipc_data_write_finalize(callid, name_buf, len);
143 ipc_answer_0(rid, EOK);
[2f57690]144
[c98e6ee]145 if (pathname != NULL) {
146 free(pathname);
147 pathname = NULL;
148 }
[2f57690]149
[c98e6ee]150 name_buf[len] = '\0';
151 pathname = name_buf;
152}
153
154/** Receive a call setting arguments of the program to execute.
155 *
156 * @param rid
157 * @param request
158 */
[bbdbf86]159static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]160{
161 ipc_callid_t callid;
[92fd52d7]162 size_t buf_size, arg_size;
[c98e6ee]163 char *p;
164 int n;
[2f57690]165
[92fd52d7]166 if (!ipc_data_write_receive(&callid, &buf_size)) {
[c98e6ee]167 ipc_answer_0(callid, EINVAL);
168 ipc_answer_0(rid, EINVAL);
169 return;
170 }
[2f57690]171
[c98e6ee]172 if (arg_buf != NULL) {
173 free(arg_buf);
174 arg_buf = NULL;
175 }
[2f57690]176
[c98e6ee]177 if (argv != NULL) {
178 free(argv);
179 argv = NULL;
180 }
[2f57690]181
[92fd52d7]182 arg_buf = malloc(buf_size + 1);
[c98e6ee]183 if (!arg_buf) {
184 ipc_answer_0(callid, ENOMEM);
185 ipc_answer_0(rid, ENOMEM);
186 return;
187 }
[2f57690]188
[92fd52d7]189 ipc_data_write_finalize(callid, arg_buf, buf_size);
[2f57690]190
[92fd52d7]191 arg_buf[buf_size] = '\0';
[2f57690]192
[c98e6ee]193 /*
194 * Count number of arguments
195 */
196 p = arg_buf;
197 n = 0;
[92fd52d7]198 while (p < arg_buf + buf_size) {
199 arg_size = str_size(p);
200 p = p + arg_size + 1;
[c98e6ee]201 ++n;
202 }
[2f57690]203
[c98e6ee]204 /* Allocate argv */
205 argv = malloc((n + 1) * sizeof(char *));
[2f57690]206
[c98e6ee]207 if (argv == NULL) {
208 free(arg_buf);
209 ipc_answer_0(rid, ENOMEM);
210 return;
211 }
[482c86f]212
[c98e6ee]213 /*
214 * Fill argv with argument pointers
215 */
216 p = arg_buf;
217 n = 0;
[92fd52d7]218 while (p < arg_buf + buf_size) {
[c98e6ee]219 argv[n] = p;
[2f57690]220
[92fd52d7]221 arg_size = str_size(p);
222 p = p + arg_size + 1;
[c98e6ee]223 ++n;
224 }
[2f57690]225
[c98e6ee]226 argc = n;
227 argv[n] = NULL;
[482c86f]228
229 ipc_answer_0(rid, EOK);
[c98e6ee]230}
231
[bbdbf86]232/** Receive a call setting preset files of the program to execute.
233 *
234 * @param rid
235 * @param request
236 */
237static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
238{
239 ipc_callid_t callid;
240 size_t buf_size;
241 if (!ipc_data_write_receive(&callid, &buf_size)) {
242 ipc_answer_0(callid, EINVAL);
243 ipc_answer_0(rid, EINVAL);
244 return;
245 }
246
[99272a3]247 if ((buf_size % sizeof(fdi_node_t)) != 0) {
[bbdbf86]248 ipc_answer_0(callid, EINVAL);
249 ipc_answer_0(rid, EINVAL);
250 return;
251 }
252
253 if (fil_buf != NULL) {
254 free(fil_buf);
255 fil_buf = NULL;
256 }
257
258 if (filv != NULL) {
259 free(filv);
260 filv = NULL;
261 }
262
263 fil_buf = malloc(buf_size);
264 if (!fil_buf) {
265 ipc_answer_0(callid, ENOMEM);
266 ipc_answer_0(rid, ENOMEM);
267 return;
268 }
269
270 ipc_data_write_finalize(callid, fil_buf, buf_size);
271
[99272a3]272 int count = buf_size / sizeof(fdi_node_t);
[bbdbf86]273
274 /* Allocate filvv */
[99272a3]275 filv = malloc((count + 1) * sizeof(fdi_node_t *));
[bbdbf86]276
277 if (filv == NULL) {
278 free(fil_buf);
279 ipc_answer_0(rid, ENOMEM);
280 return;
281 }
282
283 /*
284 * Fill filv with argument pointers
285 */
286 int i;
287 for (i = 0; i < count; i++)
288 filv[i] = &fil_buf[i];
289
290 filc = count;
291 filv[count] = NULL;
292
293 ipc_answer_0(rid, EOK);
294}
295
[4470e26]296/** Load the previously selected program.
[c98e6ee]297 *
298 * @param rid
299 * @param request
300 * @return 0 on success, !0 on error.
301 */
[bbdbf86]302static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]303{
304 int rc;
[2f57690]305
[c98e6ee]306 rc = elf_load_file(pathname, 0, &prog_info);
[409b0d6]307 if (rc != EE_OK) {
[06b2b7f]308 DPRINTF("Failed to load executable '%s'.\n", pathname);
[c98e6ee]309 ipc_answer_0(rid, EINVAL);
310 return 1;
311 }
[2f57690]312
[c98e6ee]313 elf_create_pcb(&prog_info, &pcb);
[2f57690]314
[c98e6ee]315 pcb.argc = argc;
316 pcb.argv = argv;
[2f57690]317
[bbdbf86]318 pcb.filc = filc;
319 pcb.filv = filv;
320
[c98e6ee]321 if (prog_info.interp == NULL) {
322 /* Statically linked program */
[4470e26]323 is_dyn_linked = false;
[c98e6ee]324 ipc_answer_0(rid, EOK);
325 return 0;
326 }
[2f57690]327
[49093a4]328 rc = elf_load_file(prog_info.interp, 0, &interp_info);
[409b0d6]329 if (rc != EE_OK) {
[06b2b7f]330 DPRINTF("Failed to load interpreter '%s.'\n",
331 prog_info.interp);
[c98e6ee]332 ipc_answer_0(rid, EINVAL);
333 return 1;
334 }
[2f57690]335
[4470e26]336 is_dyn_linked = true;
[c98e6ee]337 ipc_answer_0(rid, EOK);
[2f57690]338
[c98e6ee]339 return 0;
340}
341
[4470e26]342
343/** Run the previously loaded program.
344 *
345 * @param rid
346 * @param request
347 * @return 0 on success, !0 on error.
348 */
[bbdbf86]349static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
[4470e26]350{
[20f1597]351 const char *cp;
[2f57690]352
[bc18d63]353 /* Set the task name. */
[7afb4a5]354 cp = str_rchr(pathname, '/');
[20f1597]355 cp = (cp == NULL) ? pathname : (cp + 1);
356 task_set_name(cp);
[2f57690]357
[4470e26]358 if (is_dyn_linked == true) {
359 /* Dynamically linked program */
[06b2b7f]360 DPRINTF("Run ELF interpreter.\n");
361 DPRINTF("Entry point: 0x%lx\n", interp_info.entry);
[2f57690]362
[4470e26]363 ipc_answer_0(rid, EOK);
364 elf_run(&interp_info, &pcb);
365 } else {
366 /* Statically linked program */
367 ipc_answer_0(rid, EOK);
368 elf_run(&prog_info, &pcb);
[bbdbf86]369 }
370
[4470e26]371 /* Not reached */
372}
373
[c98e6ee]374/** Handle loader connection.
375 *
376 * Receive and carry out commands (of which the last one should be
377 * to execute the loaded program).
378 */
[bbdbf86]379static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
[c98e6ee]380{
381 ipc_callid_t callid;
382 ipc_call_t call;
383 int retval;
[2f57690]384
[bfd1546]385 /* Already have a connection? */
386 if (connected) {
387 ipc_answer_0(iid, ELIMIT);
388 return;
389 }
[2f57690]390
[bfd1546]391 connected = true;
392
393 /* Accept the connection */
394 ipc_answer_0(iid, EOK);
[2f57690]395
[c98e6ee]396 /* Ignore parameters, the connection is already open */
[2f57690]397 (void) iid;
398 (void) icall;
399
[c98e6ee]400 while (1) {
401 callid = async_get_call(&call);
[2f57690]402
[c98e6ee]403 switch (IPC_GET_METHOD(call)) {
[86e3d62]404 case IPC_M_PHONE_HUNGUP:
405 exit(0);
[47e0a05b]406 case LOADER_GET_TASKID:
[bbdbf86]407 ldr_get_taskid(callid, &call);
[47e0a05b]408 continue;
[c98e6ee]409 case LOADER_SET_PATHNAME:
[bbdbf86]410 ldr_set_pathname(callid, &call);
[c98e6ee]411 continue;
412 case LOADER_SET_ARGS:
[bbdbf86]413 ldr_set_args(callid, &call);
414 continue;
415 case LOADER_SET_FILES:
416 ldr_set_files(callid, &call);
[4470e26]417 continue;
418 case LOADER_LOAD:
[bbdbf86]419 ldr_load(callid, &call);
[4470e26]420 continue;
[c98e6ee]421 case LOADER_RUN:
[bbdbf86]422 ldr_run(callid, &call);
[4470e26]423 /* Not reached */
[c98e6ee]424 default:
425 retval = ENOENT;
426 break;
427 }
428 if ((callid & IPC_CALLID_NOTIFICATION) == 0 &&
429 IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP) {
[06b2b7f]430 DPRINTF("Responding EINVAL to method %d.\n",
[c98e6ee]431 IPC_GET_METHOD(call));
432 ipc_answer_0(callid, EINVAL);
433 }
434 }
435}
436
437/** Program loader main function.
438 */
439int main(int argc, char *argv[])
440{
[bfd1546]441 ipcarg_t phonead;
[5d96851b]442 task_id_t id;
443 int rc;
444
[bfd1546]445 connected = false;
[5d96851b]446
447 /* Introduce this task to the NS (give it our task ID). */
448 id = task_get_id();
449 rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
450 if (rc != EOK)
451 return -1;
452
[bfd1546]453 /* Set a handler of incomming connections. */
[bbdbf86]454 async_set_client_connection(ldr_connection);
[2f57690]455
[bfd1546]456 /* Register at naming service. */
457 if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0)
[5d96851b]458 return -2;
459
[c98e6ee]460 async_manager();
[2f57690]461
[bfd1546]462 /* Never reached */
[c98e6ee]463 return 0;
464}
465
466/** @}
467 */
Note: See TracBrowser for help on using the repository browser.