incidentd: fix race in waitpid_with_timeout
waitpid_with_timeout has a race between a child process exiting and the signal being blocked. Add an early waitpid to detect a child that exited quickly. Test: TH Bug: 215574756 Change-Id: I6c7e9998d5b848c6144769f218fbcd7a0ee154bf (cherry picked from commit 1f3012d2235276348edda1f8a0564c223b7aff8e)
This commit is contained in:
parent
7f9d05c6d2
commit
2538e20d62
@ -184,11 +184,26 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
|
|||||||
sigemptyset(&child_mask);
|
sigemptyset(&child_mask);
|
||||||
sigaddset(&child_mask, SIGCHLD);
|
sigaddset(&child_mask, SIGCHLD);
|
||||||
|
|
||||||
|
// block SIGCHLD before we check if a process has exited
|
||||||
if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
|
if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
|
||||||
ALOGW("sigprocmask failed: %s", strerror(errno));
|
ALOGW("*** sigprocmask failed: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the child has exited already, handle and reset signals before leaving
|
||||||
|
pid_t child_pid = waitpid(pid, status, WNOHANG);
|
||||||
|
if (child_pid != pid) {
|
||||||
|
if (child_pid > 0) {
|
||||||
|
ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
|
||||||
|
sigprocmask(SIG_SETMASK, &old_mask, nullptr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sigprocmask(SIG_SETMASK, &old_mask, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for a SIGCHLD
|
||||||
timespec ts;
|
timespec ts;
|
||||||
ts.tv_sec = timeout_ms / 1000;
|
ts.tv_sec = timeout_ms / 1000;
|
||||||
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
|
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
|
||||||
@ -197,7 +212,7 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
|
|||||||
|
|
||||||
// Set the signals back the way they were.
|
// Set the signals back the way they were.
|
||||||
if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
|
if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
|
||||||
ALOGW("sigprocmask failed: %s", strerror(errno));
|
ALOGW("*** sigprocmask failed: %s\n", strerror(errno));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -207,21 +222,21 @@ static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
|
|||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
} else {
|
} else {
|
||||||
ALOGW("sigtimedwait failed: %s", strerror(errno));
|
ALOGW("*** sigtimedwait failed: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t child_pid = waitpid(pid, status, WNOHANG);
|
child_pid = waitpid(pid, status, WNOHANG);
|
||||||
if (child_pid == pid) {
|
if (child_pid != pid) {
|
||||||
return true;
|
if (child_pid != -1) {
|
||||||
|
ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
|
||||||
|
} else {
|
||||||
|
ALOGW("*** waitpid failed: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (child_pid == -1) {
|
return true;
|
||||||
ALOGW("waitpid failed: %s", strerror(errno));
|
|
||||||
} else {
|
|
||||||
ALOGW("Waiting for pid %d, got pid %d instead", pid, child_pid);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t kill_child(pid_t pid) {
|
status_t kill_child(pid_t pid) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user