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

Contents of /trunk/src/sandbox.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 429 - (show annotations) (download) (as text)
Sun Nov 16 14:39:45 2008 UTC (5 years, 9 months ago) by vapier
File MIME type: text/x-csrc
File size: 10456 byte(s)
make -h/--help/-V/--version options to sandbox print out something useful
1 /*
2 * sandbox.c
3 *
4 * Main sandbox related functions.
5 *
6 * Copyright 1999-2008 Gentoo Foundation
7 * Licensed under the GPL-2
8 *
9 * Some parts might have Copyright:
10 *
11 * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>
12 */
13
14 #include "headers.h"
15 #include "sbutil.h"
16 #include "sandbox.h"
17
18 static int print_debug = 0;
19
20 volatile static int stop_called = 0;
21 volatile static pid_t child_pid = 0;
22
23 static char log_domain[] = "sandbox";
24 static const char sandbox_banner[] = "============================= Gentoo path sandbox ==============================";
25
26 int setup_sandbox(struct sandbox_info_t *sandbox_info, bool interactive)
27 {
28 if (NULL != getenv(ENV_PORTAGE_TMPDIR)) {
29 /* Portage handle setting SANDBOX_WRITE itself. */
30 sandbox_info->work_dir[0] = '\0';
31 } else {
32 if (NULL == getcwd(sandbox_info->work_dir, SB_PATH_MAX)) {
33 perror("sandbox: Failed to get current directory");
34 return -1;
35 }
36 if (interactive)
37 setenv(ENV_SANDBOX_WORKDIR, sandbox_info->work_dir, 1);
38 }
39
40 /* Do not resolve symlinks, etc .. libsandbox will handle that. */
41 if (!rc_is_dir(VAR_TMPDIR, true)) {
42 perror("sandbox: Failed to get var_tmp_dir");
43 return -1;
44 }
45 snprintf(sandbox_info->var_tmp_dir, SB_PATH_MAX, "%s", VAR_TMPDIR);
46
47 if (-1 == get_tmp_dir(sandbox_info->tmp_dir)) {
48 perror("sandbox: Failed to get tmp_dir");
49 return -1;
50 }
51 setenv(ENV_TMPDIR, sandbox_info->tmp_dir, 1);
52
53 sandbox_info->home_dir = getenv("HOME");
54 if (!sandbox_info->home_dir) {
55 sandbox_info->home_dir = sandbox_info->tmp_dir;
56 setenv("HOME", sandbox_info->home_dir, 1);
57 }
58
59 /* Generate sandbox lib path */
60 get_sandbox_lib(sandbox_info->sandbox_lib);
61
62 /* Generate sandbox bashrc path */
63 get_sandbox_rc(sandbox_info->sandbox_rc);
64
65 /* Generate sandbox log full path */
66 get_sandbox_log(sandbox_info->sandbox_log);
67 if (rc_file_exists(sandbox_info->sandbox_log)) {
68 if (-1 == unlink(sandbox_info->sandbox_log)) {
69 perror("sandbox: Could not unlink old log file");
70 return -1;
71 }
72 }
73
74 /* Generate sandbox debug log full path */
75 get_sandbox_debug_log(sandbox_info->sandbox_debug_log);
76 if (rc_file_exists(sandbox_info->sandbox_debug_log)) {
77 if (-1 == unlink(sandbox_info->sandbox_debug_log)) {
78 perror("sandbox: Could not unlink old debug log file");
79 return -1;
80 }
81 }
82
83 return 0;
84 }
85
86 int print_sandbox_log(char *sandbox_log)
87 {
88 int sandbox_log_file = -1;
89 char *beep_count_env = NULL;
90 int i, beep_count = 0;
91 off_t len = 0;
92 char *buffer = NULL;
93
94 if (!rc_is_file(sandbox_log, false)) {
95 perror("sandbox: Log file is not a regular file");
96 return 0;
97 }
98
99 len = rc_get_size(sandbox_log, true);
100 if (0 == len)
101 return 0;
102
103 sandbox_log_file = sb_open(sandbox_log, O_RDONLY, 0);
104 if (-1 == sandbox_log_file) {
105 perror("sandbox: Could not open Log file");
106 return 0;
107 }
108
109 buffer = xmalloc((len + 1) * sizeof(char));
110 if (NULL == buffer) {
111 perror("sandbox: Could not allocate buffer for Log file");
112 return 0;
113 }
114 memset(buffer, 0, len + 1);
115 if (-1 == sb_read(sandbox_log_file, buffer, len)) {
116 perror("sandbox: Could read Log file");
117 return 0;
118 }
119 sb_close(sandbox_log_file);
120
121 SB_EERROR(
122 "--------------------------- ACCESS VIOLATION SUMMARY ---------------------------",
123 "\n");
124 SB_EERROR("LOG FILE", " \"%s\"\n\n", sandbox_log);
125 fprintf(stderr, "%s", buffer);
126 free(buffer);
127 SB_EERROR(
128 "--------------------------------------------------------------------------------",
129 "\n");
130
131 beep_count_env = getenv(ENV_SANDBOX_BEEP);
132 if (beep_count_env)
133 beep_count = atoi(beep_count_env);
134 else
135 beep_count = DEFAULT_BEEP_COUNT;
136
137 for (i = 0; i < beep_count; i++) {
138 fputc('\a', stderr);
139 if (i < beep_count - 1)
140 sleep(1);
141 }
142
143 return 1;
144 }
145
146 void stop(int signum)
147 {
148 if (0 == stop_called) {
149 stop_called = 1;
150 printf("sandbox: Caught signal %d in pid %d\n",
151 signum, getpid());
152 } else {
153 fprintf(stderr,
154 "sandbox: Signal already caught and busy still cleaning up!\n");
155 }
156 }
157
158 void usr1_handler(int signum, siginfo_t *siginfo, void *ucontext)
159 {
160 if (0 == stop_called) {
161 stop_called = 1;
162 printf("sandbox: Caught signal %d in pid %d\n",
163 signum, getpid());
164
165 /* FIXME: This is really bad form, as we should kill the whole process
166 * tree, but currently that is too much work and not worth the
167 * effort. Thus we only kill the calling process and our child
168 * for now.
169 */
170 if (siginfo->si_pid > 0)
171 kill(siginfo->si_pid, SIGKILL);
172 kill(child_pid, SIGKILL);
173 } else {
174 fprintf(stderr,
175 "sandbox: Signal already caught and busy still cleaning up!\n");
176 }
177 }
178
179 int spawn_shell(char *argv_bash[], char **env, int debug)
180 {
181 int status = 0;
182 int ret = 0;
183
184 child_pid = fork();
185
186 /* Child's process */
187 if (0 == child_pid) {
188 int ret = execve(argv_bash[0], argv_bash, env);
189 perror("sandbox: Failed to exec child");
190 _exit(ret);
191 } else if (child_pid < 0) {
192 if (debug)
193 fprintf(stderr, "Process failed to spawn!\n");
194 return 0;
195 }
196
197 /* fork() creates a copy of this, so no need to use more memory than
198 * absolutely needed. */
199 str_list_free(argv_bash);
200 str_list_free(env);
201
202 ret = waitpid(child_pid, &status, 0);
203 if (-1 == ret) {
204 perror("sandbox: Failed to waitpid for child");
205 return 0;
206 } else if (status != 0) {
207 if (WIFSIGNALED(status))
208 psignal(WTERMSIG(status), "Sandboxed process killed by signal");
209 else if (debug)
210 fprintf(stderr, "Process returned with failed exit status %d!\n", WEXITSTATUS(status));
211 return 0;
212 }
213
214 return 1;
215 }
216
217 int main(int argc, char **argv)
218 {
219 struct sigaction act_new;
220
221 int success = 1;
222 int sandbox_log_presence = 0;
223
224 struct sandbox_info_t sandbox_info;
225
226 char **sandbox_environ;
227 char **argv_bash = NULL;
228
229 char *run_str = "-c";
230
231 rc_log_domain(log_domain);
232
233 /* Only print info if called with no arguments .... */
234 if (argc < 2)
235 print_debug = 1;
236 else {
237 /* handle a few common options */
238 if (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V")) {
239 puts(
240 "Gentoo path sandbox\n"
241 " version: " PACKAGE_VERSION "\n"
242 " C lib: " LIBC_VERSION "\n"
243 " build: " __DATE__ " " __TIME__ "\n"
244 " contact: " PACKAGE_BUGREPORT " via http://bugs.gentoo.org/\n"
245 " rtld: "
246 #ifdef BROKEN_RTLD_NEXT
247 "next is broken ;(\n"
248 #else
249 "next is OK! :D\n"
250 #endif
251 "\nconfigured with these options:\n"
252 SANDBOX_CONFIGURE_OPTS
253 );
254 return 0;
255 } else if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
256 puts(
257 "Usage: sandbox [program [program args...]]\n"
258 "\n"
259 "Sandbox will start up a sandbox session and execute the specified program.\n"
260 "If no program is specified, an interactive shell is automatically launched.\n"
261 "You can use this to quickly test out sandbox behavior.\n"
262 "\n"
263 "Upon startup, initial settings are taken from these files / directories:\n"
264 "\t" SANDBOX_CONF_FILE "\n"
265 "\t" SANDBOX_CONFD_DIR "\n"
266 "\n"
267 "Contact: " PACKAGE_BUGREPORT " via http://bugs.gentoo.org/"
268 );
269 return 0;
270 }
271 }
272
273 if (print_debug)
274 puts(sandbox_banner);
275
276 /* check if a sandbox is already running */
277 if (NULL != getenv(ENV_SANDBOX_ACTIVE)) {
278 fprintf(stderr, "Not launching a new sandbox instance\n");
279 fprintf(stderr, "Another one is already running in this process hierarchy.\n");
280 exit(EXIT_FAILURE);
281 }
282
283 /* determine the location of all the sandbox support files */
284 if (print_debug)
285 printf("Detection of the support files.\n");
286
287 if (-1 == setup_sandbox(&sandbox_info, print_debug)) {
288 fprintf(stderr, "sandbox: Failed to setup sandbox.");
289 exit(EXIT_FAILURE);
290 }
291
292 /* verify the existance of required files */
293 if (print_debug)
294 printf("Verification of the required files.\n");
295
296 if (!rc_file_exists(sandbox_info.sandbox_rc)) {
297 perror("sandbox: Could not open the sandbox rc file");
298 exit(EXIT_FAILURE);
299 }
300
301 /* set up the required environment variables */
302 if (print_debug)
303 printf("Setting up the required environment variables.\n");
304
305 /* If not in portage, cd into it work directory */
306 if ('\0' != sandbox_info.work_dir[0])
307 chdir(sandbox_info.work_dir);
308
309 /* Setup the child environment stuff.
310 * XXX: We free this in spawn_shell(). */
311 sandbox_environ = setup_environ(&sandbox_info, print_debug);
312 if (NULL == sandbox_environ)
313 goto oom_error;
314
315 /* Setup bash argv */
316 str_list_add_item_copy(argv_bash, "/bin/bash", oom_error);
317 str_list_add_item_copy(argv_bash, "-rcfile", oom_error);
318 str_list_add_item_copy(argv_bash, sandbox_info.sandbox_rc, oom_error);
319 if (argc >= 2) {
320 int i;
321
322 str_list_add_item_copy(argv_bash, run_str, oom_error);
323 str_list_add_item_copy(argv_bash, argv[1], oom_error);
324 for (i = 2; i < argc; i++) {
325 char *tmp_ptr;
326
327 tmp_ptr = xrealloc(argv_bash[4],
328 (strlen(argv_bash[4]) +
329 strlen(argv[i]) + 2) *
330 sizeof(char));
331 if (NULL == tmp_ptr)
332 goto oom_error;
333 argv_bash[4] = tmp_ptr;
334
335 snprintf(argv_bash[4] + strlen(argv_bash[4]),
336 strlen(argv[i]) + 2, " %s",
337 argv[i]);
338 }
339 }
340
341 /* set up the required signal handlers */
342 signal(SIGHUP, &stop);
343 signal(SIGINT, &stop);
344 signal(SIGQUIT, &stop);
345 signal(SIGTERM, &stop);
346 act_new.sa_sigaction = usr1_handler;
347 sigemptyset (&act_new.sa_mask);
348 act_new.sa_flags = SA_SIGINFO | SA_RESTART;
349 sigaction (SIGUSR1, &act_new, NULL);
350
351 /* STARTING PROTECTED ENVIRONMENT */
352 if (print_debug) {
353 printf("The protected environment has been started.\n");
354 printf("--------------------------------------------------------------------------------\n");
355 }
356
357 if (print_debug)
358 printf("Process being started in forked instance.\n");
359
360 /* Start Bash */
361 if (!spawn_shell(argv_bash, sandbox_environ, print_debug))
362 success = 0;
363
364 /* As spawn_shell() free both argv_bash and sandbox_environ, make sure
365 * we do not run into issues in future if we need a OOM error below
366 * this ... */
367 argv_bash = NULL;
368 sandbox_environ = NULL;
369
370 if (print_debug)
371 printf("Cleaning up sandbox process\n");
372
373 if (print_debug) {
374 puts(sandbox_banner);
375 printf("The protected environment has been shut down.\n");
376 }
377
378 if (rc_file_exists(sandbox_info.sandbox_log)) {
379 sandbox_log_presence = 1;
380 print_sandbox_log(sandbox_info.sandbox_log);
381 } else if (print_debug) {
382 printf("--------------------------------------------------------------------------------\n");
383 }
384
385 if ((sandbox_log_presence) || (!success))
386 return 1;
387 else
388 return 0;
389
390 oom_error:
391 if (NULL != argv_bash)
392 str_list_free(argv_bash);
393
394 perror("sandbox: Out of memory (environ)");
395 exit(EXIT_FAILURE);
396 }

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.20