]>
git.saurik.com Git - apple/securityd.git/blob - src/child.cpp
27b9debf25e2014e1978251b35cb33d8ae37b585
2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 // child - track a single child process and its belongings
32 #include <security_utilities/debugging.h>
36 ucsp_server_handleSignal(mach_port_t sport
,
37 mach_port_t task_port
,
41 if (task_port
!= mach_task_self()) {
42 Syslog::error("handleSignal: recieved from someone other than myself");
44 ChildManager::childManager
.handleSignal(signal_number
);
47 mach_port_deallocate(mach_task_self(), task_port
);
53 ucsp_server_registerChild(mach_port_t sport
,
55 mach_port_t task_port
)
57 mach_port_t childPort
= rport
;
60 kern_return_t kt
= pid_for_task(task_port
, &pid
);
62 Syslog::error("registerChild: pid_for_task returned: %d", kt
);
64 ChildManager::childManager
.registerChild(pid
, childPort
);
69 // Dealloc the childPort unless registerChild set it to zero, which indicates it took over ownership.
70 mach_port_deallocate(mach_task_self(), childPort
);
74 mach_port_deallocate(mach_task_self(), task_port
);
81 // A Child object represents a UNIX process that was forked by us
82 // and may have some state associated with it.
83 // Although some children may be created per session (such as SecurityAgent instances)
84 // in general child processes are PerGlobal.
92 void waitStatus(int status
);
93 int waitStatus() const { return mStatus
; }
95 void childPort(mach_port_t
&childPort
);
97 // Return our childPort and transfer ownership of it.
98 mach_port_t
childPort() { mach_port_t childPort
= mChildPort
; mChildPort
= 0; return childPort
; }
103 // Wait for the child to register or die. If it registered mChildPort will be non zero, it will be 0 if it didn't.
104 void waitForRegister();
111 // Service port for this child.
112 // This should only be nonzero while this object owns the port. Once it is retrieved ownership is handed off.
113 mach_port_t mChildPort
;
115 int mStatus
; // Exit status if child died.
122 // Construct a Child object.
124 Child::Child(pid_t pid
) :
125 mLock(mLockInternal
), mPid(pid
), mChildPort(0), mStatus(0), mInMap(false)
134 // Dealloc our mChildPort someone else took over ownership.
135 mach_port_deallocate(mach_task_self(), mChildPort
);
141 Child::eraseFromMap()
144 ChildManager::childManager
.eraseChild(mPid
);
150 ChildManager::childManager
.insertChild(mPid
, this);
155 Child::waitStatus(int status
)
158 mLock
.unlock(); // Unlock the lock to unblock waitForRegister()
162 Child::childPort(mach_port_t
&childPort
)
164 mChildPort
= childPort
;
165 childPort
= 0; // Tell our caller that we consumed the child port.
167 mLock
.unlock(); // Unlock the lock to unblock waitForRegister()
171 Child::waitForRegister()
173 // Try to lock the lock again (this won't succeed until we get a register or wait result).
175 // Unlock as soon as we get the lock.
181 // ChildManager - Singleton Child Manager class
184 // The signleton ChildManager.
185 ChildManager
ChildManager::childManager
;
187 ChildManager::ChildManager()
191 ChildManager::~ChildManager()
196 ChildManager::forkChild(mach_port_t
&outChildPort
, int &outWaitStatus
)
198 StLock
<Mutex
> lock(mLock
, false);
201 /* Retry fork 10 times on failure after that just give up. */
202 for (int tries
= 0; tries
< 10; ++tries
)
204 lock
.lock(); // aquire the lock
206 if (pid
!= pid_t(-1))
209 /* Something went wrong. */
210 lock
.unlock(); // Release the lock so we aren't holding it during the usleep below.
216 if (err
== EAGAIN
|| err
== ENOMEM
)
219 UnixError::throwMe(err
);
224 // Child - return true.
230 child
.insertInMap(); // Insert child into the map.
231 lock
.unlock(); // Unlock as soon as we are done accessing mChildMap.
233 child
.waitForRegister();
235 // Remove child from the map.
236 child
.eraseFromMap();
238 // Transfer ownership of child's childPort to our caller.
239 outChildPort
= child
.childPort();
242 outWaitStatus
= child
.waitStatus();
244 // Parent - return false
250 ChildManager::handleSignal(int signal_number
)
252 if (signal_number
== SIGCHLD
)
257 ChildManager::registerChild(pid_t pid
, mach_port_t
&childPort
)
259 StLock
<Mutex
> _(mLock
);
260 Child
*child
= findChild(pid
);
262 child
->childPort(childPort
);
265 // Assumes mLock is not locked.
267 ChildManager::eraseChild(pid_t pid
)
269 StLock
<Mutex
> _(mLock
);
270 mChildMap
.erase(pid
);
273 // Assumes mLock is already locked.
275 ChildManager::insertChild(pid_t pid
, Child
*child
)
277 mChildMap
[pid
] = child
;
286 ChildManager::findChild(pid_t pid
)
288 ChildMap::iterator it
= mChildMap
.find(pid
);
289 if (it
== mChildMap
.end())
296 ChildManager::handleSigChild()
298 for (int tries
= 0; tries
< 10; ++tries
)
301 pid_t pid
= waitpid(-1, &status
, WNOHANG
|WUNTRACED
);
306 Syslog::notice("Spurious SIGCHLD ignored");
314 Syslog::notice("Spurious SIGCHLD ignored");
320 Syslog::error("waitpid after SIGCHLD failed: %s", strerror(err
));
325 if (WIFEXITED(status
) || WIFSIGNALED(status
))
327 if (WIFEXITED(status
))
328 secdebug("child", "child with pid: %d exited: %d", pid
, WEXITSTATUS(status
));
329 else if (WCOREDUMP(status
))
330 secdebug("child", "child with pid: %d terminated by signal: %d and dumped core", pid
, WTERMSIG(status
));
332 secdebug("child", "child with pid: %d terminated by signal: %d", pid
, WTERMSIG(status
));
334 waitStatusForPid(pid
, status
);
336 else if (WSTOPSIG(status
))
338 secdebug("child", "child with pid: %d stopped by signal: %d", pid
, WSTOPSIG(status
));
342 Syslog::error("child with pid: %d bogus waitpid status: %d", pid
, status
);
351 ChildManager::waitStatusForPid(pid_t pid
, int status
)
353 StLock
<Mutex
> _(mLock
);
354 Child
*child
= findChild(pid
);
356 child
->waitStatus(status
);