1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker * Copyright 2021 Google LLC
3*bbecb9d1SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*bbecb9d1SAndroid Build Coastguard Worker */
5*bbecb9d1SAndroid Build Coastguard Worker
6*bbecb9d1SAndroid Build Coastguard Worker #include "render_worker.h"
7*bbecb9d1SAndroid Build Coastguard Worker
8*bbecb9d1SAndroid Build Coastguard Worker /* One and only one of ENABLE_RENDER_SERVER_WORKER_* must be set.
9*bbecb9d1SAndroid Build Coastguard Worker *
10*bbecb9d1SAndroid Build Coastguard Worker * With ENABLE_RENDER_SERVER_WORKER_PROCESS, each worker is a subprocess
11*bbecb9d1SAndroid Build Coastguard Worker * forked from the server process.
12*bbecb9d1SAndroid Build Coastguard Worker *
13*bbecb9d1SAndroid Build Coastguard Worker * With ENABLE_RENDER_SERVER_WORKER_THREAD, each worker is a thread of the
14*bbecb9d1SAndroid Build Coastguard Worker * server process.
15*bbecb9d1SAndroid Build Coastguard Worker *
16*bbecb9d1SAndroid Build Coastguard Worker * With ENABLE_RENDER_SERVER_WORKER_MINIJAIL, each worker is a subprocess
17*bbecb9d1SAndroid Build Coastguard Worker * forked from the server process, jailed with minijail.
18*bbecb9d1SAndroid Build Coastguard Worker */
19*bbecb9d1SAndroid Build Coastguard Worker #if (ENABLE_RENDER_SERVER_WORKER_PROCESS + ENABLE_RENDER_SERVER_WORKER_THREAD + \
20*bbecb9d1SAndroid Build Coastguard Worker ENABLE_RENDER_SERVER_WORKER_MINIJAIL) != 1
21*bbecb9d1SAndroid Build Coastguard Worker #error "no worker defined"
22*bbecb9d1SAndroid Build Coastguard Worker #endif
23*bbecb9d1SAndroid Build Coastguard Worker
24*bbecb9d1SAndroid Build Coastguard Worker #include <errno.h>
25*bbecb9d1SAndroid Build Coastguard Worker #include <fcntl.h>
26*bbecb9d1SAndroid Build Coastguard Worker #include <signal.h>
27*bbecb9d1SAndroid Build Coastguard Worker #include <sys/signalfd.h>
28*bbecb9d1SAndroid Build Coastguard Worker #include <sys/types.h>
29*bbecb9d1SAndroid Build Coastguard Worker #include <sys/wait.h>
30*bbecb9d1SAndroid Build Coastguard Worker #include <threads.h>
31*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
32*bbecb9d1SAndroid Build Coastguard Worker
33*bbecb9d1SAndroid Build Coastguard Worker struct minijail;
34*bbecb9d1SAndroid Build Coastguard Worker
35*bbecb9d1SAndroid Build Coastguard Worker struct render_worker_jail {
36*bbecb9d1SAndroid Build Coastguard Worker int max_worker_count;
37*bbecb9d1SAndroid Build Coastguard Worker
38*bbecb9d1SAndroid Build Coastguard Worker int sigchld_fd;
39*bbecb9d1SAndroid Build Coastguard Worker struct minijail *minijail;
40*bbecb9d1SAndroid Build Coastguard Worker
41*bbecb9d1SAndroid Build Coastguard Worker struct list_head workers;
42*bbecb9d1SAndroid Build Coastguard Worker int worker_count;
43*bbecb9d1SAndroid Build Coastguard Worker };
44*bbecb9d1SAndroid Build Coastguard Worker
45*bbecb9d1SAndroid Build Coastguard Worker struct render_worker {
46*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
47*bbecb9d1SAndroid Build Coastguard Worker thrd_t thread;
48*bbecb9d1SAndroid Build Coastguard Worker #else
49*bbecb9d1SAndroid Build Coastguard Worker pid_t pid;
50*bbecb9d1SAndroid Build Coastguard Worker #endif
51*bbecb9d1SAndroid Build Coastguard Worker bool destroyed;
52*bbecb9d1SAndroid Build Coastguard Worker bool reaped;
53*bbecb9d1SAndroid Build Coastguard Worker
54*bbecb9d1SAndroid Build Coastguard Worker struct list_head head;
55*bbecb9d1SAndroid Build Coastguard Worker
56*bbecb9d1SAndroid Build Coastguard Worker char thread_data[];
57*bbecb9d1SAndroid Build Coastguard Worker };
58*bbecb9d1SAndroid Build Coastguard Worker
59*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_MINIJAIL
60*bbecb9d1SAndroid Build Coastguard Worker
61*bbecb9d1SAndroid Build Coastguard Worker #include <fcntl.h>
62*bbecb9d1SAndroid Build Coastguard Worker #include <libminijail.h>
63*bbecb9d1SAndroid Build Coastguard Worker #include <linux/filter.h>
64*bbecb9d1SAndroid Build Coastguard Worker #include <linux/seccomp.h>
65*bbecb9d1SAndroid Build Coastguard Worker #include <stdio.h>
66*bbecb9d1SAndroid Build Coastguard Worker #include <sys/stat.h>
67*bbecb9d1SAndroid Build Coastguard Worker
68*bbecb9d1SAndroid Build Coastguard Worker static bool
load_bpf_program(struct sock_fprog * prog,const char * path)69*bbecb9d1SAndroid Build Coastguard Worker load_bpf_program(struct sock_fprog *prog, const char *path)
70*bbecb9d1SAndroid Build Coastguard Worker {
71*bbecb9d1SAndroid Build Coastguard Worker int fd = -1;
72*bbecb9d1SAndroid Build Coastguard Worker void *data = NULL;
73*bbecb9d1SAndroid Build Coastguard Worker
74*bbecb9d1SAndroid Build Coastguard Worker fd = open(path, O_RDONLY);
75*bbecb9d1SAndroid Build Coastguard Worker if (fd < 0)
76*bbecb9d1SAndroid Build Coastguard Worker goto fail;
77*bbecb9d1SAndroid Build Coastguard Worker
78*bbecb9d1SAndroid Build Coastguard Worker const off_t size = lseek(fd, 0, SEEK_END);
79*bbecb9d1SAndroid Build Coastguard Worker if (size <= 0 || size % sizeof(struct sock_filter))
80*bbecb9d1SAndroid Build Coastguard Worker goto fail;
81*bbecb9d1SAndroid Build Coastguard Worker lseek(fd, 0, SEEK_SET);
82*bbecb9d1SAndroid Build Coastguard Worker
83*bbecb9d1SAndroid Build Coastguard Worker data = malloc(size);
84*bbecb9d1SAndroid Build Coastguard Worker if (!data)
85*bbecb9d1SAndroid Build Coastguard Worker goto fail;
86*bbecb9d1SAndroid Build Coastguard Worker
87*bbecb9d1SAndroid Build Coastguard Worker off_t cur = 0;
88*bbecb9d1SAndroid Build Coastguard Worker while (cur < size) {
89*bbecb9d1SAndroid Build Coastguard Worker const ssize_t r = read(fd, (char *)data + cur, size - cur);
90*bbecb9d1SAndroid Build Coastguard Worker if (r <= 0)
91*bbecb9d1SAndroid Build Coastguard Worker goto fail;
92*bbecb9d1SAndroid Build Coastguard Worker cur += r;
93*bbecb9d1SAndroid Build Coastguard Worker }
94*bbecb9d1SAndroid Build Coastguard Worker
95*bbecb9d1SAndroid Build Coastguard Worker close(fd);
96*bbecb9d1SAndroid Build Coastguard Worker
97*bbecb9d1SAndroid Build Coastguard Worker prog->len = size / sizeof(struct sock_filter);
98*bbecb9d1SAndroid Build Coastguard Worker prog->filter = data;
99*bbecb9d1SAndroid Build Coastguard Worker
100*bbecb9d1SAndroid Build Coastguard Worker return true;
101*bbecb9d1SAndroid Build Coastguard Worker
102*bbecb9d1SAndroid Build Coastguard Worker fail:
103*bbecb9d1SAndroid Build Coastguard Worker if (data)
104*bbecb9d1SAndroid Build Coastguard Worker free(data);
105*bbecb9d1SAndroid Build Coastguard Worker if (fd >= 0)
106*bbecb9d1SAndroid Build Coastguard Worker close(fd);
107*bbecb9d1SAndroid Build Coastguard Worker return false;
108*bbecb9d1SAndroid Build Coastguard Worker }
109*bbecb9d1SAndroid Build Coastguard Worker
110*bbecb9d1SAndroid Build Coastguard Worker static struct minijail *
create_minijail(enum render_worker_jail_seccomp_filter seccomp_filter,const char * seccomp_path)111*bbecb9d1SAndroid Build Coastguard Worker create_minijail(enum render_worker_jail_seccomp_filter seccomp_filter,
112*bbecb9d1SAndroid Build Coastguard Worker const char *seccomp_path)
113*bbecb9d1SAndroid Build Coastguard Worker {
114*bbecb9d1SAndroid Build Coastguard Worker struct minijail *j = minijail_new();
115*bbecb9d1SAndroid Build Coastguard Worker
116*bbecb9d1SAndroid Build Coastguard Worker /* TODO namespaces and many more */
117*bbecb9d1SAndroid Build Coastguard Worker minijail_no_new_privs(j);
118*bbecb9d1SAndroid Build Coastguard Worker
119*bbecb9d1SAndroid Build Coastguard Worker if (seccomp_filter != RENDER_WORKER_JAIL_SECCOMP_NONE) {
120*bbecb9d1SAndroid Build Coastguard Worker if (seccomp_filter == RENDER_WORKER_JAIL_SECCOMP_BPF) {
121*bbecb9d1SAndroid Build Coastguard Worker struct sock_fprog prog;
122*bbecb9d1SAndroid Build Coastguard Worker if (!load_bpf_program(&prog, seccomp_path)) {
123*bbecb9d1SAndroid Build Coastguard Worker minijail_destroy(j);
124*bbecb9d1SAndroid Build Coastguard Worker return NULL;
125*bbecb9d1SAndroid Build Coastguard Worker }
126*bbecb9d1SAndroid Build Coastguard Worker
127*bbecb9d1SAndroid Build Coastguard Worker minijail_set_seccomp_filters(j, &prog);
128*bbecb9d1SAndroid Build Coastguard Worker free(prog.filter);
129*bbecb9d1SAndroid Build Coastguard Worker } else {
130*bbecb9d1SAndroid Build Coastguard Worker if (seccomp_filter == RENDER_WORKER_JAIL_SECCOMP_MINIJAIL_POLICY_LOG)
131*bbecb9d1SAndroid Build Coastguard Worker minijail_log_seccomp_filter_failures(j);
132*bbecb9d1SAndroid Build Coastguard Worker minijail_parse_seccomp_filters(j, seccomp_path);
133*bbecb9d1SAndroid Build Coastguard Worker }
134*bbecb9d1SAndroid Build Coastguard Worker
135*bbecb9d1SAndroid Build Coastguard Worker minijail_use_seccomp_filter(j);
136*bbecb9d1SAndroid Build Coastguard Worker }
137*bbecb9d1SAndroid Build Coastguard Worker
138*bbecb9d1SAndroid Build Coastguard Worker return j;
139*bbecb9d1SAndroid Build Coastguard Worker }
140*bbecb9d1SAndroid Build Coastguard Worker
141*bbecb9d1SAndroid Build Coastguard Worker static pid_t
fork_minijail(const struct minijail * template)142*bbecb9d1SAndroid Build Coastguard Worker fork_minijail(const struct minijail *template)
143*bbecb9d1SAndroid Build Coastguard Worker {
144*bbecb9d1SAndroid Build Coastguard Worker struct minijail *j = minijail_new();
145*bbecb9d1SAndroid Build Coastguard Worker if (!j)
146*bbecb9d1SAndroid Build Coastguard Worker return -1;
147*bbecb9d1SAndroid Build Coastguard Worker
148*bbecb9d1SAndroid Build Coastguard Worker /* is this faster? */
149*bbecb9d1SAndroid Build Coastguard Worker if (minijail_copy_jail(template, j)) {
150*bbecb9d1SAndroid Build Coastguard Worker minijail_destroy(j);
151*bbecb9d1SAndroid Build Coastguard Worker return -1;
152*bbecb9d1SAndroid Build Coastguard Worker }
153*bbecb9d1SAndroid Build Coastguard Worker
154*bbecb9d1SAndroid Build Coastguard Worker pid_t pid = minijail_fork(j);
155*bbecb9d1SAndroid Build Coastguard Worker minijail_destroy(j);
156*bbecb9d1SAndroid Build Coastguard Worker
157*bbecb9d1SAndroid Build Coastguard Worker return pid;
158*bbecb9d1SAndroid Build Coastguard Worker }
159*bbecb9d1SAndroid Build Coastguard Worker
160*bbecb9d1SAndroid Build Coastguard Worker #endif /* ENABLE_RENDER_SERVER_WORKER_MINIJAIL */
161*bbecb9d1SAndroid Build Coastguard Worker
162*bbecb9d1SAndroid Build Coastguard Worker #ifndef ENABLE_RENDER_SERVER_WORKER_THREAD
163*bbecb9d1SAndroid Build Coastguard Worker
164*bbecb9d1SAndroid Build Coastguard Worker static int
create_sigchld_fd(void)165*bbecb9d1SAndroid Build Coastguard Worker create_sigchld_fd(void)
166*bbecb9d1SAndroid Build Coastguard Worker {
167*bbecb9d1SAndroid Build Coastguard Worker const int signum = SIGCHLD;
168*bbecb9d1SAndroid Build Coastguard Worker
169*bbecb9d1SAndroid Build Coastguard Worker sigset_t set;
170*bbecb9d1SAndroid Build Coastguard Worker if (sigemptyset(&set) || sigaddset(&set, signum)) {
171*bbecb9d1SAndroid Build Coastguard Worker render_log("failed to initialize sigset_t");
172*bbecb9d1SAndroid Build Coastguard Worker return -1;
173*bbecb9d1SAndroid Build Coastguard Worker }
174*bbecb9d1SAndroid Build Coastguard Worker
175*bbecb9d1SAndroid Build Coastguard Worker int fd = signalfd(-1, &set, SFD_NONBLOCK | SFD_CLOEXEC);
176*bbecb9d1SAndroid Build Coastguard Worker if (fd < 0) {
177*bbecb9d1SAndroid Build Coastguard Worker render_log("failed to create signalfd");
178*bbecb9d1SAndroid Build Coastguard Worker return -1;
179*bbecb9d1SAndroid Build Coastguard Worker }
180*bbecb9d1SAndroid Build Coastguard Worker
181*bbecb9d1SAndroid Build Coastguard Worker if (sigprocmask(SIG_BLOCK, &set, NULL)) {
182*bbecb9d1SAndroid Build Coastguard Worker render_log("failed to call sigprocmask");
183*bbecb9d1SAndroid Build Coastguard Worker close(fd);
184*bbecb9d1SAndroid Build Coastguard Worker return -1;
185*bbecb9d1SAndroid Build Coastguard Worker }
186*bbecb9d1SAndroid Build Coastguard Worker
187*bbecb9d1SAndroid Build Coastguard Worker return fd;
188*bbecb9d1SAndroid Build Coastguard Worker }
189*bbecb9d1SAndroid Build Coastguard Worker
190*bbecb9d1SAndroid Build Coastguard Worker #endif /* !ENABLE_RENDER_SERVER_WORKER_THREAD */
191*bbecb9d1SAndroid Build Coastguard Worker
192*bbecb9d1SAndroid Build Coastguard Worker static void
render_worker_jail_add_worker(struct render_worker_jail * jail,struct render_worker * worker)193*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_add_worker(struct render_worker_jail *jail,
194*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *worker)
195*bbecb9d1SAndroid Build Coastguard Worker {
196*bbecb9d1SAndroid Build Coastguard Worker list_add(&worker->head, &jail->workers);
197*bbecb9d1SAndroid Build Coastguard Worker jail->worker_count++;
198*bbecb9d1SAndroid Build Coastguard Worker }
199*bbecb9d1SAndroid Build Coastguard Worker
200*bbecb9d1SAndroid Build Coastguard Worker static void
render_worker_jail_remove_worker(struct render_worker_jail * jail,struct render_worker * worker)201*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_remove_worker(struct render_worker_jail *jail,
202*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *worker)
203*bbecb9d1SAndroid Build Coastguard Worker {
204*bbecb9d1SAndroid Build Coastguard Worker list_del(&worker->head);
205*bbecb9d1SAndroid Build Coastguard Worker jail->worker_count--;
206*bbecb9d1SAndroid Build Coastguard Worker
207*bbecb9d1SAndroid Build Coastguard Worker free(worker);
208*bbecb9d1SAndroid Build Coastguard Worker }
209*bbecb9d1SAndroid Build Coastguard Worker
210*bbecb9d1SAndroid Build Coastguard Worker static struct render_worker *
render_worker_jail_reap_any_worker(struct render_worker_jail * jail,bool block)211*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_reap_any_worker(struct render_worker_jail *jail, bool block)
212*bbecb9d1SAndroid Build Coastguard Worker {
213*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
214*bbecb9d1SAndroid Build Coastguard Worker (void)jail;
215*bbecb9d1SAndroid Build Coastguard Worker (void)block;
216*bbecb9d1SAndroid Build Coastguard Worker return NULL;
217*bbecb9d1SAndroid Build Coastguard Worker #else
218*bbecb9d1SAndroid Build Coastguard Worker const int options = WEXITED | (block ? 0 : WNOHANG);
219*bbecb9d1SAndroid Build Coastguard Worker siginfo_t siginfo = { 0 };
220*bbecb9d1SAndroid Build Coastguard Worker const int ret = waitid(P_ALL, 0, &siginfo, options);
221*bbecb9d1SAndroid Build Coastguard Worker const pid_t pid = ret ? 0 : siginfo.si_pid;
222*bbecb9d1SAndroid Build Coastguard Worker if (!pid)
223*bbecb9d1SAndroid Build Coastguard Worker return NULL;
224*bbecb9d1SAndroid Build Coastguard Worker
225*bbecb9d1SAndroid Build Coastguard Worker list_for_each_entry (struct render_worker, worker, &jail->workers, head) {
226*bbecb9d1SAndroid Build Coastguard Worker if (worker->pid == pid) {
227*bbecb9d1SAndroid Build Coastguard Worker worker->reaped = true;
228*bbecb9d1SAndroid Build Coastguard Worker return worker;
229*bbecb9d1SAndroid Build Coastguard Worker }
230*bbecb9d1SAndroid Build Coastguard Worker }
231*bbecb9d1SAndroid Build Coastguard Worker
232*bbecb9d1SAndroid Build Coastguard Worker render_log("unknown child process %d", pid);
233*bbecb9d1SAndroid Build Coastguard Worker return NULL;
234*bbecb9d1SAndroid Build Coastguard Worker #endif
235*bbecb9d1SAndroid Build Coastguard Worker }
236*bbecb9d1SAndroid Build Coastguard Worker
237*bbecb9d1SAndroid Build Coastguard Worker struct render_worker_jail *
render_worker_jail_create(int max_worker_count,enum render_worker_jail_seccomp_filter seccomp_filter,const char * seccomp_path)238*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_create(int max_worker_count,
239*bbecb9d1SAndroid Build Coastguard Worker enum render_worker_jail_seccomp_filter seccomp_filter,
240*bbecb9d1SAndroid Build Coastguard Worker const char *seccomp_path)
241*bbecb9d1SAndroid Build Coastguard Worker {
242*bbecb9d1SAndroid Build Coastguard Worker struct render_worker_jail *jail = calloc(1, sizeof(*jail));
243*bbecb9d1SAndroid Build Coastguard Worker if (!jail)
244*bbecb9d1SAndroid Build Coastguard Worker return NULL;
245*bbecb9d1SAndroid Build Coastguard Worker
246*bbecb9d1SAndroid Build Coastguard Worker jail->max_worker_count = max_worker_count;
247*bbecb9d1SAndroid Build Coastguard Worker jail->sigchld_fd = -1;
248*bbecb9d1SAndroid Build Coastguard Worker list_inithead(&jail->workers);
249*bbecb9d1SAndroid Build Coastguard Worker
250*bbecb9d1SAndroid Build Coastguard Worker #ifndef ENABLE_RENDER_SERVER_WORKER_THREAD
251*bbecb9d1SAndroid Build Coastguard Worker jail->sigchld_fd = create_sigchld_fd();
252*bbecb9d1SAndroid Build Coastguard Worker if (jail->sigchld_fd < 0)
253*bbecb9d1SAndroid Build Coastguard Worker goto fail;
254*bbecb9d1SAndroid Build Coastguard Worker #endif
255*bbecb9d1SAndroid Build Coastguard Worker
256*bbecb9d1SAndroid Build Coastguard Worker #if defined(ENABLE_RENDER_SERVER_WORKER_MINIJAIL)
257*bbecb9d1SAndroid Build Coastguard Worker jail->minijail = create_minijail(seccomp_filter, seccomp_path);
258*bbecb9d1SAndroid Build Coastguard Worker if (!jail->minijail)
259*bbecb9d1SAndroid Build Coastguard Worker goto fail;
260*bbecb9d1SAndroid Build Coastguard Worker #else
261*bbecb9d1SAndroid Build Coastguard Worker /* TODO RENDER_WORKER_JAIL_SECCOMP_BPF */
262*bbecb9d1SAndroid Build Coastguard Worker if (seccomp_filter != RENDER_WORKER_JAIL_SECCOMP_NONE)
263*bbecb9d1SAndroid Build Coastguard Worker goto fail;
264*bbecb9d1SAndroid Build Coastguard Worker (void)seccomp_path;
265*bbecb9d1SAndroid Build Coastguard Worker #endif
266*bbecb9d1SAndroid Build Coastguard Worker
267*bbecb9d1SAndroid Build Coastguard Worker return jail;
268*bbecb9d1SAndroid Build Coastguard Worker
269*bbecb9d1SAndroid Build Coastguard Worker fail:
270*bbecb9d1SAndroid Build Coastguard Worker free(jail);
271*bbecb9d1SAndroid Build Coastguard Worker return NULL;
272*bbecb9d1SAndroid Build Coastguard Worker }
273*bbecb9d1SAndroid Build Coastguard Worker
274*bbecb9d1SAndroid Build Coastguard Worker static void
render_worker_jail_wait_workers(struct render_worker_jail * jail)275*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_wait_workers(struct render_worker_jail *jail)
276*bbecb9d1SAndroid Build Coastguard Worker {
277*bbecb9d1SAndroid Build Coastguard Worker while (jail->worker_count) {
278*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *worker =
279*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_reap_any_worker(jail, true /* block */);
280*bbecb9d1SAndroid Build Coastguard Worker if (worker) {
281*bbecb9d1SAndroid Build Coastguard Worker assert(worker->destroyed && worker->reaped);
282*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_remove_worker(jail, worker);
283*bbecb9d1SAndroid Build Coastguard Worker }
284*bbecb9d1SAndroid Build Coastguard Worker }
285*bbecb9d1SAndroid Build Coastguard Worker }
286*bbecb9d1SAndroid Build Coastguard Worker
287*bbecb9d1SAndroid Build Coastguard Worker void
render_worker_jail_destroy(struct render_worker_jail * jail)288*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_destroy(struct render_worker_jail *jail)
289*bbecb9d1SAndroid Build Coastguard Worker {
290*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_wait_workers(jail);
291*bbecb9d1SAndroid Build Coastguard Worker
292*bbecb9d1SAndroid Build Coastguard Worker #if defined(ENABLE_RENDER_SERVER_WORKER_MINIJAIL)
293*bbecb9d1SAndroid Build Coastguard Worker minijail_destroy(jail->minijail);
294*bbecb9d1SAndroid Build Coastguard Worker #endif
295*bbecb9d1SAndroid Build Coastguard Worker
296*bbecb9d1SAndroid Build Coastguard Worker if (jail->sigchld_fd >= 0)
297*bbecb9d1SAndroid Build Coastguard Worker close(jail->sigchld_fd);
298*bbecb9d1SAndroid Build Coastguard Worker
299*bbecb9d1SAndroid Build Coastguard Worker free(jail);
300*bbecb9d1SAndroid Build Coastguard Worker }
301*bbecb9d1SAndroid Build Coastguard Worker
302*bbecb9d1SAndroid Build Coastguard Worker int
render_worker_jail_get_sigchld_fd(const struct render_worker_jail * jail)303*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_get_sigchld_fd(const struct render_worker_jail *jail)
304*bbecb9d1SAndroid Build Coastguard Worker {
305*bbecb9d1SAndroid Build Coastguard Worker return jail->sigchld_fd;
306*bbecb9d1SAndroid Build Coastguard Worker }
307*bbecb9d1SAndroid Build Coastguard Worker
308*bbecb9d1SAndroid Build Coastguard Worker static bool
render_worker_jail_drain_sigchld_fd(struct render_worker_jail * jail)309*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_drain_sigchld_fd(struct render_worker_jail *jail)
310*bbecb9d1SAndroid Build Coastguard Worker {
311*bbecb9d1SAndroid Build Coastguard Worker if (jail->sigchld_fd < 0)
312*bbecb9d1SAndroid Build Coastguard Worker return true;
313*bbecb9d1SAndroid Build Coastguard Worker
314*bbecb9d1SAndroid Build Coastguard Worker do {
315*bbecb9d1SAndroid Build Coastguard Worker struct signalfd_siginfo siginfos[8];
316*bbecb9d1SAndroid Build Coastguard Worker const ssize_t r = read(jail->sigchld_fd, siginfos, sizeof(siginfos));
317*bbecb9d1SAndroid Build Coastguard Worker if (r == sizeof(siginfos))
318*bbecb9d1SAndroid Build Coastguard Worker continue;
319*bbecb9d1SAndroid Build Coastguard Worker if (r > 0 || (r < 0 && errno == EAGAIN))
320*bbecb9d1SAndroid Build Coastguard Worker break;
321*bbecb9d1SAndroid Build Coastguard Worker
322*bbecb9d1SAndroid Build Coastguard Worker render_log("failed to read signalfd");
323*bbecb9d1SAndroid Build Coastguard Worker return false;
324*bbecb9d1SAndroid Build Coastguard Worker } while (true);
325*bbecb9d1SAndroid Build Coastguard Worker
326*bbecb9d1SAndroid Build Coastguard Worker return true;
327*bbecb9d1SAndroid Build Coastguard Worker }
328*bbecb9d1SAndroid Build Coastguard Worker
329*bbecb9d1SAndroid Build Coastguard Worker bool
render_worker_jail_reap_workers(struct render_worker_jail * jail)330*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_reap_workers(struct render_worker_jail *jail)
331*bbecb9d1SAndroid Build Coastguard Worker {
332*bbecb9d1SAndroid Build Coastguard Worker if (!render_worker_jail_drain_sigchld_fd(jail))
333*bbecb9d1SAndroid Build Coastguard Worker return false;
334*bbecb9d1SAndroid Build Coastguard Worker
335*bbecb9d1SAndroid Build Coastguard Worker do {
336*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *worker =
337*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_reap_any_worker(jail, false /* block */);
338*bbecb9d1SAndroid Build Coastguard Worker if (!worker)
339*bbecb9d1SAndroid Build Coastguard Worker break;
340*bbecb9d1SAndroid Build Coastguard Worker
341*bbecb9d1SAndroid Build Coastguard Worker assert(worker->reaped);
342*bbecb9d1SAndroid Build Coastguard Worker if (worker->destroyed)
343*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_remove_worker(jail, worker);
344*bbecb9d1SAndroid Build Coastguard Worker } while (true);
345*bbecb9d1SAndroid Build Coastguard Worker
346*bbecb9d1SAndroid Build Coastguard Worker return true;
347*bbecb9d1SAndroid Build Coastguard Worker }
348*bbecb9d1SAndroid Build Coastguard Worker
349*bbecb9d1SAndroid Build Coastguard Worker void
render_worker_jail_detach_workers(struct render_worker_jail * jail)350*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_detach_workers(struct render_worker_jail *jail)
351*bbecb9d1SAndroid Build Coastguard Worker {
352*bbecb9d1SAndroid Build Coastguard Worker /* free workers without killing nor reaping */
353*bbecb9d1SAndroid Build Coastguard Worker list_for_each_entry_safe (struct render_worker, worker, &jail->workers, head)
354*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_remove_worker(jail, worker);
355*bbecb9d1SAndroid Build Coastguard Worker }
356*bbecb9d1SAndroid Build Coastguard Worker
357*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *
render_worker_create(struct render_worker_jail * jail,int (* thread_func)(void * thread_data),void * thread_data,size_t thread_data_size)358*bbecb9d1SAndroid Build Coastguard Worker render_worker_create(struct render_worker_jail *jail,
359*bbecb9d1SAndroid Build Coastguard Worker int (*thread_func)(void *thread_data),
360*bbecb9d1SAndroid Build Coastguard Worker void *thread_data,
361*bbecb9d1SAndroid Build Coastguard Worker size_t thread_data_size)
362*bbecb9d1SAndroid Build Coastguard Worker {
363*bbecb9d1SAndroid Build Coastguard Worker if (jail->worker_count >= jail->max_worker_count) {
364*bbecb9d1SAndroid Build Coastguard Worker render_log("too many workers");
365*bbecb9d1SAndroid Build Coastguard Worker return NULL;
366*bbecb9d1SAndroid Build Coastguard Worker }
367*bbecb9d1SAndroid Build Coastguard Worker
368*bbecb9d1SAndroid Build Coastguard Worker struct render_worker *worker = calloc(1, sizeof(*worker) + thread_data_size);
369*bbecb9d1SAndroid Build Coastguard Worker if (!worker)
370*bbecb9d1SAndroid Build Coastguard Worker return NULL;
371*bbecb9d1SAndroid Build Coastguard Worker
372*bbecb9d1SAndroid Build Coastguard Worker memcpy(worker->thread_data, thread_data, thread_data_size);
373*bbecb9d1SAndroid Build Coastguard Worker
374*bbecb9d1SAndroid Build Coastguard Worker bool ok;
375*bbecb9d1SAndroid Build Coastguard Worker #if defined(ENABLE_RENDER_SERVER_WORKER_PROCESS)
376*bbecb9d1SAndroid Build Coastguard Worker worker->pid = fork();
377*bbecb9d1SAndroid Build Coastguard Worker ok = worker->pid >= 0;
378*bbecb9d1SAndroid Build Coastguard Worker (void)thread_func;
379*bbecb9d1SAndroid Build Coastguard Worker #elif defined(ENABLE_RENDER_SERVER_WORKER_THREAD)
380*bbecb9d1SAndroid Build Coastguard Worker ok = thrd_create(&worker->thread, thread_func, worker->thread_data) == thrd_success;
381*bbecb9d1SAndroid Build Coastguard Worker #elif defined(ENABLE_RENDER_SERVER_WORKER_MINIJAIL)
382*bbecb9d1SAndroid Build Coastguard Worker worker->pid = fork_minijail(jail->minijail);
383*bbecb9d1SAndroid Build Coastguard Worker ok = worker->pid >= 0;
384*bbecb9d1SAndroid Build Coastguard Worker (void)thread_func;
385*bbecb9d1SAndroid Build Coastguard Worker #endif
386*bbecb9d1SAndroid Build Coastguard Worker if (!ok) {
387*bbecb9d1SAndroid Build Coastguard Worker free(worker);
388*bbecb9d1SAndroid Build Coastguard Worker return NULL;
389*bbecb9d1SAndroid Build Coastguard Worker }
390*bbecb9d1SAndroid Build Coastguard Worker
391*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_add_worker(jail, worker);
392*bbecb9d1SAndroid Build Coastguard Worker
393*bbecb9d1SAndroid Build Coastguard Worker return worker;
394*bbecb9d1SAndroid Build Coastguard Worker }
395*bbecb9d1SAndroid Build Coastguard Worker
396*bbecb9d1SAndroid Build Coastguard Worker void
render_worker_destroy(struct render_worker_jail * jail,struct render_worker * worker)397*bbecb9d1SAndroid Build Coastguard Worker render_worker_destroy(struct render_worker_jail *jail, struct render_worker *worker)
398*bbecb9d1SAndroid Build Coastguard Worker {
399*bbecb9d1SAndroid Build Coastguard Worker assert(render_worker_is_record(worker));
400*bbecb9d1SAndroid Build Coastguard Worker
401*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
402*bbecb9d1SAndroid Build Coastguard Worker /* we trust the thread to clean up and exit in finite time */
403*bbecb9d1SAndroid Build Coastguard Worker thrd_join(worker->thread, NULL);
404*bbecb9d1SAndroid Build Coastguard Worker worker->reaped = true;
405*bbecb9d1SAndroid Build Coastguard Worker #else
406*bbecb9d1SAndroid Build Coastguard Worker /* kill to make sure the worker exits in finite time */
407*bbecb9d1SAndroid Build Coastguard Worker if (!worker->reaped)
408*bbecb9d1SAndroid Build Coastguard Worker kill(worker->pid, SIGKILL);
409*bbecb9d1SAndroid Build Coastguard Worker #endif
410*bbecb9d1SAndroid Build Coastguard Worker
411*bbecb9d1SAndroid Build Coastguard Worker worker->destroyed = true;
412*bbecb9d1SAndroid Build Coastguard Worker
413*bbecb9d1SAndroid Build Coastguard Worker if (worker->reaped)
414*bbecb9d1SAndroid Build Coastguard Worker render_worker_jail_remove_worker(jail, worker);
415*bbecb9d1SAndroid Build Coastguard Worker }
416*bbecb9d1SAndroid Build Coastguard Worker
417*bbecb9d1SAndroid Build Coastguard Worker bool
render_worker_is_record(const struct render_worker * worker)418*bbecb9d1SAndroid Build Coastguard Worker render_worker_is_record(const struct render_worker *worker)
419*bbecb9d1SAndroid Build Coastguard Worker {
420*bbecb9d1SAndroid Build Coastguard Worker /* return false if called from the worker itself */
421*bbecb9d1SAndroid Build Coastguard Worker #ifdef ENABLE_RENDER_SERVER_WORKER_THREAD
422*bbecb9d1SAndroid Build Coastguard Worker return !thrd_equal(worker->thread, thrd_current());
423*bbecb9d1SAndroid Build Coastguard Worker #else
424*bbecb9d1SAndroid Build Coastguard Worker return worker->pid > 0;
425*bbecb9d1SAndroid Build Coastguard Worker #endif
426*bbecb9d1SAndroid Build Coastguard Worker }
427