]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_utilities/lib/unixchild.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / 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
d64be36e 45#include <sstream>
b1ab9ed8
A
46
47namespace Security {
48namespace UnixPlusPlus {
49
50
51//
52// All our globals are in a ModuleNexus, for that special lazy-init goodness
53//
54ModuleNexus<Child::Children> Child::mChildren;
55
56
57//
58// Make and break Children
59//
60Child::Child()
61 : mState(unborn), mPid(0), mStatus(0)
62{
63}
64
65
66Child::~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//
77void 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//
97void Child::sharedChildren(bool s)
98{
99 StLock<Mutex> _(mChildren());
100 mChildren().shared = s;
101}
102
103bool Child::sharedChildren()
104{
105 StLock<Mutex> _(mChildren());
106 return mChildren().shared;
107}
108
109
110//
111// Check status for one Child
112//
113Child::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//
139void 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//
163void 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//
184void 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//
202void 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//
240void 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//
259int Child::waitStatus() const
260{
261 assert(mState == dead);
262 return mStatus;
263}
264
265bool Child::bySignal() const
266{
267 assert(mState == dead);
268 return WIFSIGNALED(mStatus);
269}
270
271int Child::exitCode() const
272{
273 assert(mState == dead);
274 assert(WIFEXITED(mStatus));
275 return WEXITSTATUS(mStatus);
276}
277
278int Child::exitSignal() const
279{
280 assert(mState == dead);
281 assert(WIFSIGNALED(mStatus));
282 return WTERMSIG(mStatus);
283}
284
285bool 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//
297Child *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//
315void 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//
369bool 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//
412void 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//
466void 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//
487void Child::parentAction()
488{ /* nothing */ }
489
490void Child::dying()
491{ /* nothing */ }
492
493
494//
495// Biers
496//
497void 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