/[path-sandbox]/trunk/src/sandbox.c
Gentoo

Contents of /trunk/src/sandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 152 - (show annotations) (download) (as text)
Wed Jul 27 18:04:35 2005 UTC (8 years, 11 months ago) by azarah
Original Path: trunk/sandbox.c
File MIME type: text/x-csrc
File size: 15285 byte(s)
Do not resolve symlinks in PORTAGE_TMPDIR in sandbox .. we will handle that
in libsandbox .. bug #100309.

1 /*
2 ** Path sandbox for the gentoo linux portage package system, initially
3 ** based on the ROCK Linux Wrapper for getting a list of created files
4 **
5 ** to integrate with bash, bash should have been built like this
6 **
7 ** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
8 **
9 ** it's very important that the --enable-static-link option is NOT specified
10 **
11 ** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
12 ** Distributed under the terms of the GNU General Public License, v2 or later
13 ** Author : Geert Bevin <gbevin@uwyn.com>
14 ** $Header$
15 */
16
17 /* #define _GNU_SOURCE */
18
19 #include <errno.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "sandbox.h"
30
31 struct sandbox_info_t {
32 char sandbox_log[SB_PATH_MAX];
33 char sandbox_debug_log[SB_PATH_MAX];
34 char sandbox_lib[SB_PATH_MAX];
35 char sandbox_rc[SB_PATH_MAX];
36 char portage_tmp_dir[SB_PATH_MAX];
37 char var_tmp_dir[SB_PATH_MAX];
38 char tmp_dir[SB_PATH_MAX];
39 char *home_dir;
40 } sandbox_info_t;
41
42 static char *tmp_dir;
43
44 static int print_debug = 0;
45 static int stop_called = 0;
46
47 int sandbox_setup(struct sandbox_info_t *sandbox_info)
48 {
49 /* Do not resolve symlinks, etc .. libsandbox will handle that. */
50 if (1 != is_dir(getenv(ENV_PORTAGE_TMPDIR) ? getenv(ENV_PORTAGE_TMPDIR)
51 : PORTAGE_TMPDIR, 1)) {
52 perror("sandbox: Failed to get portage_tmp_dir");
53 return -1;
54 }
55 snprintf(sandbox_info->portage_tmp_dir, SB_PATH_MAX, "%s",
56 getenv(ENV_PORTAGE_TMPDIR) ? getenv(ENV_PORTAGE_TMPDIR)
57 : PORTAGE_TMPDIR);
58 setenv(ENV_PORTAGE_TMPDIR, sandbox_info->portage_tmp_dir, 1);
59
60 /* Do not resolve symlinks, etc .. libsandbox will handle that. */
61 if (1 != is_dir(VAR_TMPDIR, 1)) {
62 perror("sandbox: Failed to get var_tmp_dir");
63 return -1;
64 }
65 snprintf(sandbox_info->var_tmp_dir, SB_PATH_MAX, "%s", VAR_TMPDIR);
66
67 if (-1 == get_tmp_dir(sandbox_info->tmp_dir)) {
68 perror("sandbox: Failed to get tmp_dir");
69 return -1;
70 }
71 tmp_dir = sandbox_info->tmp_dir;
72 setenv(ENV_TMPDIR, tmp_dir, 1);
73
74 sandbox_info->home_dir = getenv("HOME");
75 if (!sandbox_info->home_dir) {
76 sandbox_info->home_dir = tmp_dir;
77 setenv("HOME", sandbox_info->home_dir, 1);
78 }
79
80 /* Generate sandbox lib path */
81 get_sandbox_lib(sandbox_info->sandbox_lib);
82
83 /* Generate sandbox bashrc path */
84 get_sandbox_rc(sandbox_info->sandbox_rc);
85
86 /* Generate sandbox log full path */
87 get_sandbox_log(sandbox_info->sandbox_log);
88 if (1 == exists(sandbox_info->sandbox_log)) {
89 if (-1 == unlink(sandbox_info->sandbox_log)) {
90 perror("sandbox: Could not unlink old log file");
91 return -1;
92 }
93 }
94
95 /* Generate sandbox debug log full path */
96 get_sandbox_debug_log(sandbox_info->sandbox_debug_log);
97 if (1 == exists(sandbox_info->sandbox_debug_log)) {
98 if (-1 == unlink(sandbox_info->sandbox_debug_log)) {
99 perror("sandbox: Could not unlink old debug log file");
100 return -1;
101 }
102 }
103
104 return 0;
105 }
106
107 int print_sandbox_log(char *sandbox_log)
108 {
109 int sandbox_log_file = -1;
110 char *beep_count_env = NULL;
111 int i, color, beep_count = 0;
112 long len = 0;
113 char *buffer = NULL;
114
115 if (1 != is_file(sandbox_log)) {
116 perror("sandbox: Log file is not a regular file");
117 return 0;
118 }
119
120 sandbox_log_file = open(sandbox_log, O_RDONLY);
121 if (-1 == sandbox_log_file) {
122 perror("sandbox: Could not open Log file");
123 return 0;
124 }
125
126 len = file_length(sandbox_log_file);
127 buffer = (char *)malloc((len + 1) * sizeof(char));
128 memset(buffer, 0, len + 1);
129 read(sandbox_log_file, buffer, len);
130 close(sandbox_log_file);
131
132 color = ((getenv("NOCOLOR") != NULL) ? 0 : 1);
133
134 EERROR(color,
135 "--------------------------- ACCESS VIOLATION SUMMARY ---------------------------",
136 "\n");
137 EERROR(color, "LOG FILE = \"%s\"", "\n\n", sandbox_log);
138 fprintf(stderr, "%s", buffer);
139 if (NULL != buffer)
140 free(buffer);
141 EERROR(color,
142 "--------------------------------------------------------------------------------",
143 "\n");
144
145 beep_count_env = getenv(ENV_SANDBOX_BEEP);
146 if (beep_count_env)
147 beep_count = atoi(beep_count_env);
148 else
149 beep_count = DEFAULT_BEEP_COUNT;
150
151 for (i = 0; i < beep_count; i++) {
152 fputc('\a', stderr);
153 if (i < beep_count - 1)
154 sleep(1);
155 }
156
157 return 1;
158 }
159
160 void stop(int signum)
161 {
162 if (stop_called == 0) {
163 stop_called = 1;
164 printf("sandbox: Caught signal %d in pid %d\n",
165 signum, getpid());
166 } else {
167 fprintf(stderr,
168 "sandbox: Signal already caught and busy still cleaning up!\n");
169 }
170 }
171
172 void get_sandbox_write_envvar(char *buf, struct sandbox_info_t *sandbox_info)
173 {
174 /* bzero out entire buffer then append trailing 0 */
175 memset(buf, 0, SB_BUF_LEN);
176
177 /* these could go into make.globals later on */
178 snprintf(buf, SB_BUF_LEN,
179 "%s:%s/.gconfd/lock:%s/.bash_history:%s:%s:%s:%s",
180 "/dev/zero:/dev/null:/dev/fd:/proc/self/fd:/dev/pts/:"
181 "/dev/vc/:/dev/pty:/dev/tty:/dev/console:"
182 "/dev/shm/ngpt:/var/log/scrollkeeper.log:"
183 "/usr/tmp/conftest:/usr/lib/conftest:"
184 "/usr/lib32/conftest:/usr/lib64/conftest:"
185 "/usr/tmp/cf:/usr/lib/cf:/usr/lib32/cf:/usr/lib64/cf",
186 sandbox_info->home_dir, sandbox_info->home_dir,
187 (NULL != sandbox_info->portage_tmp_dir) ? sandbox_info->portage_tmp_dir : tmp_dir,
188 sandbox_info->tmp_dir, sandbox_info->var_tmp_dir,
189 "/tmp/:/var/tmp/");
190 }
191
192 void get_sandbox_predict_envvar(char *buf, struct sandbox_info_t *sandbox_info)
193 {
194 /* bzero out entire buffer then append trailing 0 */
195 memset(buf, 0, SB_BUF_LEN);
196
197 /* these should go into make.globals later on */
198 snprintf(buf, SB_BUF_LEN, "%s/.:"
199 "/usr/lib/python2.0/:"
200 "/usr/lib/python2.1/:"
201 "/usr/lib/python2.2/:"
202 "/usr/lib/python2.3/:"
203 "/usr/lib/python2.4/:"
204 "/usr/lib/python2.5/:"
205 "/usr/lib/python3.0/:"
206 "/var/db/aliases.db:"
207 "/var/db/netgroup.db:"
208 "/var/db/netmasks.db:"
209 "/var/db/ethers.db:"
210 "/var/db/rpc.db:"
211 "/var/db/protocols.db:"
212 "/var/db/services.db:"
213 "/var/db/networks.db:"
214 "/var/db/hosts.db:"
215 "/var/db/group.db:"
216 "/var/db/passwd.db",
217 sandbox_info->home_dir);
218 }
219
220 int sandbox_setenv(char **env, const char *name, const char *val) {
221 char **tmp_env = env;
222 char *tmp_string = NULL;
223
224 /* XXX: We add the new variable to the end (no replacing). If this
225 * is changed, we need to fix sandbox_setup_environ() below */
226 while (NULL != *tmp_env)
227 tmp_env++;
228
229 /* strlen(name) + strlen(val) + '=' + '\0' */
230 /* FIXME: Should probably free this at some stage - more neatness than
231 * a real leak that will cause issues. */
232 tmp_string = calloc(strlen(name) + strlen(val) + 2, sizeof(char *));
233 if (NULL == tmp_string) {
234 perror("sandbox: Out of memory (sandbox_setenv)");
235 exit(EXIT_FAILURE);
236 }
237
238 snprintf(tmp_string, strlen(name) + strlen(val) + 2, "%s=%s",
239 name, val);
240 *tmp_env = tmp_string;
241
242 return 0;
243 }
244
245 /* We setup the environment child side only to prevent issues with
246 * setting LD_PRELOAD parent side */
247 char **sandbox_setup_environ(struct sandbox_info_t *sandbox_info)
248 {
249 int env_size = 0;
250 int have_ld_preload = 0;
251
252 char **new_environ;
253 char **env_ptr = environ;
254 char sandbox_write_envvar[SB_BUF_LEN];
255 char sandbox_predict_envvar[SB_BUF_LEN];
256 char *ld_preload_envvar = NULL;
257 char *orig_ld_preload_envvar = NULL;
258
259 /* Unset these, as its easier than replacing when setting up our
260 * new environment below */
261 unsetenv(ENV_SANDBOX_LIB);
262 unsetenv(ENV_SANDBOX_BASHRC);
263 unsetenv(ENV_SANDBOX_LOG);
264 unsetenv(ENV_SANDBOX_DEBUG_LOG);
265
266 if (NULL != getenv(ENV_LD_PRELOAD)) {
267 have_ld_preload = 1;
268 orig_ld_preload_envvar = getenv(ENV_LD_PRELOAD);
269
270 /* FIXME: Should probably free this at some stage - more neatness
271 * than a real leak that will cause issues. */
272 ld_preload_envvar = calloc(strlen(orig_ld_preload_envvar) +
273 strlen(sandbox_info->sandbox_lib) + 2,
274 sizeof(char *));
275 if (NULL == ld_preload_envvar)
276 return NULL;
277 snprintf(ld_preload_envvar, strlen(orig_ld_preload_envvar) +
278 strlen(sandbox_info->sandbox_lib) + 2, "%s %s",
279 sandbox_info->sandbox_lib, orig_ld_preload_envvar);
280 } else {
281 /* FIXME: Should probably free this at some stage - more neatness
282 * than a real leak that will cause issues. */
283 ld_preload_envvar = strndup(sandbox_info->sandbox_lib,
284 strlen(sandbox_info->sandbox_lib));
285 if (NULL == ld_preload_envvar)
286 return NULL;
287 }
288 /* Do not unset this, as strange things might happen */
289 /* unsetenv(ENV_LD_PRELOAD); */
290
291 while (NULL != *env_ptr) {
292 env_size++;
293 env_ptr++;
294 }
295
296 /* FIXME: Should probably free this at some stage - more neatness than
297 * a real leak that will cause issues. */
298 new_environ = calloc((env_size + 15 + 1) * sizeof(char *), sizeof(char *));
299 if (NULL == new_environ)
300 return NULL;
301
302 /* First add our new variables to the beginning - this is due to some
303 * weirdness that I cannot remember */
304 sandbox_setenv(new_environ, ENV_SANDBOX_LIB, sandbox_info->sandbox_lib);
305 sandbox_setenv(new_environ, ENV_SANDBOX_BASHRC, sandbox_info->sandbox_rc);
306 sandbox_setenv(new_environ, ENV_SANDBOX_LOG, sandbox_info->sandbox_log);
307 sandbox_setenv(new_environ, ENV_SANDBOX_DEBUG_LOG,
308 sandbox_info->sandbox_debug_log);
309 /* If LD_PRELOAD was not set, set it here, else do it below */
310 if (1 != have_ld_preload)
311 sandbox_setenv(new_environ, ENV_LD_PRELOAD, ld_preload_envvar);
312
313 if (!getenv(ENV_SANDBOX_DENY))
314 sandbox_setenv(new_environ, ENV_SANDBOX_DENY, LD_PRELOAD_FILE);
315
316 if (!getenv(ENV_SANDBOX_READ))
317 sandbox_setenv(new_environ, ENV_SANDBOX_READ, "/");
318
319 get_sandbox_write_envvar(sandbox_write_envvar, sandbox_info);
320 if (!getenv(ENV_SANDBOX_WRITE))
321 sandbox_setenv(new_environ, ENV_SANDBOX_WRITE, sandbox_write_envvar);
322
323 get_sandbox_predict_envvar(sandbox_predict_envvar, sandbox_info);
324 if (!getenv(ENV_SANDBOX_PREDICT))
325 sandbox_setenv(new_environ, ENV_SANDBOX_PREDICT, sandbox_predict_envvar);
326
327 /* This one should NEVER be set in ebuilds, as it is the one
328 * private thing libsandbox.so use to test if the sandbox
329 * should be active for this pid, or not.
330 *
331 * azarah (3 Aug 2002)
332 */
333
334 sandbox_setenv(new_environ, "SANDBOX_ACTIVE", "armedandready");
335
336 env_size = 0;
337 while (NULL != new_environ[env_size])
338 env_size++;
339
340 /* Now add the rest */
341 env_ptr = environ;
342 while (NULL != *env_ptr) {
343 if ((1 == have_ld_preload) &&
344 (strstr(*env_ptr, LD_PRELOAD_EQ) == *env_ptr))
345 /* If LD_PRELOAD was set, and this is it in the original
346 * environment, replace it with our new copy */
347 /* XXX: The following works as it just add whatever as
348 * the last variable to nev_environ */
349 sandbox_setenv(new_environ, ENV_LD_PRELOAD,
350 ld_preload_envvar);
351 else
352 new_environ[env_size + (env_ptr - environ)] = *env_ptr;
353 env_ptr++;
354 }
355
356 return new_environ;
357 }
358
359 int spawn_shell(char *argv_bash[], char *env[], int debug)
360 {
361 int pid;
362 int status = 0;
363 int ret = 0;
364
365 pid = fork();
366
367 /* Child's process */
368 if (0 == pid) {
369 execve(argv_bash[0], argv_bash, env);
370 return 0;
371 } else if (pid < 0) {
372 if (debug)
373 fprintf(stderr, "Process failed to spawn!\n");
374 return 0;
375 }
376 ret = waitpid(pid, &status, 0);
377 if ((-1 == ret) || (status > 0)) {
378 if (debug)
379 fprintf(stderr, "Process returned with failed exit status!\n");
380 return 0;
381 }
382
383 return 1;
384 }
385
386 int main(int argc, char **argv)
387 {
388 int i = 0, success = 1;
389 int sandbox_log_presence = 0;
390 long len;
391
392 struct sandbox_info_t sandbox_info;
393
394 char **sandbox_environ;
395 char **argv_bash = NULL;
396
397 char *run_str = "-c";
398
399 /* Only print info if called with no arguments .... */
400 if (argc < 2)
401 print_debug = 1;
402
403 if (print_debug)
404 printf("========================== Gentoo linux path sandbox ===========================\n");
405
406 /* check if a sandbox is already running */
407 if (NULL != getenv(ENV_SANDBOX_ON)) {
408 fprintf(stderr, "Not launching a new sandbox instance\n");
409 fprintf(stderr, "Another one is already running in this process hierarchy.\n");
410 exit(EXIT_FAILURE);
411 }
412
413 /* determine the location of all the sandbox support files */
414 if (print_debug)
415 printf("Detection of the support files.\n");
416
417 if (-1 == sandbox_setup(&sandbox_info)) {
418 fprintf(stderr, "sandbox: Failed to setup sandbox.");
419 exit(EXIT_FAILURE);
420 }
421
422 /* verify the existance of required files */
423 if (print_debug)
424 printf("Verification of the required files.\n");
425
426 #ifndef SB_HAVE_64BIT_ARCH
427 if (0 >= exists(sandbox_info.sandbox_lib)) {
428 perror("sandbox: Could not open the sandbox library");
429 exit(EXIT_FAILURE);
430 }
431 #endif
432 if (0 >= exists(sandbox_info.sandbox_rc)) {
433 perror("sandbox: Could not open the sandbox rc file");
434 exit(EXIT_FAILURE);
435 }
436
437 /* set up the required environment variables */
438 if (print_debug)
439 printf("Setting up the required environment variables.\n");
440
441 /* This one should not be child only, as we check above to see
442 * if we are already running (check sandbox_setup_environ).
443 * This needs to be set before calling sandbox_setup_environ(),
444 * else its not set for the child */
445 setenv(ENV_SANDBOX_ON, "1", 0);
446
447 /* Setup the child environment stuff */
448 sandbox_environ = sandbox_setup_environ(&sandbox_info);
449 if (NULL == sandbox_environ) {
450 perror("sandbox: Out of memory (environ)");
451 exit(EXIT_FAILURE);
452 }
453
454 /* if the portage temp dir was present, cd into it */
455 if (NULL != sandbox_info.portage_tmp_dir)
456 chdir(sandbox_info.portage_tmp_dir);
457
458 argv_bash = (char **)malloc(6 * sizeof(char *));
459 argv_bash[0] = strdup("/bin/bash");
460 argv_bash[1] = strdup("-rcfile");
461 argv_bash[2] = strdup(sandbox_info.sandbox_rc);
462
463 if (argc < 2)
464 argv_bash[3] = NULL;
465 else
466 argv_bash[3] = strdup(run_str); /* "-c" */
467
468 argv_bash[4] = NULL; /* strdup(run_arg); */
469 argv_bash[5] = NULL;
470
471 if (argc >= 2) {
472 for (i = 1; i < argc; i++) {
473 if (NULL == argv_bash[4])
474 len = 0;
475 else
476 len = strlen(argv_bash[4]);
477
478 argv_bash[4] = (char *)realloc(argv_bash[4],
479 (len + strlen(argv[i]) + 2) * sizeof(char));
480
481 if (0 == len)
482 argv_bash[4][0] = 0;
483 if (1 != i)
484 strcat(argv_bash[4], " ");
485
486 strcat(argv_bash[4], argv[i]);
487 }
488 }
489
490 /* set up the required signal handlers */
491 signal(SIGHUP, &stop);
492 signal(SIGINT, &stop);
493 signal(SIGQUIT, &stop);
494 signal(SIGTERM, &stop);
495
496 /* STARTING PROTECTED ENVIRONMENT */
497 if (print_debug) {
498 printf("The protected environment has been started.\n");
499 printf("--------------------------------------------------------------------------------\n");
500 }
501
502 if (print_debug)
503 printf("Process being started in forked instance.\n");
504
505 /* Start Bash */
506 if (!spawn_shell(argv_bash, sandbox_environ, print_debug))
507 success = 0;
508
509 /* Free bash stuff */
510 for (i = 0; i < 6; i++) {
511 if (argv_bash[i])
512 free(argv_bash[i]);
513 argv_bash[i] = NULL;
514 }
515 if (argv_bash)
516 free(argv_bash);
517 argv_bash = NULL;
518
519 if (print_debug)
520 printf("Cleaning up sandbox process\n");
521
522 if (print_debug) {
523 printf("========================== Gentoo linux path sandbox ===========================\n");
524 printf("The protected environment has been shut down.\n");
525 }
526
527 if (1 == exists(sandbox_info.sandbox_log)) {
528 sandbox_log_presence = 1;
529 print_sandbox_log(sandbox_info.sandbox_log);
530 } else if (print_debug) {
531 printf("--------------------------------------------------------------------------------\n");
532 }
533
534 if ((sandbox_log_presence) || (!success))
535 return 1;
536 else
537 return 0;
538 }
539
540 // vim:noexpandtab noai:cindent ai

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20