static int check_shm_sanity(void) { unsigned int i; if (shm->running_childs == 0) return SHM_OK; for_each_pidslot(i) { pid_t pid; pid = shm->pids[i]; if (pid == EMPTY_PIDSLOT) continue; if (pid_is_valid(pid) == FALSE) { shm->exit_reason = EXIT_PID_OUT_OF_RANGE; return SHM_CORRUPT; } } // FIXME: The '500000' is magic, and should be dynamically calculated. // On startup, we should figure out how many getpid()'s per second we can do, // and use that. if (shm->total_syscalls_done - shm->previous_count > 500000) { output(0, "Execcount increased dramatically! (old:%ld new:%ld):\n", shm->previous_count, shm->total_syscalls_done); shm->exit_reason = EXIT_SHM_CORRUPTION; } shm->previous_count = shm->total_syscalls_done; return SHM_OK; }
void server_process_native_message( Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { size_t remaining = buffer_size; ClientContext *context; int r; assert(s); assert(buffer || buffer_size == 0); if (ucred && pid_is_valid(ucred->pid)) { r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context); if (r < 0) log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid); } do { r = server_process_entry(s, (const uint8_t*) buffer + (buffer_size - remaining), &remaining, context, ucred, tv, label, label_len); } while (r == 0); }
int msg_send_int(msg_t *m, kernel_pid_t target_pid) { #ifdef DEVELHELP if (!pid_is_valid(target_pid)) { DEBUG("msg_send(): target_pid is invalid, continuing anyways\n"); } #endif /* DEVELHELP */ thread_t *target = (thread_t *) sched_threads[target_pid]; if (target == NULL) { DEBUG("msg_send_int(): target thread does not exist\n"); return -1; } m->sender_pid = KERNEL_PID_ISR; if (target->status == STATUS_RECEIVE_BLOCKED) { DEBUG("msg_send_int: Direct msg copy from %" PRIkernel_pid " to %" PRIkernel_pid ".\n", thread_getpid(), target_pid); /* copy msg to target */ msg_t *target_message = (msg_t*) target->wait_data; *target_message = *m; sched_set_status(target, STATUS_PENDING); sched_context_switch_request = 1; return 1; } else { DEBUG("msg_send_int: Receiver not waiting.\n"); return (queue_msg(target, m)); } }
volatile tcb_t *thread_get(kernel_pid_t pid) { if (pid_is_valid(pid)) { return sched_threads[pid]; } return NULL; }
static unsigned int reap_dead_kids(void) { unsigned int i; unsigned int alive = 0; unsigned int reaped = 0; for_each_child(i) { struct childdata *child; pid_t pid; int ret; child = shm->children[i]; pid = child->pid; if (pid == EMPTY_PIDSLOT) continue; if (pid_is_valid(pid) == FALSE) { static bool once = FALSE; if (once != FALSE) return 0; output(0, "Sanity check failed! Found pid %u at pidslot %u!\n", pid, i); dump_childnos(); if (shm->exit_reason == STILL_RUNNING) panic(EXIT_PID_OUT_OF_RANGE); dump_childdata(child); once = TRUE; return 0; } ret = kill(pid, 0); /* If it disappeared, reap it. */ if (ret == -1) { if (errno == ESRCH) { output(0, "pid %u has disappeared. Reaping.\n", pid); reap_child(pid); reaped++; } else { output(0, "problem checking on pid %u (%d:%s)\n", pid, errno, strerror(errno)); } } else { alive++; } if (shm->running_childs == 0) return 0; } if (reaped != 0) output(0, "Reaped %d dead children\n", reaped); return alive; }
static void kill_all_kids(void) { unsigned int i; shm->spawn_no_more = TRUE; reap_dead_kids(); /* Wait for all the children to exit. */ while (shm->running_childs > 0) { int children_seen = 0; /* Ok, some kids are still alive. 'help' them along with a SIGKILL */ for_each_child(i) { pid_t pid; int ret; pid = shm->children[i]->pid; if (pid == EMPTY_PIDSLOT) continue; /* if we find corruption, just skip over it. */ if (pid_is_valid(pid) == FALSE) continue; children_seen++; ret = kill(pid, SIGKILL); /* check we don't have anything stale in the pidlist */ if (ret == -1) { if (errno == ESRCH) reap_child(pid); } } if (children_seen == 0) shm->running_childs = 0; /* Check that no dead children hold locks. */ check_all_locks(); /* wait a second to give kids a chance to exit. */ sleep(1); } /* Just to be sure, clear out the pid slots. */ for_each_child(i) shm->children[i]->pid = EMPTY_PIDSLOT; }
static void client_context_read_uid_gid(ClientContext *c, const struct ucred *ucred) { assert(c); assert(pid_is_valid(c->pid)); /* The ucred data passed in is always the most current and accurate, if we have any. Use it. */ if (ucred && uid_is_valid(ucred->uid)) c->uid = ucred->uid; else (void) get_process_uid(c->pid, &c->uid); if (ucred && gid_is_valid(ucred->gid)) c->gid = ucred->gid; else (void) get_process_gid(c->pid, &c->gid); }
static void client_context_read_basic(ClientContext *c) { char *t; assert(c); assert(pid_is_valid(c->pid)); if (get_process_comm(c->pid, &t) >= 0) free_and_replace(c->comm, t); if (get_process_exe(c->pid, &t) >= 0) free_and_replace(c->exe, t); if (get_process_cmdline(c->pid, 0, false, &t) >= 0) free_and_replace(c->cmdline, t); if (get_process_capeff(c->pid, &t) >= 0) free_and_replace(c->capeff, t); }
/* * Make sure various entries in the shm look sensible. * We use this to make sure that random syscalls haven't corrupted it. * * also check the pids for sanity. */ static int shm_is_corrupt(void) { unsigned int i; // FIXME: The '500000' is magic, and should be dynamically calculated. // On startup, we should figure out how many getpid()'s per second we can do, // and use that. if (shm->stats.total_syscalls_done - shm->stats.previous_op_count > 500000) { output(0, "Execcount increased dramatically! (old:%ld new:%ld):\n", shm->stats.previous_op_count, shm->stats.total_syscalls_done); panic(EXIT_SHM_CORRUPTION); return TRUE; } shm->stats.previous_op_count = shm->stats.total_syscalls_done; for_each_child(i) { struct childdata *child; pid_t pid; child = shm->children[i]; pid = child->pid; if (pid == EMPTY_PIDSLOT) continue; if (pid_is_valid(pid) == FALSE) { static bool once = FALSE; if (once != FALSE) return TRUE; output(0, "Sanity check failed! Found pid %u at pidslot %u!\n", pid, i); dump_childnos(); if (shm->exit_reason == STILL_RUNNING) panic(EXIT_PID_OUT_OF_RANGE); dump_childdata(child); once = TRUE; return TRUE; } } return FALSE; }
static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { ClientContext *c; int r; assert(s); assert(pid_is_valid(pid)); assert(ret); r = hashmap_ensure_allocated(&s->client_contexts, NULL); if (r < 0) return r; r = prioq_ensure_allocated(&s->client_contexts_lru, client_context_compare); if (r < 0) return r; c = new0(ClientContext, 1); if (!c) return -ENOMEM; c->pid = pid; c->uid = UID_INVALID; c->gid = GID_INVALID; c->auditid = AUDIT_SESSION_INVALID; c->loginuid = UID_INVALID; c->owner_uid = UID_INVALID; c->lru_index = PRIOQ_IDX_NULL; c->timestamp = USEC_INFINITY; c->extra_fields_mtime = NSEC_INFINITY; c->log_level_max = -1; c->log_rate_limit_interval = s->rate_limit_interval; c->log_rate_limit_burst = s->rate_limit_burst; r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); if (r < 0) { free(c); return r; } *ret = c; return 0; }
static int client_context_read_label( ClientContext *c, const char *label, size_t label_size) { assert(c); assert(pid_is_valid(c->pid)); assert(label_size == 0 || label); if (label_size > 0) { char *l; /* If we got an SELinux label passed in it counts. */ l = newdup_suffix0(char, label, label_size); if (!l) return -ENOMEM; free_and_replace(c->label, l); c->label_size = label_size; }
/* * Make sure various entries in the shm look sensible. * We use this to make sure that random syscalls haven't corrupted it. * * also check the pids for sanity. */ static int shm_is_corrupt(void) { unsigned int i; if (shm->stats.op_count < shm->stats.previous_op_count) { output(0, "Execcount went backwards! (old:%ld new:%ld):\n", shm->stats.previous_op_count, shm->stats.op_count); panic(EXIT_SHM_CORRUPTION); return TRUE; } shm->stats.previous_op_count = shm->stats.op_count; for_each_child(i) { struct childdata *child; pid_t pid; child = shm->children[i]; pid = pids[i]; if (pid == EMPTY_PIDSLOT) continue; if (pid_is_valid(pid) == FALSE) { static bool once = FALSE; if (once != FALSE) return TRUE; output(0, "Sanity check failed! Found pid %u at pidslot %u!\n", pid, i); dump_childnos(); if (shm->exit_reason == STILL_RUNNING) panic(EXIT_PID_OUT_OF_RANGE); dump_childdata(child); once = TRUE; return TRUE; } } return FALSE; }
/* Make sure there's no dead kids lying around. * We need to do this in case the oom killer has been killing them, * otherwise we end up stuck with no child processes. */ static void reap_dead_kids(void) { unsigned int i; unsigned int reaped = 0; for_each_child(i) { struct childdata *child; pid_t pid; int ret; child = shm->children[i]; pid = child->pid; if (pid == EMPTY_PIDSLOT) continue; /* if we find corruption, just skip over it. */ if (pid_is_valid(pid) == FALSE) continue; ret = kill(pid, 0); /* If it disappeared, reap it. */ if (ret == -1) { if (errno == ESRCH) { output(0, "pid %u has disappeared. Reaping.\n", pid); reap_child(pid); reaped++; } else { output(0, "problem checking on pid %u (%d:%s)\n", pid, errno, strerror(errno)); } } if (shm->running_childs == 0) return; } if (reaped != 0) output(0, "Reaped %d dead children\n", reaped); }
void dump_childnos(void) { unsigned int i, j = 0; char string[512], *sptr = string; sptr += sprintf(sptr, "## pids: (%u active)\n", shm->running_childs); for (i = 0; i < max_children; i += 8) { sptr += sprintf(sptr, "%u-%u: ", i, i + 7); for (j = 0; j < 8; j++) { struct childdata *child; if (i + j > max_children) break; child = shm->children[i + j]; if (pids[child->num] == EMPTY_PIDSLOT) { sptr += sprintf(sptr, "[empty] "); } else { pid_t pid = pids[child->num]; if (pid_is_valid(pid) == FALSE) sptr += sprintf(sptr, "%s", ANSI_RED); if (pid_alive(pid) == FALSE) sptr += sprintf(sptr, "%s", ANSI_RED); sptr += sprintf(sptr, "%u %s", pid, ANSI_RESET); } } sptr += sprintf(sptr, "\n"); *sptr = '\0'; outputerr("%s", string); sptr = string; } }
static int _msg_send(msg_t *m, kernel_pid_t target_pid, bool block, unsigned state) { #ifdef DEVELHELP if (!pid_is_valid(target_pid)) { DEBUG("msg_send(): target_pid is invalid, continuing anyways\n"); } #endif /* DEVELHELP */ thread_t *target = (thread_t*) sched_threads[target_pid]; m->sender_pid = sched_active_pid; if (target == NULL) { DEBUG("msg_send(): target thread does not exist\n"); irq_restore(state); return -1; } thread_t *me = (thread_t *) sched_active_thread; DEBUG("msg_send() %s:%i: Sending from %" PRIkernel_pid " to %" PRIkernel_pid ". block=%i src->state=%i target->state=%i\n", RIOT_FILE_RELATIVE, __LINE__, sched_active_pid, target_pid, block, me->status, target->status); if (target->status != STATUS_RECEIVE_BLOCKED) { DEBUG("msg_send() %s:%i: Target %" PRIkernel_pid " is not RECEIVE_BLOCKED.\n", RIOT_FILE_RELATIVE, __LINE__, target_pid); if (queue_msg(target, m)) { DEBUG("msg_send() %s:%i: Target %" PRIkernel_pid " has a msg_queue. Queueing message.\n", RIOT_FILE_RELATIVE, __LINE__, target_pid); irq_restore(state); if (me->status == STATUS_REPLY_BLOCKED) { thread_yield_higher(); } return 1; } if (!block) { DEBUG("msg_send: %" PRIkernel_pid ": Receiver not waiting, block=%u\n", me->pid, block); irq_restore(state); return 0; } DEBUG("msg_send: %" PRIkernel_pid ": going send blocked.\n", me->pid); me->wait_data = (void*) m; int newstatus; if (me->status == STATUS_REPLY_BLOCKED) { newstatus = STATUS_REPLY_BLOCKED; } else { newstatus = STATUS_SEND_BLOCKED; } sched_set_status((thread_t*) me, newstatus); thread_add_to_list(&(target->msg_waiters), me); irq_restore(state); thread_yield_higher(); DEBUG("msg_send: %" PRIkernel_pid ": Back from send block.\n", me->pid); } else { DEBUG("msg_send: %" PRIkernel_pid ": Direct msg copy from %" PRIkernel_pid " to %" PRIkernel_pid ".\n", me->pid, thread_getpid(), target_pid); /* copy msg to target */ msg_t *target_message = (msg_t*) target->wait_data; *target_message = *m; sched_set_status(target, STATUS_PENDING); irq_restore(state); thread_yield_higher(); } return 1; }
static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) { struct iovec *iovec; int priority; char syslog_priority[] = "PRIORITY=\0"; char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1]; _cleanup_free_ char *message = NULL, *syslog_identifier = NULL; size_t n = 0, m; int r; assert(s); assert(p); if (s->context) (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY); else if (pid_is_valid(s->ucred.pid)) { r = client_context_acquire(s->server, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context); if (r < 0) log_warning_errno(r, "Failed to acquire client context, ignoring: %m"); } priority = s->priority; if (s->level_prefix) syslog_parse_priority(&p, &priority, false); if (!client_context_test_priority(s->context, priority)) return 0; if (isempty(p)) return 0; if (s->forward_to_syslog || s->server->forward_to_syslog) server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); if (s->forward_to_kmsg || s->server->forward_to_kmsg) server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred); if (s->forward_to_console || s->server->forward_to_console) server_forward_console(s->server, priority, s->identifier, p, &s->ucred); if (s->server->forward_to_wall) server_forward_wall(s->server, priority, s->identifier, p, &s->ucred); m = N_IOVEC_META_FIELDS + 7 + client_context_extra_fields_n_iovec(s->context); iovec = newa(struct iovec, m); iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=stdout"); iovec[n++] = IOVEC_MAKE_STRING(s->id_field); syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority); iovec[n++] = IOVEC_MAKE_STRING(syslog_priority); if (priority & LOG_FACMASK) { xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); iovec[n++] = IOVEC_MAKE_STRING(syslog_facility); } if (s->identifier) { syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier); if (syslog_identifier) iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier); } if (line_break != LINE_BREAK_NEWLINE) { const char *c; /* If this log message was generated due to an uncommon line break then mention this in the log * entry */ c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" : line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" : "_LINE_BREAK=eof"; iovec[n++] = IOVEC_MAKE_STRING(c); } message = strappend("MESSAGE=", p); if (message) iovec[n++] = IOVEC_MAKE_STRING(message); server_dispatch_message(s->server, iovec, n, m, s->context, NULL, priority, 0); return 0; }