process-util: explicitly handle processes lacking parents in get_process_ppid()

Let's make sure we signal out-of-band via an error message if a process
doesn't have a parent process whose PID we could return. Otherwise we'll
too likely hide errors, as we return an invalid PID 0, which in other
contexts has special meaning (i.e. usually "myself").

Replaces: #20153

This is based on work by @dtardon, but goes a different route, by
ensuring we propagate a proper error in this case.

This modernizes the function in question a bit in other ways, i.e.
renames stuff and makes the return parameter optional.
This commit is contained in:
Lennart Poettering
2021-07-07 18:41:08 +01:00
committed by Luca Boccassi
parent 682047f834
commit 0c4d1e6d96
3 changed files with 72 additions and 26 deletions
+18 -9
View File
@@ -643,20 +643,23 @@ int get_process_environ(pid_t pid, char **env) {
return 0;
}
int get_process_ppid(pid_t pid, pid_t *_ppid) {
int r;
int get_process_ppid(pid_t pid, pid_t *ret) {
_cleanup_free_ char *line = NULL;
long unsigned ppid;
const char *p;
int r;
assert(pid >= 0);
assert(_ppid);
if (pid == 0 || pid == getpid_cached()) {
*_ppid = getppid();
if (ret)
*ret = getppid();
return 0;
}
if (pid == 1) /* PID 1 has no parent, shortcut this case */
return -EADDRNOTAVAIL;
p = procfs_file_alloca(pid, "stat");
r = read_one_line_file(p, &line);
if (r == -ENOENT)
@@ -664,9 +667,8 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) {
if (r < 0)
return r;
/* Let's skip the pid and comm fields. The latter is enclosed
* in () but does not escape any () in its value, so let's
* skip over it manually */
/* Let's skip the pid and comm fields. The latter is enclosed in () but does not escape any () in its
* value, so let's skip over it manually */
p = strrchr(line, ')');
if (!p)
@@ -680,10 +682,17 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) {
&ppid) != 1)
return -EIO;
if ((long unsigned) (pid_t) ppid != ppid)
/* If ppid is zero the process has no parent. Which might be the case for PID 1 but also for
* processes originating in other namespaces that are inserted into a pidns. Return a recognizable
* error in this case. */
if (ppid == 0)
return -EADDRNOTAVAIL;
if ((pid_t) ppid < 0 || (long unsigned) (pid_t) ppid != ppid)
return -ERANGE;
*_ppid = (pid_t) ppid;
if (ret)
*ret = (pid_t) ppid;
return 0;
}