forked from google/xsecurelock
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathprocess_util.c
More file actions
208 lines (187 loc) · 5.05 KB
/
Copy pathprocess_util.c
File metadata and controls
208 lines (187 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// SPDX-License-Identifier: Apache-2.0
#include "config.h"
#include "process_util.h"
#include <errno.h>
#include <stdbool.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include "build-config.h"
#include "io_util.h"
#include "logging.h"
#include "time_util.h"
#include "xsl_signal.h"
static char *const *BorrowExecvArgv(const char *const argv[]) {
char *const *execv_argv = NULL;
memcpy((void *)&execv_argv, (const void *)&argv, sizeof(execv_argv));
return execv_argv;
}
static int ExecvHelper(const char *path, const char *const argv[]);
static void ExecvHelperOrExit(const char *path, const char *const argv[]);
pid_t ForkWithoutSigHandlers(void) {
sigset_t oldset;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGCHLD);
sigemptyset(&oldset);
if (sigprocmask(SIG_BLOCK, &set, &oldset)) {
LogErrno("Unable to block signals");
}
pid_t pid = fork();
int fork_errno = errno;
if (pid == 0) {
if (ResetSignalToDefault(SIGUSR1) != 0) {
LogErrno("sigaction(SIGUSR1)");
}
if (ResetSignalToDefault(SIGUSR2) != 0) {
LogErrno("sigaction(SIGUSR2)");
}
if (ResetSignalToDefault(SIGTERM) != 0) {
LogErrno("sigaction(SIGTERM)");
}
if (ResetSignalToDefault(SIGCHLD) != 0) {
LogErrno("sigaction(SIGCHLD)");
}
}
if (sigprocmask(SIG_SETMASK, &oldset, NULL)) {
LogErrno("Unable to restore signal mask");
}
errno = fork_errno;
return pid;
}
void StartPgrp(void) {
if (setsid() == (pid_t)-1) {
LogErrno("setsid");
}
// To avoid a race condition when killing the process group after the leader
// is already dead (which could then kill another new process group with the
// same ID), keep a placeholder alive until the group is explicitly signaled.
pid_t pid = fork();
if (pid == -1) {
LogErrno("StartPgrp -> fork; expect potential race in KillPgrp");
} else if (pid == 0) {
if (IgnoreSignal(SIGUSR1) != 0) {
LogErrno("sigaction(SIGUSR1)");
}
if (IgnoreSignal(SIGUSR2) != 0) {
LogErrno("sigaction(SIGUSR2)");
}
const char *args[2] = {"pgrp_placeholder", NULL};
ExecvHelperOrExit("pgrp_placeholder", args);
}
}
pid_t ForkHelperChild(const char *label, ChildSetupFn setup, void *setup_arg,
const char *path, const char *const argv[]) {
pid_t pid = ForkWithoutSigHandlers();
if (pid == -1) {
LogErrno("fork for %s", label);
return -1;
}
if (pid == 0) {
if (setup != NULL) {
setup(setup_arg);
}
ExecvHelperOrExit(path, argv);
}
return pid;
}
pid_t ForkHelperPgrpChild(const char *label, ChildSetupFn setup,
void *setup_arg, const char *path,
const char *const argv[]) {
pid_t pid = ForkWithoutSigHandlers();
if (pid == -1) {
LogErrno("fork for %s", label);
return -1;
}
if (pid == 0) {
StartPgrp();
if (setup != NULL) {
setup(setup_arg);
}
ExecvHelperOrExit(path, argv);
}
return pid;
}
static int ExecvHelper(const char *path, const char *const argv[]) {
if (chdir(HELPER_PATH)) {
LogErrno("chdir %s", HELPER_PATH);
return -1;
}
execv(path, BorrowExecvArgv(argv));
int saved_errno = errno;
LogErrno("execv %s", path);
errno = saved_errno;
return -1;
}
static void ExecvHelperOrExit(const char *path, const char *const argv[]) {
ExecvHelper(path, argv);
(void)SleepMs(2000);
_exit(EXIT_FAILURE);
}
void ExecvpOrExit(const char *path, char *const argv[]) {
execvp(path, argv);
LogErrno("execvp %s", path);
_exit(EXIT_FAILURE);
}
static void MoveStdioFdOrExit(int *fd, int target_fd) {
if (*fd < 0) {
return;
}
if (*fd <= STDERR_FILENO && *fd != target_fd) {
*fd = DuplicateAwayFromStdio(*fd);
if (*fd < 0) {
LogErrno("DuplicateAwayFromStdio");
_exit(EXIT_FAILURE);
}
}
if (MoveFdTo(fd, target_fd) != 0) {
LogErrno("MoveFdTo");
_exit(EXIT_FAILURE);
}
}
void ChildWireStdioOrExit(const struct ChildStdioSetup *setup) {
struct ChildStdioSetup local = *setup;
MoveStdioFdOrExit(&local.stdin_fd, STDIN_FILENO);
MoveStdioFdOrExit(&local.stdout_fd, STDOUT_FILENO);
MoveStdioFdOrExit(&local.stderr_fd, STDERR_FILENO);
}
bool WaitPidNoEintr(pid_t pid, int *status_out) {
for (;;) {
pid_t gotpid = waitpid(pid, status_out, 0);
if (gotpid == pid) {
return true;
}
if (gotpid < 0 && errno == EINTR) {
continue;
}
return false;
}
}
bool LogWaitStatus(const char *label, int status) {
if (WIFSIGNALED(status)) {
Log("%s terminated by signal %d", label, WTERMSIG(status));
return false;
}
if (!WIFEXITED(status)) {
Log("%s ended unexpectedly", label);
return false;
}
if (WEXITSTATUS(status) != EXIT_SUCCESS) {
Log("%s exited with status %d", label, WEXITSTATUS(status));
return false;
}
return true;
}
void KillProcIfRunning(pid_t pid, int signo) {
if (pid == 0) {
return;
}
if (kill(pid, signo) != 0 && errno != ESRCH) {
LogErrno("kill");
}
}