void handle_parent(FILE *input) { char buffer[DEFAULT_BUFFER]; int i; for(i = 0; (fgets(buffer, DEFAULT_BUFFER, input) != NULL); i++) { write_safe(mapper_pipes[i % NUMBER_MAPPERS][WRITE_END], buffer, DEFAULT_BUFFER); } // close mapper pipes then wait for mappers to exit for(i = 0; i < NUMBER_MAPPERS; i++) { close_safe(mapper_pipes[i][WRITE_END]); } int status; for(i = 0; i < NUMBER_MAPPERS; i++) { wait_safe(&status); } // close reducer pipes then wait for reducers to exit for(i = 0; i < NUMBER_REDUCERS; i++) { close_safe(reducer_pipes[i][WRITE_END]); } for(i = 0; i < NUMBER_REDUCERS; i++) { wait_safe(&status); } }
void handle_mapper() { char buffer[DEFAULT_BUFFER]; int i; while(read_safe(mapper_pipes[process_number][READ_END], buffer, DEFAULT_BUFFER) > 0) { for(i = 0; i < strlen(buffer) && buffer[i] != '\n'; i++) { char letter = buffer[i]; if((letter >= (int)'a') && (letter <= (int) 'z')) { int index = (int)letter - (int)'a'; write_safe(reducer_pipes[index][WRITE_END], &letter, 1); } } } for(i = 0; i < NUMBER_MAPPERS; i++) { close_safe(mapper_pipes[i][READ_END]); } for(i = 0; i < NUMBER_REDUCERS; i++) { close_safe(reducer_pipes[i][WRITE_END]); } exit(0); }
void context_fini(context_t *ctx) { close_safe(&ctx->fd); close_safe(&ctx->dfd); close_safe(&ctx->rootfd); context_fini_fdset_glob(ctx); context_fini_fdset_netns(ctx); }
OrFalse <array <string> > f$file (const string &name) { struct stat stat_buf; dl::enter_critical_section();//OK int file_fd = open_safe (name.c_str(), O_RDONLY); if (file_fd < 0) { dl::leave_critical_section(); return false; } if (fstat (file_fd, &stat_buf) < 0) { close_safe (file_fd); dl::leave_critical_section(); return false; } if (!S_ISREG (stat_buf.st_mode)) { php_warning ("Regular file expected as first argument in function file, \"%s\" is given", name.c_str()); close_safe (file_fd); dl::leave_critical_section(); return false; } size_t size = stat_buf.st_size; if (size > string::max_size) { php_warning ("File \"%s\" is too large", name.c_str()); close_safe (file_fd); dl::leave_critical_section(); return false; } dl::leave_critical_section(); string res ((dl::size_type)size, false); dl::enter_critical_section();//OK char *s = &res[0]; if (read_safe (file_fd, s, size) < (ssize_t)size) { close_safe (file_fd); dl::leave_critical_section(); return false; } close_safe (file_fd); dl::leave_critical_section(); array <string> result; int prev = -1; for (int i = 0; i < (int)size; i++) { if (s[i] == '\n' || i + 1 == (int)size) { result.push_back (string (s + prev + 1, i - prev)); prev = i; } } return result; }
int reopen_fd_as_safe(char *file, int line, int new_fd, int old_fd, bool allow_reuse_fd) { int tmp; if (old_fd != new_fd) { if (!allow_reuse_fd) { if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) { if (new_fd < 3) { /* * Standard descriptors. */ pr_warn("fd %d already in use (called at %s:%d)\n", new_fd, file, line); } else { pr_err("fd %d already in use (called at %s:%d)\n", new_fd, file, line); return -1; } } } tmp = dup2(old_fd, new_fd); if (tmp < 0) { pr_perror("Dup %d -> %d failed (called at %s:%d)", old_fd, new_fd, file, line); return tmp; } /* Just to have error message if failed */ close_safe(&old_fd); } return 0; }
static int prepare_ipc_var(int pid) { int fd, ret; IpcVarEntry *var; pr_info("Restoring IPC variables\n"); fd = open_image(CR_FD_IPC_VAR, O_RSTR, pid); if (fd < 0) return -1; ret = pb_read_one(fd, &var, PB_IPC_VAR); close_safe(&fd); if (ret <= 0) { pr_err("Failed to read IPC namespace variables\n"); return -EFAULT; } ipc_sysctl_req(var, CTL_PRINT); ret = ipc_sysctl_req(var, CTL_WRITE); ipc_var_entry__free_unpacked(var, NULL); if (ret < 0) { pr_err("Failed to prepare IPC namespace variables\n"); return -EFAULT; } return 0; }
void handle_reducer() { char my_letter = (char)((int)'a' + process_number); int count = 0; char c; while(read_safe(reducer_pipes[process_number][READ_END], &c, 1) > 0) { if(c == my_letter) { count++; } } printf("count %c:\t%d\n", my_letter, count); fflush_safe(stdout); int i; for(i = 0; i < NUMBER_REDUCERS; i++) { close_safe(reducer_pipes[i][READ_END]); } exit(0); }
void log_fini(void) { if (current_logfd > 2) close_safe(¤t_logfd); current_logfd = DEFAULT_LOGFD; }
OrFalse <string> f$file_get_contents (const string &name) { if ((int)name.size() == 11 && !memcmp (name.c_str(), "php://input", 11)) { return raw_post_data; } struct stat stat_buf; dl::enter_critical_section();//OK int file_fd = open_safe (name.c_str(), O_RDONLY); if (file_fd < 0) { dl::leave_critical_section(); return false; } if (fstat (file_fd, &stat_buf) < 0) { close_safe (file_fd); dl::leave_critical_section(); return false; } if (!S_ISREG (stat_buf.st_mode)) { php_warning ("Regular file expected as first argument in function file_get_contents, \"%s\" is given", name.c_str()); close_safe (file_fd); dl::leave_critical_section(); return false; } size_t size = stat_buf.st_size; if (size > string::max_size) { php_warning ("File \"%s\" is too large", name.c_str()); close_safe (file_fd); dl::leave_critical_section(); return false; } dl::leave_critical_section(); string res ((dl::size_type)size, false); dl::enter_critical_section();//OK if (read_safe (file_fd, &res[0], size) < (ssize_t)size) { close_safe (file_fd); dl::leave_critical_section(); return false; } close_safe (file_fd); dl::leave_critical_section(); return res; }
static int check_tty(void) { int master = -1, slave = -1; const int lock = 1; struct termios t; char *slavename; int ret = -1; if (ARRAY_SIZE(t.c_cc) < TERMIOS_NCC) { pr_msg("struct termios has %d @c_cc while " "at least %d expected.\n", (int)ARRAY_SIZE(t.c_cc), TERMIOS_NCC); goto out; } master = open("/dev/ptmx", O_RDWR); if (master < 0) { pr_perror("Can't open /dev/ptmx"); goto out; } if (ioctl(master, TIOCSPTLCK, &lock)) { pr_perror("Can't lock pty master"); goto out; } slavename = ptsname(master); slave = open(slavename, O_RDWR); if (slave < 0) { if (errno != EIO) { pr_perror("Unexpected error on locked pty"); goto out; } } else { pr_err("Managed to open locked pty.\n"); goto out; } ret = 0; out: close_safe(&master); close_safe(&slave); return ret; }
static void __close_cr_fdset(struct cr_fdset *cr_fdset) { unsigned int i; if (!cr_fdset) return; for (i = 0; i < cr_fdset->fd_nr; i++) { if (cr_fdset->_fds[i] == -1) continue; close_safe(&cr_fdset->_fds[i]); cr_fdset->_fds[i] = -1; } }
static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, struct parasite_init_args *args) { int ssock = -1; socklen_t sk_len; struct sockaddr_un addr; pr_info("Putting tsock into pid %d\n", pid); args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); ssock = ctl->ictx.sock; sk_len = sizeof(addr); if (ssock == -1) { pr_err("No socket in ictx\n"); goto err; } if (getsockname(ssock, (struct sockaddr *) &addr, &sk_len) < 0) { pr_perror("Unable to get name for a socket"); return -1; } if (sk_len == sizeof(addr.sun_family)) { if (bind(ssock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { pr_perror("Can't bind socket"); goto err; } if (listen(ssock, 1)) { pr_perror("Can't listen on transport socket"); goto err; } } /* Check a case when parasite can't initialize a command socket */ if (ctl->ictx.flags & INFECT_FAIL_CONNECT) args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid() + 1); /* * Set to -1 to prevent any accidental misuse. The * only valid user of it is accept_tsock(). */ ctl->tsock = -ssock; return 0; err: close_safe(&ssock); return -1; }
static int prepare_ipc_msg(int pid) { int fd, ret; pr_info("Restoring IPC message queues\n"); fd = open_image(CR_FD_IPCNS_MSG, O_RSTR, pid); if (fd < 0) return -1; while (1) { IpcMsgEntry *msq; ret = pb_read_one_eof(fd, &msq, PB_IPCNS_MSG_ENT); if (ret < 0) { pr_err("Failed to read IPC messages queue\n"); ret = -EIO; goto err; } if (ret == 0) break; pr_info_ipc_msg_entry(msq); ret = prepare_ipc_msg_queue(fd, msq); ipc_msg_entry__free_unpacked(msq, NULL); if (ret < 0) { pr_err("Failed to prepare messages queue\n"); goto err; } } return close_safe(&fd); err: close_safe(&fd); return ret; }
static int prepare_ipc_shm(int pid) { int fd, ret; pr_info("Restoring IPC shared memory\n"); fd = open_image(CR_FD_IPCNS_SHM, O_RSTR, pid); if (fd < 0) return -1; while (1) { IpcShmEntry *shm; ret = pb_read_one_eof(fd, &shm, PB_IPC_SHM); if (ret < 0) { pr_err("Failed to read IPC shared memory segment\n"); ret = -EIO; goto err; } if (ret == 0) break; pr_info_ipc_shm(shm); ret = prepare_ipc_shm_seg(fd, shm); ipc_shm_entry__free_unpacked(shm, NULL); if (ret < 0) { pr_err("Failed to prepare shm segment\n"); goto err; } } return close_safe(&fd); err: close_safe(&fd); return ret; }
static int prepare_ipc_sem(int pid) { int fd, ret; pr_info("Restoring IPC semaphores sets\n"); fd = open_image(CR_FD_IPCNS_SEM, O_RSTR, pid); if (fd < 0) return -1; while (1) { IpcSemEntry *sem; ret = pb_read_one_eof(fd, &sem, PB_IPC_SEM); if (ret < 0) { ret = -EIO; goto err; } if (ret == 0) break; pr_info_ipc_sem_entry(sem); ret = prepare_ipc_sem_desc(fd, sem); ipc_sem_entry__free_unpacked(sem, NULL); if (ret < 0) { pr_err("Failed to prepare semaphores set\n"); goto err; } } return close_safe(&fd); err: close_safe(&fd); return ret; }
void files_free_static (void) { dl::enter_critical_section();//OK if (dl::query_num == opened_files_last_query_num) { const array <FILE *> *const_opened_files = opened_files; for (array <FILE *>::const_iterator p = const_opened_files->begin(); p != const_opened_files->end(); ++p) { if (neq2 (p.get_key(), STDOUT) && neq2 (p.get_key(), STDERR)) { fclose (p.get_value()); } } opened_files_last_query_num--; } if (opened_fd != -1) { close_safe (opened_fd); } CLEAR_VAR(string, raw_post_data); dl::leave_critical_section(); }
static int __sysctl_op(int dir, struct sysctl_req *req, int op) { int fd = -1; int ret = -1; int nr = 1; if (dir >= 0) { int flags; if (op == CTL_READ) flags = O_RDONLY; else flags = O_WRONLY; fd = openat(dir, req->name, flags); if (fd < 0) { pr_perror("Can't open sysctl %s", req->name); return -1; } } switch (CTL_TYPE(req->type)) { case __CTL_U32A: nr = CTL_LEN(req->type); case CTL_U32: __SYSCTL_OP(ret, fd, req, u32, nr, op); break; case __CTL_U64A: nr = CTL_LEN(req->type); case CTL_U64: __SYSCTL_OP(ret, fd, req, u64, nr, op); break; case __CTL_STR: nr = CTL_LEN(req->type); __SYSCTL_OP(ret, fd, req, char, nr, op); break; } close_safe(&fd); return ret; }
int compel_stop_daemon(struct parasite_ctl *ctl) { if (ctl->daemonized) { /* * Looks like a previous attempt failed, we should do * nothing in this case. parasite will try to cure itself. */ if (ctl->tsock < 0) return -1; if (parasite_fini_seized(ctl)) { close_safe(&ctl->tsock); return -1; } } ctl->daemonized = false; return 0; }
int sysctl_op(struct sysctl_req *req, size_t nr_req, int op) { int ret = 0; int dir = -1; dir = open("/proc/sys", O_RDONLY); if (dir < 0) { pr_perror("Can't open sysctl dir"); return -1; } while (nr_req--) { ret = __sysctl_op(dir, req, op); if (ret < 0) break; req++; } close_safe(&dir); return ret; }
void close_pipe_ends() { int i; switch (*identifier) { /* Parent process maintains mapper write and reducer write */ case PARENT_IDENTIFIER: // close mapper read ends and reducer read ends for(i = 0; i < NUMBER_MAPPERS; i++) close_safe(mapper_pipes[i][READ_END]); for(i = 0; i < NUMBER_REDUCERS; i++) { close_safe(reducer_pipes[i][READ_END]); //close(reducer_pipes[i][WRITE_END]); } break; /* Mappers maintain mapper read and reducer write */ case MAPPER_IDENTIFIER: // close mapper write ends and reducer read ends for(i = 0; i < NUMBER_MAPPERS; i++) close_safe(mapper_pipes[i][WRITE_END]); for(i = 0; i < NUMBER_REDUCERS; i++) close_safe(reducer_pipes[i][READ_END]); break; /* Reducers maintain reducer read ends */ case REDUCER_IDENTIFIER: // close mapper read/write ends and reducer write ends for(i = 0; i < NUMBER_MAPPERS; i++) { close_safe(mapper_pipes[i][READ_END]); close_safe(mapper_pipes[i][WRITE_END]); } for(i = 0; i < NUMBER_REDUCERS; i++) close_safe(reducer_pipes[i][WRITE_END]); break; default: exit(1); break; } }
int sysctl_op(struct sysctl_req *req, int op) { int ret = 0; int dir = -1; if (op != CTL_PRINT && op != CTL_SHOW) { dir = open("/proc/sys", O_RDONLY); if (dir < 0) { pr_perror("Can't open sysctl dir"); return -1; } } while (req->name) { ret = __sysctl_op(dir, req, op); if (ret < 0) break; req++; } close_safe(&dir); return ret; }
static int start_daemon (pam_handle_t *ph, struct passwd *pwd, const char *password) { struct sigaction defsact, oldsact, ignpipe, oldpipe; int inp[2] = { -1, -1 }; int outp[2] = { -1, -1 }; int errp[2] = { -1, -1 }; int ret = PAM_SERVICE_ERR; pid_t pid; char *output = NULL; char *outerr = NULL; int failed, status; assert (pwd); /* * Make sure that SIGCHLD occurs. Otherwise our waitpid below * doesn't work properly. We need to wait on the process to * get the daemon exit status. */ memset (&defsact, 0, sizeof (defsact)); memset (&oldsact, 0, sizeof (oldsact)); defsact.sa_handler = SIG_DFL; sigaction (SIGCHLD, &defsact, &oldsact); /* * Make sure we don't exit with a SIGPIPE while doing this, that * would be very annoying to a user trying to log in. */ memset (&ignpipe, 0, sizeof (ignpipe)); memset (&oldpipe, 0, sizeof (oldpipe)); ignpipe.sa_handler = SIG_IGN; sigaction (SIGPIPE, &ignpipe, &oldpipe); /* Create the necessary pipes */ if (pipe (inp) < 0 || pipe (outp) < 0 || pipe (errp) < 0) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't create pipes: %s", strerror (errno)); goto done; } /* Start up daemon child process */ switch (pid = fork ()) { case -1: syslog (GKR_LOG_ERR, "gkr-pam: couldn't fork: %s", strerror (errno)); goto done; /* This is the child */ case 0: setup_child (inp, outp, errp, ph, pwd); /* Should never be reached */ break; /* This is the parent */ default: break; }; /* Close our unneeded ends of the pipes */ close (inp[READ_END]); close (outp[WRITE_END]); close (errp[WRITE_END]); inp[READ_END] = outp[WRITE_END] = errp[WRITE_END] = -1; /* * We always pass in a --login argument, even when we have a NULL password * since this controls the startup behavior. When using --login daemon waits * for a password. Closing input signifies password is done. */ if (password) write_string (inp[WRITE_END], password); close (inp[WRITE_END]); /* * Note that we're not using select() or any such. We know how the * daemon sends its data. */ /* Read any stdout and stderr data */ output = read_string (outp[READ_END]); outerr = read_string (errp[READ_END]); if (!output || !outerr) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't read data from mate-keyring-daemon: %s", strerror (errno)); goto done; } /* Wait for the initial process to exit */ if (waitpid (pid, &status, 0) < 0) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't wait on mate-keyring-daemon process: %s", strerror (errno)); goto done; } failed = !WIFEXITED (status) || WEXITSTATUS (status) != 0; if (outerr && outerr[0]) foreach_line (outerr, log_problem, &failed); /* Failure from process */ if (failed) { syslog (GKR_LOG_ERR, "gkr-pam: mate-keyring-daemon didn't start properly properly"); goto done; } ret = foreach_line (output, setup_environment, ph); done: /* Restore old handler */ sigaction (SIGCHLD, &oldsact, NULL); sigaction (SIGPIPE, &oldpipe, NULL); close_safe (inp[0]); close_safe (inp[1]); close_safe (outp[0]); close_safe (outp[1]); close_safe (errp[0]); close_safe (errp[1]); free_safe (output); free_safe (outerr); return ret; }
static int restore_shmem_content(void *addr, struct shmem_info *si) { int fd, fd_pg, ret = 0; fd = open_image(CR_FD_SHMEM_PAGEMAP, O_RSTR, si->shmid); if (fd < 0) { fd_pg = open_image(CR_FD_SHM_PAGES_OLD, O_RSTR, si->shmid); if (fd_pg < 0) goto err_unmap; } else { fd_pg = open_pages_image(O_RSTR, fd); if (fd_pg < 0) goto out_close; } while (1) { unsigned long vaddr; unsigned nr_pages; if (fd >= 0) { PagemapEntry *pe; ret = pb_read_one_eof(fd, &pe, PB_PAGEMAP); if (ret <= 0) break; vaddr = (unsigned long)decode_pointer(pe->vaddr); nr_pages = pe->nr_pages; pagemap_entry__free_unpacked(pe, NULL); } else { __u64 img_vaddr; ret = read_img_eof(fd_pg, &img_vaddr); if (ret <= 0) break; vaddr = (unsigned long)decode_pointer(img_vaddr); nr_pages = 1; } if (vaddr + nr_pages * PAGE_SIZE > si->size) break; ret = read(fd_pg, addr + vaddr, nr_pages * PAGE_SIZE); if (ret != nr_pages * PAGE_SIZE) { ret = -1; break; } } close_safe(&fd_pg); close_safe(&fd); return ret; out_close: close_safe(&fd); err_unmap: munmap(addr, si->size); return -1; }
static int parasite_fini_seized(struct parasite_ctl *ctl) { pid_t pid = ctl->rpid; user_regs_struct_t regs; int status, ret = 0; enum trace_flags flag; /* stop getting chld from parasite -- we're about to step-by-step it */ if (restore_child_handler(ctl)) return -1; /* Start to trace syscalls for each thread */ if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) { pr_perror("Unable to interrupt the process"); return -1; } pr_debug("Waiting for %d to trap\n", pid); if (wait4(pid, &status, __WALL, NULL) != pid) { pr_perror("Waited pid mismatch (pid: %d)", pid); return -1; } pr_debug("Daemon %d exited trapping\n", pid); if (!WIFSTOPPED(status)) { pr_err("Task is still running (pid: %d)\n", pid); return -1; } ret = ptrace_get_regs(pid, ®s); if (ret) { pr_perror("Unable to get registers"); return -1; } if (!task_in_parasite(ctl, ®s)) { pr_err("The task is not in parasite code\n"); return -1; } ret = compel_rpc_call(PARASITE_CMD_FINI, ctl); close_safe(&ctl->tsock); if (ret) return -1; /* Go to sigreturn as closer as we can */ ret = compel_stop_pie(pid, ctl->sigreturn_addr, &flag, ctl->ictx.flags & INFECT_NO_BREAKPOINTS); if (ret < 0) return ret; if (compel_stop_on_syscall(1, __NR(rt_sigreturn, 0), __NR(rt_sigreturn, 1), flag)) return -1; if (ptrace_flush_breakpoints(pid)) return -1; /* * All signals are unblocked now. The kernel notifies about leaving * syscall before starting to deliver signals. All parasite code are * executed with blocked signals, so we can sefly unmap a parasite blob. */ return 0; }
static int parasite_init(struct parasite_ctl *ctl, pid_t pid, int nr_threads) { struct parasite_init_args *args; static int sock = -1; args = parasite_args(ctl, struct parasite_init_args); pr_info("Putting tsock into pid %d\n", pid); args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); args->p_addr_len = gen_parasite_saddr(&args->p_addr, pid); args->nr_threads = nr_threads; if (sock == -1) { int rst = -1; if (current_ns_mask & CLONE_NEWNET) { pr_info("Switching to %d's net for tsock creation\n", pid); if (switch_ns(pid, &net_ns_desc, &rst)) return -1; } sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (sock < 0) pr_perror("Can't create socket"); if (rst > 0 && restore_ns(rst, &net_ns_desc) < 0) return -1; if (sock < 0) return -1; if (bind(sock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { pr_perror("Can't bind socket"); goto err; } } else { struct sockaddr addr = { .sa_family = AF_UNSPEC, }; /* * When the peer of a dgram socket dies the original socket * remains in connected state, thus denying any connections * from "other" sources. Unconnect the socket by hands thus * allowing for parasite to connect back. */ if (connect(sock, &addr, sizeof(addr)) < 0) { pr_perror("Can't unconnect"); goto err; } } if (parasite_execute(PARASITE_CMD_INIT, ctl) < 0) { pr_err("Can't init parasite\n"); goto err; } if (connect(sock, (struct sockaddr *)&args->p_addr, args->p_addr_len) < 0) { pr_perror("Can't connect a transport socket"); goto err; } ctl->tsock = sock; return 0; err: close_safe(&sock); return -1; }
int get_shmem_fd(int pid, VmaEntry *vi) { struct shmem_info *si; void *addr = MAP_FAILED; int f = -1; int flags; si = find_shmem_by_id(vi->shmid); pr_info("Search for 0x%016"PRIx64" shmem 0x%"PRIx64" %p/%d\n", vi->start, vi->shmid, si, si ? si->pid : -1); if (!si) { pr_err("Can't find my shmem 0x%016"PRIx64"\n", vi->start); return -1; } if (si->pid != pid) return shmem_wait_and_open(pid, si); if (si->fd != -1) return dup(si->fd); flags = MAP_SHARED; if (kdat.has_memfd) { f = sys_memfd_create("", 0); if (f < 0) { pr_perror("Unable to create memfd"); goto err; } if (ftruncate(f, si->size)) { pr_perror("Unable to truncate memfd"); goto err; } flags |= MAP_FILE; } else flags |= MAP_ANONYMOUS; /* * The following hack solves problems: * vi->pgoff may be not zero in a target process. * This mapping may be mapped more then once. * The restorer doesn't have snprintf. * Here is a good place to restore content */ addr = mmap(NULL, si->size, PROT_WRITE | PROT_READ, flags, f, 0); if (addr == MAP_FAILED) { pr_err("Can't mmap shmid=0x%"PRIx64" size=%ld\n", vi->shmid, si->size); goto err; } if (restore_shmem_content(addr, si) < 0) { pr_err("Can't restore shmem content\n"); goto err; } if (f == -1) { f = open_proc_rw(getpid(), "map_files/%lx-%lx", (unsigned long) addr, (unsigned long) addr + si->size); if (f < 0) goto err; } munmap(addr, si->size); si->fd = f; /* Send signal to slaves, that they can open fd for this shmem */ futex_inc_and_wake(&si->lock); /* * All other regions in this process will duplicate * the file descriptor, so we don't wait them. */ futex_wait_until(&si->lock, si->count - si->self_count + 1); return f; err: if (addr != MAP_FAILED) munmap(addr, si->size); close_safe(&f); return -1; }
void log_closedir(void) { close_safe(&logdir); }
int cr_service(bool daemon_mode) { int server_fd = -1; int child_pid; struct sockaddr_un client_addr; socklen_t client_addr_len; { struct sockaddr_un server_addr; socklen_t server_addr_len; server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); if (server_fd == -1) { pr_perror("Can't initialize service socket"); goto err; } memset(&server_addr, 0, sizeof(server_addr)); memset(&client_addr, 0, sizeof(client_addr)); server_addr.sun_family = AF_LOCAL; if (opts.addr == NULL) { pr_warn("Binding to local dir address!\n"); opts.addr = CR_DEFAULT_SERVICE_ADDRESS; } strcpy(server_addr.sun_path, opts.addr); server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family); client_addr_len = sizeof(client_addr); unlink(server_addr.sun_path); if (bind(server_fd, (struct sockaddr *) &server_addr, server_addr_len) == -1) { pr_perror("Can't bind"); goto err; } pr_info("The service socket is bound to %s\n", server_addr.sun_path); /* change service socket permissions, so anyone can connect to it */ if (chmod(server_addr.sun_path, 0666)) { pr_perror("Can't change permissions of the service socket"); goto err; } if (listen(server_fd, 16) == -1) { pr_perror("Can't listen for socket connections"); goto err; } } if (daemon_mode) { if (daemon(1, 0) == -1) { pr_perror("Can't run service server in the background"); goto err; } } if (opts.pidfile) { if (write_pidfile(getpid()) == -1) { pr_perror("Can't write pidfile"); goto err; } } if (setup_sigchld_handler()) goto err; while (1) { int sk; pr_info("Waiting for connection...\n"); sk = accept(server_fd, &client_addr, &client_addr_len); if (sk == -1) { pr_perror("Can't accept connection"); goto err; } pr_info("Connected.\n"); child_pid = fork(); if (child_pid == 0) { int ret; if (restore_sigchld_handler()) exit(1); close(server_fd); init_opts(); ret = cr_service_work(sk); close(sk); exit(ret != 0); } if (child_pid < 0) pr_perror("Can't fork a child"); close(sk); } err: close_safe(&server_fd); return 1; }
static int __userns_sysctl_op(void *arg, int proc_fd, pid_t pid) { int fd, ret = -1, dir, i, status, *fds = NULL; struct sysctl_userns_req *userns_req = arg; int op = userns_req->op; struct sysctl_req *req, **reqs = NULL; sigset_t blockmask, oldmask; pid_t worker; // fix up the pointer req = userns_req->reqs = (struct sysctl_req *) &userns_req[1]; /* For files in the IPC/UTS namespaces, restoring is more complicated * than for net. Unprivileged users cannot even open these files, so * they must be opened by usernsd. However, the value in the kernel is * changed for the IPC/UTS namespace that write()s to the open sysctl * file (not who opened it). So, we must set the value from inside the * usernsd caller's namespace. We: * * 1. unsd opens the sysctl files * 2. forks a task * 3. setns()es to the UTS/IPC namespace of the caller * 4. write()s to the files and exits */ dir = open("/proc/sys", O_RDONLY, O_DIRECTORY); if (dir < 0) { pr_perror("Can't open sysctl dir"); return -1; } fds = xmalloc(sizeof(int) * userns_req->nr_req); if (!fds) goto out; reqs = xmalloc(sizeof(struct sysctl_req) * userns_req->nr_req); if (!reqs) goto out; memset(fds, -1, sizeof(int) * userns_req->nr_req); for (i = 0; i < userns_req->nr_req; i++) { int arg_len = sysctl_userns_arg_size(req->type); int name_len = strlen((char *) &req[1]) + 1; int total_len = sizeof(*req) + arg_len + name_len; int flags; /* fix up the pointers */ req->name = (char *) &req[1]; req->arg = req->name + name_len; if (((char *) req) + total_len >= ((char *) userns_req) + MAX_UNSFD_MSG_SIZE) { pr_err("bad sysctl req %s, too big: %d\n", req->name, total_len); goto out; } if (op == CTL_READ) flags = O_RDONLY; else flags = O_WRONLY; fd = openat(dir, req->name, flags); if (fd < 0) { if (errno == ENOENT && (req->flags & CTL_FLAGS_OPTIONAL)) continue; pr_perror("Can't open sysctl %s", req->name); goto out; } /* save a pointer to the req, so we don't need to recompute its * location */ reqs[i] = req; fds[i] = fd; req = (struct sysctl_req *) (((char *) req) + total_len); } /* * Don't let the sigchld_handler() mess with us * calling waitpid() on the exited worker. The * same is done in cr_system(). */ sigemptyset(&blockmask); sigaddset(&blockmask, SIGCHLD); sigprocmask(SIG_BLOCK, &blockmask, &oldmask); worker = fork(); if (worker < 0) goto out; if (!worker) { int nsfd; const char *nsname = ns_to_string(userns_req->ns); BUG_ON(!nsname); nsfd = openat(proc_fd, nsname, O_RDONLY); if (nsfd < 0) { pr_perror("failed to open pid %d's ns %s", pid, nsname); exit(1); } if (setns(nsfd, 0) < 0) { pr_perror("failed to setns to %d's ns %s", pid, nsname); exit(1); } close(nsfd); for (i = 0; i < userns_req->nr_req; i++) { if (do_sysctl_op(fds[i], reqs[i], op) < 0) exit(1); } exit(0); } if (waitpid(worker, &status, 0) != worker) { pr_perror("worker didn't die?"); kill(worker, SIGKILL); goto out; } sigprocmask(SIG_SETMASK, &oldmask, NULL); if (!WIFEXITED(status) || WEXITSTATUS(status)) { pr_err("worker failed: %d\n", status); goto out; } ret = 0; out: if (fds) { for (i = 0; i < userns_req->nr_req; i++) { if (fds[i] < 0) break; close_safe(&fds[i]); } xfree(fds); } if (reqs) xfree(reqs); close_safe(&dir); return ret; }