static void test_get_process_comm(pid_t pid) { struct stat st; _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL; _cleanup_free_ char *env = NULL; char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)]; pid_t e; uid_t u; gid_t g; dev_t h; int r; xsprintf(path, "/proc/"PID_FMT"/comm", pid); if (stat(path, &st) == 0) { assert_se(get_process_comm(pid, &a) >= 0); log_info("PID"PID_FMT" comm: '%s'", pid, a); } else log_warning("%s not exist.", path); assert_se(get_process_cmdline(pid, 0, true, &c) >= 0); log_info("PID"PID_FMT" cmdline: '%s'", pid, c); assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d); free(d); assert_se(get_process_cmdline(pid, 1, false, &d) >= 0); log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); assert_se(get_process_ppid(pid, &e) >= 0); log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); assert_se(pid == 1 ? e == 0 : e > 0); assert_se(is_kernel_thread(pid) == 0 || pid != 1); r = get_process_exe(pid, &f); assert_se(r >= 0 || r == -EACCES); log_info("PID"PID_FMT" exe: '%s'", pid, strna(f)); assert_se(get_process_uid(pid, &u) == 0); log_info("PID"PID_FMT" UID: "UID_FMT, pid, u); assert_se(u == 0 || pid != 1); assert_se(get_process_gid(pid, &g) == 0); log_info("PID"PID_FMT" GID: "GID_FMT, pid, g); assert_se(g == 0 || pid != 1); r = get_process_environ(pid, &env); assert_se(r >= 0 || r == -EACCES); log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno); if (!detect_container()) assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1); getenv_for_pid(pid, "PATH", &i); log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i)); }
static int bus_get_audit_data( DBusConnection *connection, const char *name, struct auditstruct *audit, DBusError *error) { pid_t pid; int r; pid = bus_get_unix_process_id(connection, name, error); if (pid <= 0) return -EIO; r = audit_loginuid_from_pid(pid, &audit->loginuid); if (r < 0) return r; r = get_process_uid(pid, &audit->uid); if (r < 0) return r; r = get_process_gid(pid, &audit->gid); if (r < 0) return r; r = get_process_cmdline(pid, LINE_MAX, true, &audit->cmdline); if (r < 0) return r; return 0; }
static void test_rename_process_now(const char *p, int ret) { _cleanup_free_ char *comm = NULL, *cmdline = NULL; int r; r = rename_process(p); assert_se(r == ret || (ret == 0 && r >= 0) || (ret > 0 && r > 0)); if (r < 0) return; #if HAVE_VALGRIND_VALGRIND_H /* see above, valgrind is weird, we can't verify what we are doing here */ if (RUNNING_ON_VALGRIND) return; #endif assert_se(get_process_comm(0, &comm) >= 0); log_info("comm = <%s>", comm); assert_se(strneq(comm, p, 15)); assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0); /* we cannot expect cmdline to be renamed properly without privileges */ if (geteuid() == 0) { log_info("cmdline = <%s>", cmdline); assert_se(strneq(p, cmdline, STRLEN("test-process-util"))); assert_se(startswith(p, cmdline)); } else log_info("cmdline = <%s> (not verified)", cmdline); }
int proc_cmdline(char **ret) { assert(ret); if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); }
static void generate_process_name(process_info_t *pi, WCHAR *name_buf /* OUT */, uint name_buf_length /* elements */) { WCHAR qual_name[MAX_CMDLINE]; WCHAR qual_args[MAX_CMDLINE]; int res; BOOL use_args = FALSE; /* hack: we assume only need qualified names for these hardcoded apps * FIXME: read registry to see whether need qualification */ if (wcsicmp(pi->ProcessName, L"svchost.exe") == 0 || wcsicmp(pi->ProcessName, L"msiexec.exe") == 0 || wcsicmp(pi->ProcessName, L"tomcat.exe") == 0 || wcsicmp(pi->ProcessName, L"dllhost.exe") == 0) { /* use qualified names */ res = get_process_cmdline(pi->ProcessID, qual_name, BUFFER_SIZE_ELEMENTS(qual_name)); NULL_TERMINATE_BUFFER(qual_name); if (res == ERROR_SUCCESS) { if (get_commandline_qualifier(qual_name, qual_args, BUFFER_SIZE_ELEMENTS(qual_args), /* hack: we assume we only strip svchost, * and we also strip dllhost here to * fit more of the GUI in and avoid the * "Processid" string. * FIXME: read from registry. */ (wcsicmp(pi->ProcessName, L"svchost.exe") != 0 && wcsicmp(pi->ProcessName, L"dllhost.exe") != 0))) { NULL_TERMINATE_BUFFER(qual_args); use_args = TRUE; } /* else not an error, just no args. e.g.: plain sqlservr.exe */ } else { /* this is an error => notify user */ _snwprintf(qual_args, BUFFER_SIZE_ELEMENTS(qual_args), L"<error>"); NULL_TERMINATE_BUFFER(qual_args); use_args = TRUE; } } if (use_args) { _snwprintf(name_buf, name_buf_length, L"%s-%s", pi->ProcessName, qual_args); } else { _snwprintf(name_buf, name_buf_length, L"%s", pi->ProcessName); } NULL_TERMINATE_SIZED_BUFFER(name_buf, name_buf_length); }
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); }
int proc_cmdline(char **ret) { const char *e; assert(ret); /* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */ e = secure_getenv("SYSTEMD_PROC_CMDLINE"); if (e) { char *m; m = strdup(e); if (!m) return -ENOMEM; *ret = m; return 0; } if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); }
static int get_audit_data( DBusConnection *connection, DBusMessage *message, struct auditstruct *audit, DBusError *error) { const char *sender; int r, fd; struct ucred ucred; socklen_t len; sender = dbus_message_get_sender(message); if (sender) return bus_get_audit_data(connection, sender, audit, error); if (!dbus_connection_get_unix_fd(connection, &fd)) return -EINVAL; r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len); if (r < 0) { log_error("Failed to determine peer credentials: %m"); return -errno; } audit->uid = ucred.uid; audit->gid = ucred.gid; r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid); if (r < 0) return r; r = get_process_cmdline(ucred.pid, LINE_MAX, true, &audit->cmdline); if (r < 0) return r; return 0; }
int main(int argc, char* argv[]) { int r, j = 0; _cleanup_free_ char *p = NULL; ssize_t n; pid_t pid; uid_t uid; gid_t gid; struct iovec iovec[14]; _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL; prctl(PR_SET_DUMPABLE, 0); if (argc != _ARG_MAX) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Invalid number of arguments passed from kernel."); r = -EINVAL; goto finish; } r = parse_pid(argv[ARG_PID], &pid); if (r < 0) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Failed to parse PID."); goto finish; } if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { /* Make sure we don't make use of the journal, * if it's the journal which is crashing */ log_set_target(LOG_TARGET_KMSG); log_open(); r = divert_coredump(); goto finish; } core_unit = strappend("COREDUMP_UNIT=", t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) core_unit = strappend("COREDUMP_USER_UNIT=", t); if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence make use of * it */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); r = parse_uid(argv[ARG_UID], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_gid(argv[ARG_GID], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); if (core_pid) IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); if (core_uid) IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); if (core_gid) IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); if (core_signal) IOVEC_SET_STRING(iovec[j++], core_signal); core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); if (core_comm) IOVEC_SET_STRING(iovec[j++], core_comm); #ifdef HAVE_LOGIND if (sd_pid_get_session(pid, &t) >= 0) { core_session = strappend("COREDUMP_SESSION=", t); free(t); if (core_session) IOVEC_SET_STRING(iovec[j++], core_session); } #endif if (get_process_exe(pid, &t) >= 0) { core_exe = strappend("COREDUMP_EXE=", t); free(t); if (core_exe) IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strappend("COREDUMP_CMDLINE=", t); free(t); if (core_cmdline) IOVEC_SET_STRING(iovec[j++], core_cmdline); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * his uid. This also ensures that the credentials journald * will see are the ones of the coredumping user, thus making * sure the user himself gets access to the core dump. */ if (setresgid(gid, gid, gid) < 0 || setresuid(uid, uid, uid) < 0) { log_error("Failed to drop privileges: %m"); r = -errno; goto finish; } p = malloc(9 + COREDUMP_MAX); if (!p) { r = log_oom(); goto finish; } memcpy(p, "COREDUMP=", 9); n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false); if (n < 0) { log_error("Failed to read core dump data: %s", strerror(-n)); r = (int) n; goto finish; } iovec[j].iov_base = p; iovec[j].iov_len = 9 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send coredump: %s", strerror(-r)); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char* argv[]) { /* The small core field we allocate on the stack, to keep things simple */ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, *core_slice = NULL; /* The larger ones we allocate on the heap */ _cleanup_free_ char *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL; const char *info[_INFO_LEN]; _cleanup_close_ int coredump_fd = -1; struct iovec iovec[26]; uint64_t coredump_size; int r, j = 0; uid_t uid, owner_uid; gid_t gid; pid_t pid; char *t; const char *p; /* Make sure we never enter a loop */ prctl(PR_SET_DUMPABLE, 0); /* First, log to a safe place, since we don't know what * crashed and it might be journald which we'd rather not log * to then. */ log_set_target(LOG_TARGET_KMSG); log_open(); if (argc < INFO_COMM + 1) { log_error("Not enough arguments passed from kernel (%d, expected %d).", argc - 1, INFO_COMM + 1 - 1); r = -EINVAL; goto finish; } /* Ignore all parse errors */ parse_config(); log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); log_debug("Selected compression %s.", yes_no(arg_compress)); r = parse_uid(argv[INFO_UID + 1], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_pid(argv[INFO_PID + 1], &pid); if (r < 0) { log_error("Failed to parse PID."); goto finish; } r = parse_gid(argv[INFO_GID + 1], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } if (get_process_comm(pid, &comm) < 0) { log_warning("Failed to get COMM, falling back to the command line."); comm = strv_join(argv + INFO_COMM + 1, " "); } if (get_process_exe(pid, &exe) < 0) log_warning("Failed to get EXE."); info[INFO_PID] = argv[INFO_PID + 1]; info[INFO_UID] = argv[INFO_UID + 1]; info[INFO_GID] = argv[INFO_GID + 1]; info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1]; info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1]; info[INFO_COMM] = comm; info[INFO_EXE] = exe; if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { free(t); /* If we are journald, we cut things short, * don't write to the journal, but still * create a coredump. */ if (arg_storage != COREDUMP_STORAGE_NONE) arg_storage = COREDUMP_STORAGE_EXTERNAL; r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) goto finish; r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); goto finish; } core_unit = strjoina("COREDUMP_UNIT=", t); free(t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) { core_unit = strjoina("COREDUMP_USER_UNIT=", t); free(t); } if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence we can make use * of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]); IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]); IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]); IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]); IOVEC_SET_STRING(iovec[j++], core_signal); if (sd_pid_get_session(pid, &t) >= 0) { core_session = strjoina("COREDUMP_SESSION=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_session); } if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); if (r > 0) IOVEC_SET_STRING(iovec[j++], core_owner_uid); } if (sd_pid_get_slice(pid, &t) >= 0) { core_slice = strjoina("COREDUMP_SLICE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_slice); } if (comm) { core_comm = strjoina("COREDUMP_COMM=", comm); IOVEC_SET_STRING(iovec[j++], core_comm); } if (exe) { core_exe = strjoina("COREDUMP_EXE=", exe); IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strjoina("COREDUMP_CMDLINE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cmdline); } if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { core_cgroup = strjoina("COREDUMP_CGROUP=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cgroup); } if (compose_open_fds(pid, &t) >= 0) { core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); free(t); if (core_open_fds) IOVEC_SET_STRING(iovec[j++], core_open_fds); } p = procfs_file_alloca(pid, "status"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); free(t); if (core_proc_status) IOVEC_SET_STRING(iovec[j++], core_proc_status); } p = procfs_file_alloca(pid, "maps"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); free(t); if (core_proc_maps) IOVEC_SET_STRING(iovec[j++], core_proc_maps); } p = procfs_file_alloca(pid, "limits"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); free(t); if (core_proc_limits) IOVEC_SET_STRING(iovec[j++], core_proc_limits); } p = procfs_file_alloca(pid, "cgroup"); if (read_full_file(p, &t, NULL) >=0) { core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); free(t); if (core_proc_cgroup) IOVEC_SET_STRING(iovec[j++], core_proc_cgroup); } if (get_process_cwd(pid, &t) >= 0) { core_cwd = strjoina("COREDUMP_CWD=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cwd); } if (get_process_root(pid, &t) >= 0) { core_root = strjoina("COREDUMP_ROOT=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_root); } if (get_process_environ(pid, &t) >= 0) { core_environ = strappend("COREDUMP_ENVIRON=", t); free(t); if (core_environ) IOVEC_SET_STRING(iovec[j++], core_environ); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); /* Vacuum before we write anything again */ coredump_vacuum(-1, arg_keep_free, arg_max_use); /* Always stream the coredump to disk, if that's possible */ r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) /* skip whole core dumping part */ goto log; /* If we don't want to keep the coredump on disk, remove it * now, as later on we will lack the privileges for * it. However, we keep the fd to it, so that we can still * process it and log it. */ r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; if (r == 0) { const char *coredump_filename; coredump_filename = strjoina("COREDUMP_FILENAME=", filename); IOVEC_SET_STRING(iovec[j++], coredump_filename); } /* Vacuum again, but exclude the coredump we just created */ coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * the user's uid. This also ensures that the credentials * journald will see are the ones of the coredumping user, * thus making sure the user gets access to the core * dump. Let's also get rid of all capabilities, if we run as * root, we won't need them anymore. */ r = drop_privileges(uid, gid, 0); if (r < 0) { log_error_errno(r, "Failed to drop privileges: %m"); goto finish; } #ifdef HAVE_ELFUTILS /* Try to get a strack trace if we can */ if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace); if (r >= 0) core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL); else if (r == -EINVAL) log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno())); else log_warning_errno(r, "Failed to generate stack trace: %m"); } if (!core_message) #endif log: core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Optionally store the entire coredump in the journal */ if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && coredump_size <= arg_journal_size_max) { size_t sz = 0; /* Store the coredump itself in the journal */ r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz); if (r >= 0) { iovec[j].iov_base = coredump_data; iovec[j].iov_len = sz; j++; } } r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to log coredump: %m"); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
void gfire_process_list_update(gfire_process_list *p_list) { if(!p_list) return; gfire_process_list_clear(p_list); acquirePrivileges(); PROCESSENTRY32 pe; memset(&pe, 0, sizeof(pe)); pe.dwSize = sizeof(pe); HANDLE hProcSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(!hProcSnapShot) return; if(!Process32First(hProcSnapShot, &pe)) { CloseHandle(hProcSnapShot); return; } do { if(pe.th32ProcessID > 0) { #ifdef DEBUG purple_debug_info("gfire", "detection: probing %s\n", pe.szExeFile); #endif // DEBUG gchar *cmdline = NULL; gchar *executable_file = NULL; if(!get_process_cmdline(pe.th32ProcessID, &executable_file, &cmdline)) continue; #ifdef DEBUG purple_debug_info("gfire", "executable file: %s\n", executable_file); purple_debug_info("gfire", "cmdline: %s\n", cmdline); #endif // DEBUG // Extract the args from the command line gchar *args = strstr(g_strstrip(cmdline), pe.szExeFile); if(args) { args += strlen(pe.szExeFile); if(args[0] == 0) args = NULL; // If the first char behind the process' name is ", strip it else if(args[0] == '\"') { args++; if(args[0] == 0) args = NULL; } } if(args) { g_strstrip(args); #ifdef DEBUG purple_debug_info("gfire", "args: %s\n", args); #endif // DEBUG } // Add the process process_info *info = gfire_process_info_new(executable_file, pe.th32ProcessID, args); g_free(cmdline); g_free(executable_file); p_list->processes = g_list_append(p_list->processes, info); } } while(Process32Next(hProcSnapShot, &pe)); CloseHandle(hProcSnapShot); }
static void test_get_process_cmdline_harder(void) { char path[] = "/tmp/test-cmdlineXXXXXX"; _cleanup_close_ int fd = -1; _cleanup_free_ char *line = NULL; pid_t pid; if (geteuid() != 0) return; #ifdef HAVE_VALGRIND_VALGRIND_H /* valgrind patches open(/proc//cmdline) * so, test_get_process_cmdline_harder fails always * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */ if (RUNNING_ON_VALGRIND) return; #endif pid = fork(); if (pid > 0) { siginfo_t si; (void) wait_for_terminate(pid, &si); assert_se(si.si_code == CLD_EXITED); assert_se(si.si_status == 0); return; } assert_se(pid == 0); assert_se(unshare(CLONE_NEWNS) >= 0); fd = mkostemp(path, O_CLOEXEC); assert_se(fd >= 0); assert_se(mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) >= 0); assert_se(unlink(path) >= 0); assert_se(prctl(PR_SET_NAME, "testa") >= 0); assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); assert_se(streq(line, "")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); assert_se(streq(line, "[")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); assert_se(streq(line, "[.")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); assert_se(streq(line, "[..")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); assert_se(streq(line, "[...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); assert_se(streq(line, "[...]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); assert_se(streq(line, "[t...]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10); assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); assert_se(streq(line, "[testa]")); line = mfree(line); assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10); assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); assert_se(streq(line, "foo bar")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); assert_se(streq(line, "foo bar")); line = mfree(line); assert_se(write(fd, "quux", 4) == 4); assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); assert_se(streq(line, "")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); assert_se(streq(line, ".")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); assert_se(streq(line, "..")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); assert_se(streq(line, "...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); assert_se(streq(line, "f...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); assert_se(streq(line, "fo...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); assert_se(streq(line, "foo...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); assert_se(streq(line, "foo...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0); assert_se(streq(line, "foo b...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); assert_se(streq(line, "foo ba...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); assert_se(streq(line, "foo bar...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); assert_se(streq(line, "foo bar...")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0); assert_se(streq(line, "foo bar quux")); line = mfree(line); assert_se(ftruncate(fd, 0) >= 0); assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0); assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); assert_se(streq(line, "[aaaa bbbb cccc]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); assert_se(streq(line, "[aaaa...]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); assert_se(streq(line, "[aaaa...]")); line = mfree(line); assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); assert_se(streq(line, "[aaaa b...]")); line = mfree(line); safe_close(fd); _exit(0); }
static void test_get_process_comm(void) { struct stat st; _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL; _cleanup_free_ char *env = NULL; pid_t e; uid_t u; gid_t g; dev_t h; int r; pid_t me; if (stat("/proc/1/comm", &st) == 0) { assert_se(get_process_comm(1, &a) >= 0); log_info("pid1 comm: '%s'", a); } else log_warning("/proc/1/comm does not exist."); assert_se(get_process_cmdline(1, 0, true, &c) >= 0); log_info("pid1 cmdline: '%s'", c); assert_se(get_process_cmdline(1, 8, false, &d) >= 0); log_info("pid1 cmdline truncated: '%s'", d); assert_se(get_process_ppid(1, &e) >= 0); log_info("pid1 ppid: "PID_FMT, e); assert_se(e == 0); assert_se(is_kernel_thread(1) == 0); r = get_process_exe(1, &f); assert_se(r >= 0 || r == -EACCES); log_info("pid1 exe: '%s'", strna(f)); assert_se(get_process_uid(1, &u) == 0); log_info("pid1 uid: "UID_FMT, u); assert_se(u == 0); assert_se(get_process_gid(1, &g) == 0); log_info("pid1 gid: "GID_FMT, g); assert_se(g == 0); me = getpid(); r = get_process_cwd(me, &cwd); assert_se(r >= 0 || r == -EACCES); log_info("pid1 cwd: '%s'", cwd); r = get_process_root(me, &root); assert_se(r >= 0 || r == -EACCES); log_info("pid1 root: '%s'", root); r = get_process_environ(me, &env); assert_se(r >= 0 || r == -EACCES); log_info("self strlen(environ): '%zu'", strlen(env)); if (!detect_container()) assert_se(get_ctty_devnr(1, &h) == -ENXIO); getenv_for_pid(1, "PATH", &i); log_info("pid1 $PATH: '%s'", strna(i)); }
BOOL pw_callback(process_info_t *pi, void **param) { char *resstr; char reschar; int res; WCHAR buf[MAX_CMDLINE]; DWORD version; BOOL under_dr; WCHAR qual_name[MAX_CMDLINE]; if (exe) generate_process_name(pi, qual_name, BUFFER_SIZE_ELEMENTS(qual_name)); if ( (pid && pi->ProcessID == pid) || (exe && (!wcsicmp(wexe, pi->ProcessName) || !wcsicmp(wexe, qual_name))) || listall || listdr) { version = -1; res = under_dynamorio_ex(pi->ProcessID, &version); switch (res) { case DLL_PROFILE : resstr=NAME" profile"; reschar='P'; break; case DLL_RELEASE : resstr=NAME" release"; reschar='R'; break; case DLL_DEBUG : resstr=NAME" debug"; reschar='D'; break; case DLL_CUSTOM : resstr=NAME" custom"; reschar='C'; break; case DLL_NONE : resstr="native"; reschar='N'; break; case DLL_UNKNOWN : default : resstr="<error>"; reschar='?'; } under_dr = !(res == DLL_NONE || res == DLL_UNKNOWN); if (!listdr || under_dr) { if (!nopid && !showmem) { if (onlypid) fprintf(fp, "%d\n", (DWORD) pi->ProcessID); else fprintf(fp, "PID %d, ", (DWORD) pi->ProcessID); } if (!showmem && !onlypid) { WCHAR qual_name[MAX_CMDLINE]; WCHAR *name_to_use = pi->ProcessName; #ifdef X64 HANDLE hproc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD) pi->ProcessID); if (is_wow64(hproc)) { if (!no32) fprintf(fp, "32-bit, "); /* FIXME: currently x64 process can't see 32-bit * drmarker */ resstr="<unknown>"; } CloseHandle(hproc); #endif if (!noqnames) { generate_process_name(pi, qual_name, BUFFER_SIZE_ELEMENTS(qual_name)); name_to_use = qual_name; } fprintf(fp, "Process %S, ", name_to_use); if (version == -1 || !showbuild) fprintf(fp, "running %s\n", resstr); else fprintf(fp, "running %s (build %d)\n", resstr, version); } if (cmdline) { res = get_process_cmdline(pi->ProcessID, buf, BUFFER_SIZE_ELEMENTS(buf)); NULL_TERMINATE_BUFFER(buf); if (res == ERROR_SUCCESS) { fprintf(fp, "\tCmdline: %S\n", buf); } else fprintf(fp, "\t<Cmdline err %d>\n", res); } if (qname) { WCHAR cmdline[MAX_CMDLINE]; res = get_process_cmdline(pi->ProcessID, cmdline, BUFFER_SIZE_ELEMENTS(cmdline)); NULL_TERMINATE_BUFFER(cmdline); if (res == ERROR_SUCCESS) { if (!get_commandline_qualifier(cmdline, buf, BUFFER_SIZE_ELEMENTS(buf), !strip)) buf[0] = L'\0'; /* no args */ NULL_TERMINATE_BUFFER(buf); } if (res == ERROR_SUCCESS) fprintf(fp, "\tQname: %S%s%S\n", pi->ProcessName, buf[0] == L'\0' ? "" : "-", buf); else fprintf(fp, "\t<Qname err %d>\n", res); } if (under_dr && hotp) { hotp_policy_status_table_t *status_tbl = NULL; res = get_hotp_status(pi->ProcessID, &status_tbl); if (res == ERROR_SUCCESS) { uint j; hotp_policy_status_t *cur; fprintf(fp, "\tHotpatching:\n", res); for (j = 0; j < status_tbl->num_policies; j++) { char status_buf[MAX_PATH]; cur = &(status_tbl->policy_status_array[j]); if (get_status_string(status_buf, MAX_PATH, cur->inject_status, cur->mode)) fprintf(fp, "\t Patch %s: %s\n", cur->policy_id, status_buf); } } else if (res == ERROR_DRMARKER_ERROR) { fprintf(fp, "\tHot Patching Not Enabled\n", res); } else { fprintf(fp, "\t<Hotpatch Query Error %d>\n", res); } } if (under_dr && showstats) { dr_statistics_t *stats = get_dynamorio_stats(pi->ProcessID); if (stats != NULL) { uint i; fprintf(fp, "\t%.*s\n", BUFFER_SIZE_ELEMENTS(stats->process_name), stats->process_name); for (i = 0; i < stats->num_stats; i++) { fprintf(fp, "\t%*.*s :%9d\n", BUFFER_SIZE_ELEMENTS(stats->stats[i].name), BUFFER_SIZE_ELEMENTS(stats->stats[i].name), stats->stats[i].name, stats->stats[i].value); } } free_dynamorio_stats(stats); } if (showmem) { print_mem_stats(pi, reschar, version); } count++; } } return TRUE; }
static int read_process(SEXP_t *cmd_ent, SEXP_t *pid_ent, probe_ctx *ctx) { int err = 1, max_cap_id; DIR *d; struct dirent *ent; oval_version_t oval_version; d = opendir("/proc"); if (d == NULL) return err; // Get the time tick hertz ticks = (unsigned long)sysconf(_SC_CLK_TCK); get_boot_time(); oval_version = probe_obj_get_schema_version(probe_ctx_getobject(ctx)); if (oval_version_cmp(oval_version, OVAL_VERSION(5.11)) < 0) { max_cap_id = OVAL_5_8_MAX_CAP_ID; } else { max_cap_id = OVAL_5_11_MAX_CAP_ID; } struct oscap_buffer *cmdline_buffer = oscap_buffer_new(); char cmd_buffer[1 + 15 + 11 + 1]; // Format:" [ cmd:15 ] <defunc>" cmd_buffer[0] = '['; // Scan the directories while (( ent = readdir(d) )) { int fd, len; char buf[256]; char *tmp, state, tty_dev[128]; int pid, ppid, pgrp, session, tty_nr, tpgid; unsigned flags, sched_policy; unsigned long minflt, cminflt, majflt, cmajflt, uutime, ustime; long cutime, cstime, priority, cnice, nthreads, itrealvalue; unsigned long long start; SEXP_t *cmd_sexp = NULL, *pid_sexp = NULL; // Skip non-process58 dir entries if(*ent->d_name<'0' || *ent->d_name>'9') continue; errno = 0; pid = strtol(ent->d_name, NULL, 10); if (errno || pid == 2) // skip err & kthreads continue; // Parse up the stat file for the proc snprintf(buf, 32, "/proc/%d/stat", pid); fd = open(buf, O_RDONLY, 0); if (fd < 0) continue; len = read(fd, buf, sizeof buf - 1); close(fd); if (len < 40) continue; buf[len] = 0; tmp = strrchr(buf, ')'); if (tmp) *tmp = 0; else continue; memset(cmd_buffer + 1, 0, sizeof(cmd_buffer)-1); // clear cmd after starting '[' sscanf(buf, "%d (%15c", &ppid, cmd_buffer + 1); sscanf(tmp+2, "%c %d %d %d %d %d " "%u %lu %lu %lu %lu " "%lu %lu %lu %ld %ld " "%ld %ld %ld %llu", &state, &ppid, &pgrp, &session, &tty_nr, &tpgid, &flags, &minflt, &cminflt, &majflt, &cmajflt, &uutime, &ustime, &cutime, &cstime, &priority, &cnice, &nthreads, &itrealvalue, &start ); // Skip kthreads if (ppid == 2) continue; const char* cmd; if (state == 'Z') { // zombie cmd = make_defunc_str(cmd_buffer); } else { snprintf(buf, 32, "/proc/%d/cmdline", pid); if (get_process_cmdline(buf, cmdline_buffer)) { cmd = oscap_buffer_get_raw(cmdline_buffer); // use full cmdline } else { cmd = cmd_buffer + 1; } } err = 0; // If we get this far, no permission problems dI("Have command: %s\n", cmd); cmd_sexp = SEXP_string_newf("%s", cmd); pid_sexp = SEXP_number_newu_32(pid); if ((cmd_sexp == NULL || probe_entobj_cmp(cmd_ent, cmd_sexp) == OVAL_RESULT_TRUE) && (pid_sexp == NULL || probe_entobj_cmp(pid_ent, pid_sexp) == OVAL_RESULT_TRUE) ) { struct result_info r; unsigned long t = uutime/ticks + ustime/ticks; char tbuf[32], sbuf[32], *selinux_domain_label, **posix_capabilities; int tday,tyear; time_t s_time; struct tm *proc, *now; const char *fmt; // Now get scheduler policy sched_policy = sched_getscheduler(pid); switch (sched_policy) { case SCHED_OTHER: r.scheduling_class = "TS"; break; case SCHED_BATCH: r.scheduling_class = "B"; break; #ifdef SCHED_IDLE case SCHED_IDLE: r.scheduling_class = "#5"; break; #endif case SCHED_FIFO: r.scheduling_class = "FF"; break; case SCHED_RR: r.scheduling_class = "RR"; break; default: r.scheduling_class = "?"; break; } // Calculate the start time s_time = time(NULL); now = localtime(&s_time); tyear = now->tm_year; tday = now->tm_yday; s_time = boot + (start / ticks); proc = localtime(&s_time); // Select format based on how long we've been running // // FROM THE SPEC: // "This is the time of day the process started formatted in HH:MM:SS if // the same day the process started or formatted as MMM_DD (Ex.: Feb_5) // if process started the previous day or further in the past." // if (tday != proc->tm_yday || tyear != proc->tm_year) fmt = "%b_%d"; else fmt = "%H:%M:%S"; strftime(sbuf, sizeof(sbuf), fmt, proc); r.command_line = cmd; r.exec_time = convert_time(t, tbuf, sizeof(tbuf)); r.pid = pid; r.ppid = ppid; r.priority = priority; r.start_time = sbuf; dev_to_tty(tty_dev, sizeof(tty_dev), (dev_t) tty_nr, pid, ABBREV_DEV); r.tty = tty_dev; r.exec_shield = (get_exec_shield_status(pid) > 0); selinux_domain_label = get_selinux_label(pid); r.selinux_domain_label = selinux_domain_label; posix_capabilities = get_posix_capability(pid, max_cap_id); r.posix_capability = posix_capabilities; r.session_id = session; get_uids(pid, &r); report_finding(&r, ctx); if (selinux_domain_label != NULL) free(selinux_domain_label); if (posix_capabilities != NULL) { char **posix_capabilities_p = posix_capabilities; while (*posix_capabilities_p) free(*posix_capabilities_p++); free(posix_capabilities); } } SEXP_free(cmd_sexp); SEXP_free(pid_sexp); } closedir(d); oscap_buffer_free(cmdline_buffer); return err; }