]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2001,2003-2004,2011,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // unixchild - low-level UNIX process child management. | |
27 | // | |
28 | // Note that the map-of-children (mChildren) only holds children presumed to | |
29 | // be alive. Neither unborn nor dead children are included. This is important | |
30 | // for how children are reaped and death notifications dispatched, and should | |
31 | // not be changed without prior deep contemplation. | |
32 | // | |
33 | // A note on locking: | |
34 | // All Child objects in this subsystem are mutated under control of a single | |
35 | // lock (mChildren). This means that children will not step on each other. | |
36 | // However, death callbacks (Child::dying) are made outside the lock's scope | |
37 | // to avoid deadlock scenarios with outside locking hierarchies. When Child::dying | |
38 | // is called, the child has already transitioned to "dead" state and is no longer | |
39 | // in the (live) children map. | |
40 | // | |
41 | #include "unixchild.h" | |
42 | #include <security_utilities/debugging.h> | |
43 | #include <signal.h> | |
44 | ||
45 | ||
46 | namespace Security { | |
47 | namespace UnixPlusPlus { | |
48 | ||
49 | ||
50 | // | |
51 | // All our globals are in a ModuleNexus, for that special lazy-init goodness | |
52 | // | |
53 | ModuleNexus<Child::Children> Child::mChildren; | |
54 | ||
55 | ||
56 | // | |
57 | // Make and break Children | |
58 | // | |
59 | Child::Child() | |
60 | : mState(unborn), mPid(0), mStatus(0) | |
61 | { | |
62 | } | |
63 | ||
64 | ||
65 | Child::~Child() | |
66 | { | |
67 | assert(mState != alive); // not allowed by protocol | |
68 | } | |
69 | ||
70 | ||
71 | // | |
72 | // Take a Child object that is not alive (i.e. is either unborn or dead), | |
73 | // and reset it to unborn, so you can fork() it again. | |
74 | // This call forgets everything about the previous process. | |
75 | // | |
76 | void Child::reset() | |
77 | { | |
78 | switch (mState) { | |
79 | case alive: | |
80 | assert(false); // bad boy; can't do that | |
81 | case unborn: | |
82 | break; // s'okay | |
83 | default: | |
84 | secdebug("unixchild", "%p reset (from state %d)", this, mState); | |
85 | mState = unborn; | |
86 | mPid = 0; | |
87 | mStatus = 0; | |
88 | break; | |
89 | } | |
90 | } | |
91 | ||
92 | ||
93 | // | |
94 | // Global inquiries and setup | |
95 | // | |
96 | void Child::sharedChildren(bool s) | |
97 | { | |
98 | StLock<Mutex> _(mChildren()); | |
99 | mChildren().shared = s; | |
100 | } | |
101 | ||
102 | bool Child::sharedChildren() | |
103 | { | |
104 | StLock<Mutex> _(mChildren()); | |
105 | return mChildren().shared; | |
106 | } | |
107 | ||
108 | ||
109 | // | |
110 | // Check status for one Child | |
111 | // | |
112 | Child::State Child::check() | |
113 | { | |
114 | Child::State state; | |
115 | bool reaped = false; | |
116 | { | |
117 | StLock<Mutex> _(mChildren()); | |
118 | state = mState; | |
119 | switch (mState) { | |
120 | case alive: | |
121 | reaped = checkStatus(WNOHANG); | |
122 | break; | |
123 | default: | |
124 | break; | |
125 | } | |
126 | } | |
127 | if (reaped) | |
128 | this->dying(); | |
129 | return state; | |
130 | } | |
131 | ||
132 | ||
133 | // | |
134 | // Wait for a particular child to be dead. | |
135 | // This call cannot wait for multiple children; you'll have | |
136 | // to program that yourself using whatever event loop you're using. | |
137 | // | |
138 | void Child::wait() | |
139 | { | |
140 | bool reaped = false; | |
141 | { | |
142 | StLock<Mutex> _(mChildren()); | |
143 | switch (mState) { | |
144 | case alive: | |
145 | reaped = checkStatus(0); // wait for it | |
146 | break; | |
147 | case unborn: | |
148 | assert(false); // don't do that | |
149 | default: | |
150 | break; | |
151 | } | |
152 | } | |
153 | if (reaped) | |
154 | this->dying(); | |
155 | } | |
156 | ||
157 | ||
158 | // | |
159 | // Common kill code. | |
160 | // Requires caller to hold mChildren() lock. | |
161 | // | |
162 | void Child::tryKill(int signal) | |
163 | { | |
164 | assert(mState == alive); // ... or don't bother us | |
165 | secdebug("unixchild", "%p (pid %d) sending signal(%d)", this, pid(), signal); | |
166 | if (::kill(pid(), signal)) | |
167 | switch (errno) { | |
168 | case ESRCH: // someone else reaped ths child; or things are just wacky | |
169 | secdebug("unixchild", "%p (pid %d) has disappeared!", this, pid()); | |
170 | mState = invalid; | |
171 | mChildren().erase(pid()); | |
172 | // fall through | |
173 | default: | |
174 | UnixError::throwMe(); | |
175 | } | |
176 | } | |
177 | ||
178 | ||
179 | // | |
180 | // Send a signal to the Child. | |
181 | // This will succeed (and do nothing) if the Child is not alive. | |
182 | // | |
183 | void Child::kill(int signal) | |
184 | { | |
185 | StLock<Mutex> _(mChildren()); | |
186 | if (mState == alive) | |
187 | tryKill(signal); | |
188 | else | |
189 | secdebug("unixchild", "%p (pid %d) not alive; cannot send signal %d", | |
190 | this, pid(), signal); | |
191 | } | |
192 | ||
193 | ||
194 | // | |
195 | // Kill with prejudice. | |
196 | // This will make a serious attempt to *synchronously* kill the process before | |
197 | // returning. If that doesn't work for some reason, abandon the child. | |
198 | // This is one thing you can do in the destructor of your subclass to legally | |
199 | // dispose of your Child's process. | |
200 | // | |
201 | void Child::kill() | |
202 | { | |
203 | // note that we mustn't hold the lock across these calls | |
204 | if (this->state() == alive) { | |
205 | this->kill(SIGTERM); // shoot it once | |
206 | checkChildren(); // check for quick death | |
207 | if (this->state() == alive) { | |
208 | usleep(200000); // give it some time to die | |
209 | if (this->state() == alive) { // could have been reaped by another thread | |
210 | checkChildren(); // check again | |
211 | if (this->state() == alive) { // it... just... won't... die... | |
212 | this->kill(SIGKILL); // take THAT! | |
213 | checkChildren(); | |
214 | if (this->state() == alive) // stuck zombie | |
215 | this->abandon(); // leave the body behind | |
216 | } | |
217 | } | |
218 | } | |
219 | } else | |
220 | secdebug("unixchild", "%p (pid %d) not alive; ignoring request to kill it", this, pid()); | |
221 | } | |
222 | ||
223 | ||
224 | // | |
225 | // Take a living child and cut it loose. This sets its state to abandoned | |
226 | // and removes it from the child registry. | |
227 | // This is one thing you can do in the destructor of your subclass to legally | |
228 | // dispose of your child's process. | |
229 | // | |
230 | void Child::abandon() | |
231 | { | |
232 | StLock<Mutex> _(mChildren()); | |
233 | if (mState == alive) { | |
234 | secdebug("unixchild", "%p (pid %d) abandoned", this, pid()); | |
235 | mState = abandoned; | |
236 | mChildren().erase(pid()); | |
237 | } else { | |
238 | secdebug("unixchild", "%p (pid %d) is not alive; abandon() ignored", | |
239 | this, pid()); | |
240 | } | |
241 | } | |
242 | ||
243 | ||
244 | // | |
245 | // Forensic examination of the Child's cadaver. | |
246 | // Not interlocked because you have to check for state() == dead first, | |
247 | // and these values are const ever after. | |
248 | // | |
249 | int Child::waitStatus() const | |
250 | { | |
251 | assert(mState == dead); | |
252 | return mStatus; | |
253 | } | |
254 | ||
255 | bool Child::bySignal() const | |
256 | { | |
257 | assert(mState == dead); | |
258 | return WIFSIGNALED(mStatus); | |
259 | } | |
260 | ||
261 | int Child::exitCode() const | |
262 | { | |
263 | assert(mState == dead); | |
264 | assert(WIFEXITED(mStatus)); | |
265 | return WEXITSTATUS(mStatus); | |
266 | } | |
267 | ||
268 | int Child::exitSignal() const | |
269 | { | |
270 | assert(mState == dead); | |
271 | assert(WIFSIGNALED(mStatus)); | |
272 | return WTERMSIG(mStatus); | |
273 | } | |
274 | ||
275 | bool Child::coreDumped() const | |
276 | { | |
277 | assert(mState == dead); | |
278 | assert(WIFSIGNALED(mStatus)); | |
279 | return WCOREDUMP(mStatus); | |
280 | } | |
281 | ||
282 | ||
283 | // | |
284 | // Find a child in the child map, by pid | |
285 | // This will only find live children, and return NULL for all others. | |
286 | // | |
287 | Child *Child::findGeneric(pid_t pid) | |
288 | { | |
289 | StLock<Mutex> _(mChildren()); | |
290 | Children::iterator it = mChildren().find(pid); | |
291 | if (it == mChildren().end()) | |
292 | return NULL; | |
293 | else | |
294 | return it->second; | |
295 | } | |
296 | ||
297 | ||
298 | // | |
299 | // Do the actual fork job. | |
300 | // At this layer, the client side does nothing but run childAction(). Any plumbing | |
301 | // or cleanup is up to that function (which runs in the child) and the caller (after | |
302 | // fork() returns). If childAction() returns at all, we will call exit(1) to get | |
303 | // rid of the child. | |
304 | // | |
305 | void Child::fork() | |
306 | { | |
307 | static const unsigned maxDelay = 30; // seconds increment, i.e. 5 retries | |
308 | ||
309 | assert(mState == unborn); | |
310 | for (unsigned delay = 1; ;) { | |
311 | switch (pid_t pid = ::fork()) { | |
312 | case -1: // fork failed | |
313 | switch (errno) { | |
314 | case EINTR: | |
315 | secdebug("unixchild", "%p fork EINTR; retrying", this); | |
316 | continue; // no problem | |
317 | case EAGAIN: | |
318 | if (delay < maxDelay) { | |
319 | secdebug("unixchild", "%p fork EAGAIN; delaying %d seconds", | |
320 | this, delay); | |
321 | sleep(delay); | |
322 | delay *= 2; | |
323 | continue; | |
324 | } | |
325 | // fall through | |
326 | default: | |
327 | UnixError::throwMe(); | |
328 | } | |
329 | assert(false); // unreached | |
330 | ||
331 | case 0: // child | |
332 | //@@@ bother to clean child map? | |
333 | secdebug("unixchild", "%p (child pid %d) running child action", | |
334 | this, getpid()); | |
335 | secdelay("/tmp/delay/unixchild"); | |
336 | try { | |
337 | this->childAction(); | |
338 | secdebug("unixchild", "%p (pid %d) child action returned; exiting", | |
339 | this, getpid()); | |
340 | } catch (...) { | |
341 | secdebug("unixchild", "%p (pid %d) child action had uncaught exception", | |
342 | this, getpid()); | |
343 | } | |
344 | _exit(1); | |
345 | ||
346 | default: // parent | |
347 | { | |
348 | StLock<Mutex> _(mChildren()); | |
349 | mState = alive; | |
350 | mPid = pid; | |
351 | mChildren().insert(make_pair(pid, this)); | |
352 | } | |
353 | secdebug("unixchild", "%p (parent) running parent action", this); | |
354 | this->parentAction(); | |
355 | break; | |
356 | } | |
357 | break; | |
358 | } | |
359 | } | |
360 | ||
361 | ||
362 | // | |
363 | // Check the status of this child by explicitly probing it. | |
364 | // Caller must hold master lock. | |
365 | // | |
366 | bool Child::checkStatus(int options) | |
367 | { | |
368 | assert(state() == alive); | |
369 | secdebug("unixchild", "checking %p (pid %d)", this, this->pid()); | |
370 | int status; | |
371 | again: | |
372 | switch (IFDEBUG(pid_t pid =) ::wait4(this->pid(), &status, options, NULL)) { | |
373 | case pid_t(-1): | |
374 | switch (errno) { | |
375 | case EINTR: | |
376 | goto again; // retry | |
377 | case ECHILD: | |
378 | secdebug("unixchild", "%p (pid=%d) unknown to kernel", this, this->pid()); | |
379 | mState = invalid; | |
380 | mChildren().erase(this->pid()); | |
381 | return false; | |
382 | default: | |
383 | UnixError::throwMe(); | |
384 | } | |
385 | break; // placebo | |
386 | case 0: | |
387 | return false; // child not ready (do nothing) | |
388 | default: | |
389 | assert(pid == this->pid()); | |
390 | bury(status); | |
391 | return true; | |
392 | } | |
393 | } | |
394 | ||
395 | ||
396 | // | |
397 | // Perform an idempotent check for dead children, as per the UNIX wait() system calls. | |
398 | // This can be called at any time, and will reap all children that have died since | |
399 | // last time. The obvious time to call this is after a SIGCHLD has been received; | |
400 | // however signal dispatch is so - uh, interesting - in UNIX that we don't even try | |
401 | // to deal with it at this level. Suffice to say that calling checkChildren directly | |
402 | // from within a signal handler is NOT generally safe due to locking constraints. | |
403 | // | |
404 | // If the shared() flag is on, we explicitly poll each child known to be recently | |
405 | // alive. That is less efficient than reaping any and all, but leaves any children | |
406 | // alone that someone else may have created without our knowledge. The default is | |
407 | // not shared(), which will reap (and discard) any unrelated children without letting | |
408 | // the caller know about it. | |
409 | // | |
410 | void Child::checkChildren() | |
411 | { | |
412 | Bier casualties; | |
413 | { | |
414 | StLock<Mutex> _(mChildren()); | |
415 | if (mChildren().shared) { | |
416 | for (Children::iterator it = mChildren().begin(); it != mChildren().end(); it++) | |
417 | if (it->second->checkStatus(WNOHANG)) | |
418 | casualties.add(it->second); | |
419 | } else if (!mChildren().empty()) { | |
420 | int status; | |
421 | while (pid_t pid = ::wait4(0, &status, WNOHANG, NULL)) { | |
422 | secdebug("unixchild", "universal child check (%ld children known alive)", mChildren().size()); | |
423 | switch (pid) { | |
424 | case pid_t(-1): | |
425 | switch (errno) { | |
426 | case EINTR: | |
427 | secdebug("unixchild", "EINTR on wait4; retrying"); | |
428 | continue; // benign, but retry the wait() | |
429 | case ECHILD: | |
430 | // Should not normally happen (there *is* a child around), | |
431 | // but gets returned anyway if the child is stopped in the debugger. | |
432 | // Treat like a zero return (no children ready to be buried). | |
433 | secdebug("unixchild", "ECHILD with filled nursery (ignored)"); | |
434 | goto no_more; | |
435 | default: | |
436 | UnixError::throwMe(); | |
437 | } | |
438 | break; | |
439 | default: | |
440 | if (Child *child = mChildren()[pid]) { | |
441 | child->bury(status); | |
442 | casualties.add(child); | |
443 | } else | |
444 | secdebug("unixchild", "reaping feral child pid=%d", pid); | |
445 | if (mChildren().empty()) | |
446 | goto no_more; // none left | |
447 | break; | |
448 | } | |
449 | } | |
450 | no_more: ; | |
451 | } else { | |
452 | secdebug("unixchild", "spurious checkChildren (the nursery is empty)"); | |
453 | } | |
454 | } // release master lock | |
455 | casualties.notify(); | |
456 | } | |
457 | ||
458 | ||
459 | // | |
460 | // Perform the canonical last rites for a formerly alive child. | |
461 | // Requires master lock held throughout. | |
462 | // | |
463 | void Child::bury(int status) | |
464 | { | |
465 | assert(mState == alive); | |
466 | mState = dead; | |
467 | mStatus = status; | |
468 | mChildren().erase(mPid); | |
469 | #if !defined(NDEBUG) | |
470 | if (bySignal()) | |
471 | secdebug("unixchild", "%p (pid %d) died by signal %d%s", | |
472 | this, mPid, exitSignal(), | |
473 | coreDumped() ? " and dumped core" : ""); | |
474 | else | |
475 | secdebug("unixchild", "%p (pid %d) died by exit(%d)", | |
476 | this, mPid, exitCode()); | |
477 | #endif //NDEBUG | |
478 | } | |
479 | ||
480 | ||
481 | // | |
482 | // Default hooks | |
483 | // | |
484 | void Child::parentAction() | |
485 | { /* nothing */ } | |
486 | ||
487 | void Child::dying() | |
488 | { /* nothing */ } | |
489 | ||
490 | ||
491 | // | |
492 | // Biers | |
493 | // | |
494 | void Child::Bier::notify() | |
495 | { | |
496 | for (const_iterator it = begin(); it != end(); ++it) | |
497 | (*it)->dying(); | |
498 | } | |
499 | ||
500 | ||
501 | } // end namespace IPPlusPlus | |
502 | } // end namespace Security |