psmisc/bugfix-fix-pstree-coredump-due-pid-reuse.patch

199 lines
7.3 KiB
Diff
Raw Normal View History

2020-07-16 09:18:44 +00:00
From 9eec9fc3cf7960157c42105343492a07f1039fce Mon Sep 17 00:00:00 2001
From: chenmingmin <chenmingmin@huawei.com>
Date: Fri, 17 Apr 2020 08:52:38 -0400
Subject: [PATCH] pstree scans /proc directory to construct tree of all
processes. In scanning, if a pid or tid is already added to ps tree, and then
exists, and it is reused by another process or thread, there will be a loop
in ps tree, and will cause coredump in tree_equal function. An example step
is as below.
2019-09-30 11:14:16 -04:00
1. process A added to ps tree
2. process B added to ps tree as a child of Author
3. B exists and its pid is reused by process C(with same pid as B)
2020-07-16 09:18:44 +00:00
4. A exists and its pid is reused by process D(with same pid as A) as a
child of process C
2019-09-30 11:14:16 -04:00
5. hence, A(pid1)->B(pid2)->C(pid2)->D(pid1)->B(pid)->... loop is constructed
This patch fix this problem by not adding processes with pid reused to ps tree.
2020-07-16 09:18:44 +00:00
2019-09-30 11:14:16 -04:00
---
2020-07-16 09:18:44 +00:00
src/pstree.c | 112 ++++++++++++++++++++++++++++++++-------------------
1 file changed, 71 insertions(+), 41 deletions(-)
2019-09-30 11:14:16 -04:00
diff --git a/src/pstree.c b/src/pstree.c
2020-07-16 09:18:44 +00:00
index 99881e9..4212c8b 100644
2019-09-30 11:14:16 -04:00
--- a/src/pstree.c
+++ b/src/pstree.c
2020-07-16 09:18:44 +00:00
@@ -127,6 +127,8 @@ typedef struct _proc {
2019-09-30 11:14:16 -04:00
#define PFLAG_HILIGHT 0x01
#define PFLAG_THREAD 0x02
+#define ISTHREAD(proc) ((proc)->flags & ~PFLAG_THREAD)
+
typedef struct _child {
PROC *child;
struct _child *next;
2020-07-16 09:18:44 +00:00
@@ -615,16 +617,44 @@ rename_proc(PROC *this, const char *comm, uid_t uid)
2019-09-30 11:14:16 -04:00
}
}
-static void
+static int has_proc_loop(const PROC *parent, const PROC *child) {
+ int ret = 0;
+ const PROC *raw_parent = parent;
+ if(child != NULL) {
+ while(parent != NULL) {
+ if(parent == child) {
+ ret = 1;
+ break ;
+ }
+ parent = parent->parent;
+ if(parent == raw_parent)
+ break ;
+ }
+ }
+ return ret;
+}
+
+static int
add_proc(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
2020-07-16 09:18:44 +00:00
const char *args, int size, char isthread, security_context_t scontext,
double process_age_sec)
2019-09-30 11:14:16 -04:00
{
PROC *this, *parent;
+ if (!(parent = find_proc(ppid))) {
+ parent = new_proc("?", ppid, 0, scontext);
+ }
if (!(this = find_proc(pid)))
this = new_proc(comm, pid, uid, scontext);
else {
+ if(strcmp(this->comm, "?") != 0 || has_proc_loop(parent, this)) {
+ /*when comm is not ?, then it is not a placeholder process, and there
+ * comes the scenario of pid/tid reuse.
+ * or if it is a placeholder, but there contains a proc loop,
+ * it will not be added to ps tree.
+ */
+ return -1;
+ }
rename_proc(this, comm, uid);
}
if (args)
2020-07-16 09:18:44 +00:00
@@ -635,13 +665,13 @@ add_proc(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
this->age = process_age_sec;
2019-09-30 11:14:16 -04:00
if (isthread)
this->flags |= PFLAG_THREAD;
- if (!(parent = find_proc(ppid))) {
- parent = new_proc("?", ppid, 0, scontext);
- }
- if (pid != 0) {
2020-07-16 09:18:44 +00:00
+
+ if (pid != 0 && !ISTHREAD(parent)) {
2019-09-30 11:14:16 -04:00
+ /*thread can not have any children. this can happen when a tid is reused as a pid*/
add_child(parent, this);
this->parent = parent;
}
2020-07-16 09:18:44 +00:00
+ return 0;
2019-09-30 11:14:16 -04:00
}
2020-07-16 09:18:44 +00:00
@@ -993,7 +1023,7 @@ static void read_proc(void)
2019-09-30 11:14:16 -04:00
char readbuf[BUFSIZ + 1];
char *tmpptr, *endptr;
pid_t pid, ppid, pgid;
- int fd, size;
2020-07-16 09:18:44 +00:00
+ int fd, size,ret;
2019-09-30 11:14:16 -04:00
int empty;
security_context_t scontext = NULL;
2020-07-16 09:18:44 +00:00
unsigned long long proc_stt_jf = 0;
@@ -1057,44 +1087,14 @@ static void read_proc(void)
2019-09-30 11:14:16 -04:00
char *taskpath;
int thread;
2020-07-16 09:18:44 +00:00
- process_age_sec = process_age(proc_stt_jf);
2019-09-30 11:14:16 -04:00
- /* handle process threads */
- if (! hide_threads) {
- if (! (taskpath = malloc(strlen(path) + 10)))
- exit(2);
- sprintf(taskpath, "%s/task", path);
-
- if ((taskdir = opendir(taskpath)) != 0) {
- /* if we have this dir, we're on 2.6 */
- while ((dt = readdir(taskdir)) != NULL) {
- if ((thread = atoi(dt->d_name)) != 0) {
- if (thread != pid) {
- char *threadname;
- threadname = get_threadname(pid, thread, comm);
- if (print_args)
- add_proc(threadname, thread, pid, pgid, st.st_uid,
2020-07-16 09:18:44 +00:00
- threadname, strlen (threadname) + 1, 1,scontext,
- process_age_sec);
2019-09-30 11:14:16 -04:00
- else
- add_proc(threadname, thread, pid, pgid, st.st_uid,
2020-07-16 09:18:44 +00:00
- NULL, 0, 1, scontext,
- process_age_sec);
2019-09-30 11:14:16 -04:00
- free(threadname);
- }
- }
- }
- (void) closedir(taskdir);
- }
- free(taskpath);
- }
2020-07-16 09:18:44 +00:00
-
2019-09-30 11:14:16 -04:00
+ char cmdline[128];
/* handle process */
if (!print_args)
2020-07-16 09:18:44 +00:00
- add_proc(comm, pid, ppid, pgid, st.st_uid, NULL, 0, 0, scontext,
+ ret = add_proc(comm, pid, ppid, pgid, st.st_uid, NULL, 0, 0, scontext,
process_age_sec);
2019-09-30 11:14:16 -04:00
else {
- sprintf(path, "%s/%d/cmdline", PROC_BASE, pid);
- if ((fd = open(path, O_RDONLY)) < 0) {
+ sprintf(cmdline, "%s/%d/cmdline", PROC_BASE, pid);
+ if ((fd = open(cmdline, O_RDONLY)) < 0) {
/* If this fails then the process is gone. If a PID
* was specified on the command-line then we might
* not even be interested in the current process.
2020-07-16 09:18:44 +00:00
@@ -1119,9 +1119,39 @@ static void read_proc(void)
2019-09-30 11:14:16 -04:00
size--;
if (size)
buffer[size++] = 0;
- add_proc(comm, pid, ppid, pgid, st.st_uid,
+ ret = add_proc(comm, pid, ppid, pgid, st.st_uid,
2020-07-16 09:18:44 +00:00
buffer, size, 0, scontext, process_age_sec);
2019-09-30 11:14:16 -04:00
}
2020-07-16 09:18:44 +00:00
+
2019-09-30 11:14:16 -04:00
+ if (ret >= 0) {/*do not add tids to ps tree when its parent process reuses pid/tid*/
+ /* handle process threads */
+ if (!hide_threads) {
+ if (! (taskpath = malloc(strlen(path) + 10)))
+ exit(2);
+ sprintf(taskpath, "%s/task", path);
+
+ if ((taskdir = opendir(taskpath)) != 0) {
+ /* if we have this dir, we're on 2.6 */
+ while ((dt = readdir(taskdir)) != NULL) {
+ if ((thread = atoi(dt->d_name)) != 0) {
+ if (thread != pid) {
+ char *threadname;
+ threadname = get_threadname(pid, thread, comm);
+ if (print_args)
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
2020-07-16 09:18:44 +00:00
+ threadname, strlen (threadname) + 1, 1,scontext,process_age_sec);
2019-09-30 11:14:16 -04:00
+ else
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
2020-07-16 09:18:44 +00:00
+ NULL, 0, 1, scontext,process_age_sec);
2019-09-30 11:14:16 -04:00
+ free(threadname);
+ }
+ }
+ }
+ (void) closedir(taskdir);
+ }
+ free(taskpath);
+ }
+ }
}
}
}
--
2020-07-16 09:18:44 +00:00
2.19.1