void onvif_set_UpgradeSystemFirmware_request(struct soap* soap, struct _tds__UpgradeSystemFirmware * req){ unsigned char* data; size_t size = 0; printf("enter %s\n", __FUNCTION__); memset(req, 0, sizeof(*req)); CHECK_FIELD(req->Firmware); data = load_file_data("1.bin", &size); if (data == NULL) { printf("empty file\n"); return; } printf("file size:%d\n", size); soap_set_field_string(soap, &req->Firmware->xmime__contentType, "binary"); req->Firmware->xop__Include.__size = min(64*1024,size); req->Firmware->xop__Include.__ptr = (unsigned char*) data; soap_set_field_string(soap, &req->Firmware->xop__Include.id, "id"); soap_set_field_string(soap, &req->Firmware->xop__Include.options, "option"); soap_set_field_string(soap, &req->Firmware->xop__Include.type, "text/html"); free(data); }
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test for fix selector THIS IS THE ONLY EXPORTED ROUTINE */ void apply_fix( tFixDesc* p_fixd, tCC* filname ) { #define _FT_(n,p) { n, p }, static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }}; #undef _FT_ #define FIX_TABLE_CT (ARRAY_SIZE (fix_table)-1) tCC* fixname = p_fixd->patch_args[0]; char* buf; int ct = FIX_TABLE_CT; fix_entry_t* pfe = fix_table; for (;;) { if (strcmp (pfe->fix_name, fixname) == 0) break; if (--ct <= 0) { fprintf (stderr, "fixincl error: the `%s' fix is unknown\n", fixname ); exit (EXIT_BROKEN); } pfe++; } buf = load_file_data (stdin); (*pfe->fix_proc)( filname, buf, p_fixd ); }
int load_file(char *file_name, char *lib_name) { struct object_file *o; unsigned char *data; static int id = 0; char *name; int size; o = malloc(sizeof(struct object_file)); name = malloc(strlen(file_name)+1); if (o == NULL || name == NULL) { if (o != NULL) free(o); if (name != NULL) free(name); fprintf(stderr, "LOAD_FILE: Out of memory.\n"); return FAILED; } if (load_file_data(file_name, &data, &size, lib_name) == FAILED) { free(name); free(o); return FAILED; } /* only valid for library files; bank 0 slot 0 base 0 assumed unless library is SUPERFREE */ o->bank = 0; o->slot = 0; o->base = 0; o->base_defined = OFF; /* init the rest of the variables */ o->source_file_names = NULL; o->memorymap = NULL; o->exported_defines = NULL; o->data_blocks = NULL; o->source_file_names_list = NULL; if (obj_first == NULL) { obj_first = o; obj_last = o; } else { obj_last->next = o; obj_last = o; } o->next = NULL; o->size = size; o->data = data; strcpy(name, file_name); o->name = name; o->id = id++; return SUCCEEDED; }
int load_file(char *fn, int state, int bank, int slot, int base, int base_defined) { struct object_file *o; unsigned char *data; static int id = 0; char *n; int size; o = malloc(sizeof(struct object_file)); n = malloc(strlen(fn)+1); if (o == NULL || n == NULL) { if (o != NULL) free(o); if (n != NULL) free(n); fprintf(stderr, "LOAD_FILE: Out of memory.\n"); return FAILED; } if (load_file_data(fn, &data, &size) == FAILED) { free(n); free(o); return FAILED; } /* only valid for library files */ o->bank = bank; o->slot = slot; o->base = base; o->base_defined = base_defined; /* init the rest of the variables */ o->source_file_names = NULL; o->memorymap = NULL; o->exported_defines = NULL; o->data_blocks = NULL; o->source_file_names_list = NULL; if (obj_first == NULL) { obj_first = o; obj_last = o; } else { obj_last->next = o; obj_last = o; } o->next = NULL; o->size = size; o->data = data; strcpy(n, fn); o->name = n; o->id = id++; return SUCCEEDED; }
/* * * * * * * * * * * * * load_file loads all the contents of a file into malloc-ed memory. Its argument is the name of the file to read in; the returned result is the NUL terminated contents of the file. The file is presumed to be an ASCII text file containing no NULs. */ char * load_file ( const char* fname ) { struct stat stbf; char* res; if (stat (fname, &stbf) != 0) { if (NOT_SILENT) fprintf (stderr, "error %d (%s) stat-ing %s\n", errno, xstrerror (errno), fname ); return (char *) NULL; } if (stbf.st_size == 0) return (char*)NULL; /* Make the data map size one larger than the file size for documentation purposes. Truth is that there will be a following NUL character if the file size is not a multiple of the page size. If it is a multiple, then this adjustment sometimes fails anyway. */ data_map_size = stbf.st_size+1; data_map_fd = open (fname, O_RDONLY); ttl_data_size += data_map_size-1; if (data_map_fd < 0) { if (NOT_SILENT) fprintf (stderr, "error %d (%s) opening %s for read\n", errno, xstrerror (errno), fname); return (char*)NULL; } #ifdef HAVE_MMAP_FILE curr_data_mapped = BOOL_TRUE; /* IF the file size is a multiple of the page size, THEN sometimes you will seg fault trying to access a trailing byte */ if ((stbf.st_size & (getpagesize()-1)) == 0) res = (char*)BAD_ADDR; else res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE, data_map_fd, 0); if (res == (char*)BAD_ADDR) #endif { FILE* fp = fdopen (data_map_fd, "r"); curr_data_mapped = BOOL_FALSE; res = load_file_data (fp); fclose (fp); } return res; }
/* Sets errno on error (== NULL), * Always ensures terminating zero */ char * load_file_at (int dirfd, const char *path) { int fd; char *data; int errsv; fd = openat (dirfd, path, O_CLOEXEC | O_RDONLY); if (fd == -1) return NULL; data = load_file_data (fd, NULL); errsv = errno; close (fd); errno = errsv; return data; }
int load_files(char *argv[], int argc) { int state = STATE_NONE, i, x, line, bank, slot, base, bank_defined, slot_defined, base_defined, n; char tmp[1024], token[1024], tmp_token[MAX_NAME_LENGTH]; struct label *l; FILE *fop, *f; fop = fopen(argv[argc - 2], "rb"); if (fop == NULL) { fprintf(stderr, "LOAD_FILES: Could not open file \"%s\".\n", argv[argc - 2]); return FAILED; } line = 0; while (fgets(tmp, 255, fop) != NULL) { line++; x = 0; if (tmp[0] == ';' || tmp[0] == '*' || tmp[0] == '#' || tmp[0] == 0x0D || tmp[0] == 0x0A) continue; /* remove garbage from the end */ for (i = 0; !(tmp[i] == 0x0D || tmp[i] == 0x0A || tmp[i] == 0x00); i++) ; tmp[i] = 0; /* empty line check */ if (get_next_token(tmp, token, &x) == FAILED) continue; /* first checks */ if (token[0] == '[') { if (strcmp("[objects]", token) == 0) { state = STATE_OBJECT; continue; } else if (strcmp("[libraries]", token) == 0) { state = STATE_LIBRARY; continue; } else if (strcmp("[header]", token) == 0) { state = STATE_HEADER; continue; } else if (strcmp("[footer]", token) == 0) { state = STATE_FOOTER; continue; } else if (strcmp("[definitions]", token) == 0) { state = STATE_DEFINITION; continue; } else { fprintf(stderr, "%s:%d LOAD_FILES: Unknown group \"%s\".\n", argv[argc - 2], line, token); fclose(fop); return FAILED; } } if (state == STATE_NONE) { fprintf(stderr, "%s:%d: LOAD_FILES: Before file \"%s\" can be loaded you must define a group for it.\n", argv[argc - 2], line, token); fclose(fop); return FAILED; } bank_defined = OFF; slot_defined = OFF; base_defined = OFF; bank = 0; slot = 0; base = 0; /* definition loading? */ if (state == STATE_DEFINITION) { l = calloc(1, sizeof(struct label)); if (l == NULL) { fprintf(stderr, "LOAD_FILES: Out of memory.\n"); return FAILED; } strcpy(l->name, token); l->status = LABEL_STATUS_DEFINE; l->bank = 0; l->slot = 0; l->base = 0; if (get_next_number(&tmp[x], &n, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in DEFINITION value.\n", argv[argc - 2], line); fclose(fop); return FAILED; } l->address = n; add_label(l); continue; } /* header loading? */ else if (state == STATE_HEADER) { if (file_header != NULL) { fprintf(stderr, "%s:%d: LOAD_FILES: There can be only one header file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (load_file_data(token, &file_header, &file_header_size) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], token, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } /* footer loading? */ else if (state == STATE_FOOTER) { if (file_footer != NULL) { fprintf(stderr, "%s:%d: LOAD_FILES: There can be only one footer file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (load_file_data(token, &file_footer, &file_footer_size) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], token, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } /* library loading? */ else if (state == STATE_LIBRARY) { i = SUCCEEDED; while (i == SUCCEEDED) { if (strcmp(token, "bank") == 0 || strcmp(token, "BANK") == 0) { if (bank_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: BANK defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } bank_defined = ON; if (get_next_number(&tmp[x], &bank, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in BANK number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else if (strcmp(token, "slot") == 0 || strcmp(token, "SLOT") == 0) { if (slot_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: SLOT defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } slot_defined = ON; if (get_next_number(&tmp[x], &slot, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in SLOT number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else if (strcmp(token, "base") == 0 || strcmp(token, "BASE") == 0) { if (base_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: BASE defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } base_defined = ON; if (get_next_number(&tmp[x], &base, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in BASE number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else break; i = get_next_token(&tmp[x], token, &x); } if (i == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: No library to load.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (slot_defined == OFF) { fprintf(stderr, "%s:%d: LOAD_FILES: Library file requires a SLOT.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (bank_defined == OFF) { fprintf(stderr, "%s:%d: LOAD_FILES: Library file requires a BANK.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (use_libdir == YES) { f = fopen(token, "rb"); /* use the current working directory if the library isn't found in the ext_libdir directory */ if (f == NULL) sprintf(tmp_token, "%s%s", ext_libdir, token); else { sprintf(tmp_token, "%s", token); fclose(f); } } else sprintf(tmp_token, "%s", token); if (load_file(tmp_token, bank, slot, base, base_defined) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], token, &x) == SUCCEEDED) { fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } continue; } /* object file loading */ else if (load_file(token, 0, 0, 0, OFF) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], token, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } fclose(fop); return SUCCEEDED; }
static void parse_args_recurse (int *argcp, char ***argvp, bool in_file, int *total_parsed_argc_p) { SetupOp *op; int argc = *argcp; char **argv = *argvp; /* I can't imagine a case where someone wants more than this. * If you do...you should be able to pass multiple files * via a single tmpfs and linking them there, etc. * * We're adding this hardening due to precedent from * http://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html * * I picked 9000 because the Internet told me to and it was hard to * resist. */ static const uint32_t MAX_ARGS = 9000; if (*total_parsed_argc_p > MAX_ARGS) die ("Exceeded maximum number of arguments %u", MAX_ARGS); while (argc > 0) { const char *arg = argv[0]; if (strcmp (arg, "--help") == 0) usage (EXIT_SUCCESS); else if (strcmp (arg, "--version") == 0) { printf ("%s\n", PACKAGE_STRING); exit (0); } else if (strcmp (arg, "--args") == 0) { int the_fd; char *endptr; char *data, *p; char *data_end; size_t data_len; cleanup_free char **data_argv = NULL; char **data_argv_copy; int data_argc; int i; if (in_file) die ("--args not supported in arguments file"); if (argc < 2) die ("--args takes an argument"); the_fd = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) die ("Invalid fd: %s", argv[1]); data = load_file_data (the_fd, &data_len); if (data == NULL) die_with_error ("Can't read --args data"); data_end = data + data_len; data_argc = 0; p = data; while (p != NULL && p < data_end) { data_argc++; (*total_parsed_argc_p)++; if (*total_parsed_argc_p > MAX_ARGS) die ("Exceeded maximum number of arguments %u", MAX_ARGS); p = memchr (p, 0, data_end - p); if (p != NULL) p++; } data_argv = xcalloc (sizeof (char *) * (data_argc + 1)); i = 0; p = data; while (p != NULL && p < data_end) { /* Note: load_file_data always adds a nul terminator, so this is safe * even for the last string. */ data_argv[i++] = p; p = memchr (p, 0, data_end - p); if (p != NULL) p++; } data_argv_copy = data_argv; /* Don't change data_argv, we need to free it */ parse_args_recurse (&data_argc, &data_argv_copy, TRUE, total_parsed_argc_p); argv += 1; argc -= 1; } else if (strcmp (arg, "--unshare-user") == 0) opt_unshare_user = TRUE; else if (strcmp (arg, "--unshare-ipc") == 0) opt_unshare_ipc = TRUE; else if (strcmp (arg, "--unshare-pid") == 0) opt_unshare_pid = TRUE; else if (strcmp (arg, "--unshare-net") == 0) opt_unshare_net = TRUE; else if (strcmp (arg, "--unshare-uts") == 0) opt_unshare_uts = TRUE; else if (strcmp (arg, "--chdir") == 0) { if (argc < 2) die ("--chdir takes one argument"); opt_chdir_path = argv[1]; argv++; argc--; } else if (strcmp (arg, "--bind") == 0) { if (argc < 3) die ("--bind takes two arguments"); op = setup_op_new (SETUP_BIND_MOUNT); op->source = canonicalize_file_name (argv[1]); if (op->source == NULL) die_with_error ("Can't find source path %s", argv[1]); op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--ro-bind") == 0) { if (argc < 3) die ("--ro-bind takes two arguments"); op = setup_op_new (SETUP_RO_BIND_MOUNT); op->source = canonicalize_file_name (argv[1]); if (op->source == NULL) die_with_error ("Can't find source path %s", argv[1]); op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--dev-bind") == 0) { if (argc < 3) die ("--dev-bind takes two arguments"); op = setup_op_new (SETUP_DEV_BIND_MOUNT); op->source = canonicalize_file_name (argv[1]); if (op->source == NULL) die_with_error ("Can't find source path %s", argv[1]); op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--proc") == 0) { if (argc < 2) die ("--proc takes an argument"); op = setup_op_new (SETUP_MOUNT_PROC); op->dest = argv[1]; argv += 1; argc -= 1; } else if (strcmp (arg, "--exec-label") == 0) { if (argc < 2) die ("--exec-label takes an argument"); opt_exec_label = argv[1]; die_unless_label_valid (opt_exec_label); argv += 1; argc -= 1; } else if (strcmp (arg, "--file-label") == 0) { if (argc < 2) die ("--file-label takes an argument"); opt_file_label = argv[1]; die_unless_label_valid (opt_file_label); if (label_create_file (opt_file_label)) die_with_error ("--file-label setup failed"); argv += 1; argc -= 1; } else if (strcmp (arg, "--dev") == 0) { if (argc < 2) die ("--dev takes an argument"); op = setup_op_new (SETUP_MOUNT_DEV); op->dest = argv[1]; opt_needs_devpts = TRUE; argv += 1; argc -= 1; } else if (strcmp (arg, "--tmpfs") == 0) { if (argc < 2) die ("--tmpfs takes an argument"); op = setup_op_new (SETUP_MOUNT_TMPFS); op->dest = argv[1]; argv += 1; argc -= 1; } else if (strcmp (arg, "--mqueue") == 0) { if (argc < 2) die ("--mqueue takes an argument"); op = setup_op_new (SETUP_MOUNT_MQUEUE); op->dest = argv[1]; argv += 1; argc -= 1; } else if (strcmp (arg, "--dir") == 0) { if (argc < 2) die ("--dir takes an argument"); op = setup_op_new (SETUP_MAKE_DIR); op->dest = argv[1]; argv += 1; argc -= 1; } else if (strcmp (arg, "--file") == 0) { int file_fd; char *endptr; if (argc < 3) die ("--file takes two arguments"); file_fd = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || file_fd < 0) die ("Invalid fd: %s", argv[1]); op = setup_op_new (SETUP_MAKE_FILE); op->fd = file_fd; op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--bind-data") == 0) { int file_fd; char *endptr; if (argc < 3) die ("--bind-data takes two arguments"); file_fd = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || file_fd < 0) die ("Invalid fd: %s", argv[1]); op = setup_op_new (SETUP_MAKE_BIND_FILE); op->fd = file_fd; op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--symlink") == 0) { if (argc < 3) die ("--symlink takes two arguments"); op = setup_op_new (SETUP_MAKE_SYMLINK); op->source = argv[1]; op->dest = argv[2]; argv += 2; argc -= 2; } else if (strcmp (arg, "--lock-file") == 0) { if (argc < 2) die ("--lock-file takes an argument"); (void)lock_file_new (argv[1]); argv += 1; argc -= 1; } else if (strcmp (arg, "--sync-fd") == 0) { int the_fd; char *endptr; if (argc < 2) die ("--sync-fd takes an argument"); the_fd = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) die ("Invalid fd: %s", argv[1]); opt_sync_fd = the_fd; argv += 1; argc -= 1; } else if (strcmp (arg, "--seccomp") == 0) { int the_fd; char *endptr; if (argc < 2) die ("--seccomp takes an argument"); the_fd = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0) die ("Invalid fd: %s", argv[1]); opt_seccomp_fd = the_fd; argv += 1; argc -= 1; } else if (strcmp (arg, "--setenv") == 0) { if (argc < 3) die ("--setenv takes two arguments"); xsetenv (argv[1], argv[2], 1); argv += 2; argc -= 2; } else if (strcmp (arg, "--unsetenv") == 0) { if (argc < 2) die ("--unsetenv takes an argument"); xunsetenv (argv[1]); argv += 1; argc -= 1; } else if (strcmp (arg, "--uid") == 0) { int the_uid; char *endptr; if (argc < 2) die ("--uid takes an argument"); the_uid = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || the_uid < 0) die ("Invalid uid: %s", argv[1]); opt_sandbox_uid = the_uid; argv += 1; argc -= 1; } else if (strcmp (arg, "--gid") == 0) { int the_gid; char *endptr; if (argc < 2) die ("--gid takes an argument"); the_gid = strtol (argv[1], &endptr, 10); if (argv[1][0] == 0 || endptr[0] != 0 || the_gid < 0) die ("Invalid gid: %s", argv[1]); opt_sandbox_gid = the_gid; argv += 1; argc -= 1; } else if (*arg == '-') die ("Unknown option %s", arg); else break; argv++; argc--; } *argcp = argc; *argvp = argv; }
int main (int argc, char **argv) { mode_t old_umask; cleanup_free char *base_path = NULL; int clone_flags; char *old_cwd = NULL; pid_t pid; int event_fd = -1; const char *new_cwd; uid_t ns_uid; gid_t ns_gid; /* Get the (optional) capabilities we need, drop root */ acquire_caps (); /* Never gain any more privs during exec */ if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) die_with_error ("prctl(PR_SET_NO_NEW_CAPS) failed"); /* The initial code is run with high permissions (i.e. CAP_SYS_ADMIN), so take lots of care. */ argv0 = argv[0]; if (isatty (1)) host_tty_dev = ttyname (1); argv++; argc--; if (argc == 0) usage (EXIT_FAILURE); parse_args (&argc, &argv); /* We have to do this if we weren't installed setuid, so let's just DWIM */ if (!is_privileged) opt_unshare_user = TRUE; if (argc == 0) usage (EXIT_FAILURE); __debug__(("Creating root mount point\n")); uid = getuid (); if (opt_sandbox_uid == -1) opt_sandbox_uid = uid; gid = getgid (); if (opt_sandbox_gid == -1) opt_sandbox_gid = gid; if (!opt_unshare_user && opt_sandbox_uid != uid) die ("Specifying --uid requires --unshare-user"); if (!opt_unshare_user && opt_sandbox_gid != gid) die ("Specifying --gid requires --unshare-user"); /* We need to read stuff from proc during the pivot_root dance, etc. Lets keep a fd to it open */ proc_fd = open ("/proc", O_RDONLY | O_PATH); if (proc_fd == -1) die_with_error ("Can't open /proc"); /* We need *some* mountpoint where we can mount the root tmpfs. We first try in /run, and if that fails, try in /tmp. */ base_path = xasprintf ("/run/user/%d/.bubblewrap", uid); if (mkdir (base_path, 0755) && errno != EEXIST) { free (base_path); base_path = xasprintf ("/tmp/.bubblewrap-%d", uid); if (mkdir (base_path, 0755) && errno != EEXIST) die_with_error ("Creating root mountpoint failed"); } __debug__(("creating new namespace\n")); if (opt_unshare_pid) { event_fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK); if (event_fd == -1) die_with_error ("eventfd()"); } /* We block sigchild here so that we can use signalfd in the monitor. */ block_sigchild (); clone_flags = SIGCHLD | CLONE_NEWNS; if (opt_unshare_user) clone_flags |= CLONE_NEWUSER; if (opt_unshare_pid) clone_flags |= CLONE_NEWPID; if (opt_unshare_net) clone_flags |= CLONE_NEWNET; if (opt_unshare_ipc) clone_flags |= CLONE_NEWIPC; if (opt_unshare_uts) clone_flags |= CLONE_NEWUTS; pid = raw_clone (clone_flags, NULL); if (pid == -1) { if (opt_unshare_user) { if (errno == EINVAL) die ("Creating new namespace failed, likely because the kernel does not support user namespaces. bwrap must be installed setuid on such systems."); else if (errno == EPERM && !is_privileged) die ("No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces. On e.g. debian this can be enabled with 'sysctl kernel.unprivileged_userns_clone=1'."); } die_with_error ("Creating new namespace failed"); } if (pid != 0) { /* Initial launched process, wait for exec:ed command to exit */ /* We don't need any caps in the launcher, drop them immediately. */ drop_caps (); monitor_child (event_fd); exit (0); /* Should not be reached, but better safe... */ } if (opt_unshare_net && loopback_setup () != 0) die ("Can't create loopback device"); ns_uid = opt_sandbox_uid; ns_gid = opt_sandbox_gid; if (opt_unshare_user) { if (opt_needs_devpts) { /* This is a bit hacky, but we need to first map the real uid/gid to 0, otherwise we can't mount the devpts filesystem because root is not mapped. Later we will create another child user namespace and map back to the real uid */ ns_uid = 0; ns_gid = 0; } write_uid_gid_map (ns_uid, uid, ns_gid, gid, TRUE); } old_umask = umask (0); /* Mark everything as slave, so that we still * receive mounts from the real root, but don't * propagate mounts to the real root. */ if (mount (NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) die_with_error ("Failed to make / slave"); /* Create a tmpfs which we will use as / in the namespace */ if (mount ("", base_path, "tmpfs", MS_NODEV|MS_NOSUID, NULL) != 0) die_with_error ("Failed to mount tmpfs"); old_cwd = get_current_dir_name (); /* Chdir to the new root tmpfs mount. This will be the CWD during the entire setup. Access old or new root via "oldroot" and "newroot". */ if (chdir (base_path) != 0) die_with_error ("chdir base_path"); /* We create a subdir "$base_path/newroot" for the new root, that * way we can pivot_root to base_path, and put the old root at * "$base_path/oldroot". This avoids problems accessing the oldroot * dir if the user requested to bind mount something over / */ if (mkdir ("newroot", 0755)) die_with_error ("Creating newroot failed"); if (mkdir ("oldroot", 0755)) die_with_error ("Creating oldroot failed"); if (pivot_root (base_path, "oldroot")) die_with_error ("pivot_root"); if (chdir ("/") != 0) die_with_error ("chdir / (base path)"); if (is_privileged) { pid_t child; int privsep_sockets[2]; if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, privsep_sockets) != 0) die_with_error ("Can't create privsep socket"); child = fork (); if (child == -1) die_with_error ("Can't fork unprivileged helper"); if (child == 0) { /* Unprivileged setup process */ drop_caps (); close (privsep_sockets[0]); setup_newroot (opt_unshare_pid, privsep_sockets[1]); exit (0); } else { uint32_t buffer[2048]; /* 8k, but is int32 to guarantee nice alignment */ uint32_t op, flags; const char *arg1, *arg2; cleanup_fd int unpriv_socket = -1; unpriv_socket = privsep_sockets[0]; close (privsep_sockets[1]); do { op = read_priv_sec_op (unpriv_socket, buffer, sizeof (buffer), &flags, &arg1, &arg2); privileged_op (-1, op, flags, arg1, arg2); if (write (unpriv_socket, buffer, 1) != 1) die ("Can't write to op_socket"); } while (op != PRIV_SEP_OP_DONE); /* Continue post setup */ } } else setup_newroot (opt_unshare_pid, -1); /* The old root better be rprivate or we will send unmount events to the parent namespace */ if (mount ("oldroot", "oldroot", NULL, MS_REC|MS_PRIVATE, NULL) != 0) die_with_error ("Failed to make old root rprivate"); if (umount2 ("oldroot", MNT_DETACH)) die_with_error ("unmount old root"); if (opt_unshare_user && (ns_uid != opt_sandbox_uid || ns_gid != opt_sandbox_gid)) { /* Now that devpts is mounted and we've no need for mount permissions we can create a new userspace and map our uid 1:1 */ if (unshare (CLONE_NEWUSER)) die_with_error ("unshare user ns"); write_uid_gid_map (opt_sandbox_uid, ns_uid, opt_sandbox_gid, ns_gid, FALSE); } /* Now make /newroot the real root */ if (chdir ("/newroot") != 0) die_with_error ("chdir newroot"); if (chroot ("/newroot") != 0) die_with_error ("chroot /newroot"); if (chdir ("/") != 0) die_with_error ("chdir /"); /* Now we have everything we need CAP_SYS_ADMIN for, so drop it */ drop_caps (); if (opt_seccomp_fd != -1) { cleanup_free char *seccomp_data = NULL; size_t seccomp_len; struct sock_fprog prog; seccomp_data = load_file_data (opt_seccomp_fd, &seccomp_len); if (seccomp_data == NULL) die_with_error ("Can't read seccomp data"); if (seccomp_len % 8 != 0) die ("Invalide seccomp data, must be multiple of 8"); prog.len = seccomp_len / 8; prog.filter = (struct sock_filter *)seccomp_data; close (opt_seccomp_fd); if (prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0) die_with_error ("prctl(PR_SET_SECCOMP)"); } umask (old_umask); new_cwd = "/"; if (opt_chdir_path) { if (chdir (opt_chdir_path)) die_with_error ("Can't chdir to %s", opt_chdir_path); new_cwd = opt_chdir_path; } else if (chdir (old_cwd) == 0) { /* If the old cwd is mapped in the sandbox, go there */ new_cwd = old_cwd; } else { /* If the old cwd is not mapped, go to home */ const char *home = getenv ("HOME"); if (home != NULL && chdir (home) == 0) new_cwd = home; } xsetenv ("PWD", new_cwd, 1); free (old_cwd); __debug__(("forking for child\n")); if (opt_unshare_pid || lock_files != NULL || opt_sync_fd != -1) { /* We have to have a pid 1 in the pid namespace, because * otherwise we'll get a bunch of zombies as nothing reaps * them. Alternatively if we're using sync_fd or lock_files we * need some process to own these. */ pid = fork (); if (pid == -1) die_with_error("Can't fork for pid 1"); if (pid != 0) { /* Close fds in pid 1, except stdio and optionally event_fd (for syncing pid 2 lifetime with monitor_child) and opt_sync_fd (for syncing sandbox lifetime with outside process). Any other fds will been passed on to the child though. */ { int dont_close[3]; int j = 0; if (event_fd != -1) dont_close[j++] = event_fd; if (opt_sync_fd != -1) dont_close[j++] = opt_sync_fd; dont_close[j++] = -1; fdwalk (proc_fd, close_extra_fds, dont_close); } return do_init (event_fd, pid); } } __debug__(("launch executable %s\n", argv[0])); if (proc_fd != -1) close (proc_fd); if (opt_sync_fd != -1) close (opt_sync_fd); /* We want sigchild in the child */ unblock_sigchild (); if (label_exec (opt_exec_label) == -1) die_with_error ("label_exec %s", argv[0]); if (execvp (argv[0], argv) == -1) die_with_error ("execvp %s", argv[0]); return 0; }
int load_files(char *argv[], int argc, int have_flags) { struct label *l; int st = STATE_NONE, i, x, line, bank, slot, base, bank_defined, slot_defined, base_defined, n; char tmp[1024], ou[1024]; FILE *fop; if (no_std_libraries == OFF) { char* stdlibs[] = { #define LIBDIR PREFIX "/lib" LIBDIR "/crt0_snes.obj", LIBDIR "/libm.obj", LIBDIR "/libtcc.obj", LIBDIR "/libc.obj", NULL }; char** sl; for (sl = stdlibs; *sl; sl++) { if (load_file(*sl, STATE_OBJECT, 0, 0, 0, OFF) == FAILED) return FAILED; } } if (object_file_parameters == ON) { for (i = (have_flags ? 2 : 1); i < argc - 1 ; i++) { if (load_file(argv[i], STATE_OBJECT, 0, 0, 0, OFF) == FAILED) return FAILED; } } else { fop = fopen(argv[argc - 2], "rb"); if (fop == NULL) { fprintf(stderr, "LOAD_FILES: Could not open file \"%s\".\n", argv[argc - 2]); return FAILED; } line = 0; while (fgets(tmp, 255, fop) != NULL) { line++; x = 0; if (tmp[0] == ';' || tmp[0] == '*' || tmp[0] == '#' || tmp[0] == 0x0D || tmp[0] == 0x0A) continue; /* remove garbage from the end */ for (i = 0; !(tmp[i] == 0x0D || tmp[i] == 0x0A); i++); tmp[i] = 0; /* empty line check */ if (get_next_token(tmp, ou, &x) == FAILED) continue; /* first checks */ if (ou[0] == '[') { if (strcmp("[objects]", ou) == 0) { st = STATE_OBJECT; continue; } else if (strcmp("[libraries]", ou) == 0) { st = STATE_LIBRARY; continue; } else if (strcmp("[header]", ou) == 0) { st = STATE_HEADER; continue; } else if (strcmp("[footer]", ou) == 0) { st = STATE_FOOTER; continue; } else if (strcmp("[definitions]", ou) == 0) { st = STATE_DEFINITION; continue; } else { fprintf(stderr, "%s:%d LOAD_FILES: Unknown group \"%s\".\n", argv[argc - 2], line, ou); fclose(fop); return FAILED; } } if (st == STATE_NONE) { fprintf(stderr, "%s:%d: LOAD_FILES: Before file \"%s\" can be loaded you must define a group for it.\n", argv[argc - 2], line, ou); fclose(fop); return FAILED; } bank_defined = OFF; slot_defined = OFF; base_defined = OFF; bank = 0; slot = 0; base = 0; /* definition loading? */ if (st == STATE_DEFINITION) { l = malloc(sizeof(struct label)); if (l == NULL) { fprintf(stderr, "LOAD_FILES: Out of memory.\n"); return FAILED; } strcpy(l->name, ou); l->status = LABEL_STATUS_DEFINE; l->bank = 0; l->slot = 0; l->base = 0; if (get_next_number(&tmp[x], &n, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in DEFINITION value.\n", argv[argc - 2], line); fclose(fop); return FAILED; } l->address = n; add_label(l); continue; } /* header loading? */ else if (st == STATE_HEADER) { if (file_header != NULL) { fprintf(stderr, "%s:%d: LOAD_FILES: There can be only one header file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (load_file_data(ou, &file_header, &file_header_size) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], ou, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } /* footer loading? */ else if (st == STATE_FOOTER) { if (file_footer != NULL) { fprintf(stderr, "%s:%d: LOAD_FILES: There can be only one footer file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (load_file_data(ou, &file_footer, &file_footer_size) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], ou, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } /* library loading? */ else if (st == STATE_LIBRARY) { i = SUCCEEDED; while (i == SUCCEEDED) { if (strcmp(ou, "bank") == 0 || strcmp(ou, "BANK") == 0) { if (bank_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: BANK defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } bank_defined = ON; if (get_next_number(&tmp[x], &bank, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in BANK number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else if (strcmp(ou, "slot") == 0 || strcmp(ou, "SLOT") == 0) { if (slot_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: SLOT defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } slot_defined = ON; if (get_next_number(&tmp[x], &slot, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in SLOT number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else if (strcmp(ou, "base") == 0 || strcmp(ou, "BASE") == 0) { if (base_defined == ON) { fprintf(stderr, "%s:%d: LOAD_FILES: BASE defined for the second time for a library file.\n", argv[argc - 2], line); fclose(fop); return FAILED; } base_defined = ON; if (get_next_number(&tmp[x], &base, &x) == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: Error in BASE number.\n", argv[argc - 2], line); fclose(fop); return FAILED; } } else break; i = get_next_token(&tmp[x], ou, &x); } if (i == FAILED) { fprintf(stderr, "%s:%d: LOAD_FILES: No library to load.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (slot_defined == OFF) { fprintf(stderr, "%s:%d: LOAD_FILES: Library file requires a SLOT.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (bank_defined == OFF) { fprintf(stderr, "%s:%d: LOAD_FILES: Library file requires a BANK.\n", argv[argc - 2], line); fclose(fop); return FAILED; } if (load_file(ou, STATE_LIBRARY, bank, slot, base, base_defined) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], ou, &x) == SUCCEEDED) { fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } continue; } /* object file loading */ else if (load_file(ou, STATE_OBJECT, 0, 0, 0, OFF) == FAILED) { fclose(fop); return FAILED; } if (get_next_token(&tmp[x], ou, &x) == FAILED) continue; fprintf(stderr, "%s:%d: LOAD_FILES: Syntax error.\n", argv[argc - 2], line); fclose(fop); return FAILED; } fclose(fop); } return SUCCEEDED; }