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