]> git.saurik.com Git - apple/security.git/blame - OSX/include/security_utilities/unixchild.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / include / security_utilities / unixchild.cpp
CommitLineData
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
46namespace Security {
47namespace UnixPlusPlus {
48
49
50//
51// All our globals are in a ModuleNexus, for that special lazy-init goodness
52//
53ModuleNexus<Child::Children> Child::mChildren;
54
55
56//
57// Make and break Children
58//
59Child::Child()
60 : mState(unborn), mPid(0), mStatus(0)
61{
62}
63
64
65Child::~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//
76void 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//
96void Child::sharedChildren(bool s)
97{
98 StLock<Mutex> _(mChildren());
99 mChildren().shared = s;
100}
101
102bool Child::sharedChildren()
103{
104 StLock<Mutex> _(mChildren());
105 return mChildren().shared;
106}
107
108
109//
110// Check status for one Child
111//
112Child::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//
138void 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//
162void 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//
183void 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//
201void 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//
230void 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//
249int Child::waitStatus() const
250{
251 assert(mState == dead);
252 return mStatus;
253}
254
255bool Child::bySignal() const
256{
257 assert(mState == dead);
258 return WIFSIGNALED(mStatus);
259}
260
261int Child::exitCode() const
262{
263 assert(mState == dead);
264 assert(WIFEXITED(mStatus));
265 return WEXITSTATUS(mStatus);
266}
267
268int Child::exitSignal() const
269{
270 assert(mState == dead);
271 assert(WIFSIGNALED(mStatus));
272 return WTERMSIG(mStatus);
273}
274
275bool 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//
287Child *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//
305void 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//
366bool 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//
410void 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//
463void 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//
484void Child::parentAction()
485{ /* nothing */ }
486
487void Child::dying()
488{ /* nothing */ }
489
490
491//
492// Biers
493//
494void 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