4B1D92010F8BDE7D00125940 /* launchd.ops in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B1D91ED0F8BDE1A00125940 /* launchd.ops */; };
4B287733111A509400C07B35 /* launchd_helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B287732111A509400C07B35 /* launchd_helper.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
4B28781B111A61A400C07B35 /* launchd_helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B287732111A509400C07B35 /* launchd_helper.defs */; };
+ 4B43EAF414101C5800E9E776 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B43EAF314101C5800E9E776 /* ServiceManagement.framework */; };
4B9A1C1F132759F700019C67 /* events.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A30FF131F24AC002DE2E5 /* events.defs */; settings = {ATTRIBUTES = (Server, ); }; };
4B9EDCA20EAFC77E00A78496 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */; };
4BA2F5FD1243063D00C2AADD /* init.defs in Sources */ = {isa = PBXBuildFile; fileRef = 4BA2F5FC1243063D00C2AADD /* init.defs */; };
4B10F1F30F43BF5C00875782 /* launchctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = launchctl; sourceTree = BUILT_PRODUCTS_DIR; };
4B1D91ED0F8BDE1A00125940 /* launchd.ops */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = launchd.ops; path = launchd/src/launchd.ops; sourceTree = "<group>"; };
4B287732111A509400C07B35 /* launchd_helper.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = launchd_helper.defs; path = launchd/src/launchd_helper.defs; sourceTree = "<group>"; };
+ 4B43EAF314101C5800E9E776 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = /System/Library/Frameworks/ServiceManagement.framework; sourceTree = "<absolute>"; };
4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = /System/Library/Frameworks/DiskArbitration.framework; sourceTree = "<absolute>"; };
4BA2F5FC1243063D00C2AADD /* init.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 4; name = init.defs; path = /usr/local/include/xpc/init.defs; sourceTree = SDKROOT; };
7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauditd.dylib; path = /usr/lib/libauditd.dylib; sourceTree = "<absolute>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 4B43EAF414101C5800E9E776 /* ServiceManagement.framework in Frameworks */,
FCC841CC0EA7138700C01666 /* IOKit.framework in Frameworks */,
FC3628080E9345E10054F1A3 /* CoreFoundation.framework in Frameworks */,
FCD713740E95DE49001B0111 /* libedit.dylib in Frameworks */,
FC36280C0E9345F60054F1A3 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 4B43EAF314101C5800E9E776 /* ServiceManagement.framework */,
4B9EDCA10EAFC77E00A78496 /* DiskArbitration.framework */,
FC36292C0E934AA40054F1A3 /* libbsm.dylib */,
7215DE4B0EFAF2EC00ABD81E /* libauditd.dylib */,
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "install -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_login_session.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_user.d\n/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
+ shellScript = "install -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchDaemons\n/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
showEnvVarsInLog = 0;
};
FC7B87B20EA7195F00542082 /* ShellScript */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man\n/bin/mkdir -p \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n";
+ shellScript = "/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man\n/bin/mkdir -p \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/var/db/launchd.db/com.apple.launchd\"\n/bin/mkdir -p \"$DSTROOT/private/etc/mach_init.d\"\n/bin/mkdir -p \"$DSTROOT/private/etc/mach_init_per_user.d\"\n/bin/mkdir -p \"$DSTROOT/private/etc/mach_init_per_login_session.d\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/etc/mach_init.d\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/etc/mach_init_per_user.d\"\n/usr/sbin/chown root:wheel \"$DSTROOT/private/etc/mach_init_per_login_session.d\"";
showEnvVarsInLog = 0;
};
FC7B87EE0EA71A4900542082 /* ShellScript */ = {
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "install -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_login_session.d\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/private/etc/mach_init_per_user.d\n/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
+ shellScript = "install -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchAgents\ninstall -o \"$INSTALL_OWNER\" -g \"$INSTALL_GROUP\" -m 0755 -d \"$DSTROOT\"/Library/LaunchDaemons\n/Developer/Makefiles/bin/compress-man-pages.pl -d \"$DSTROOT\" /usr/share/man";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
-static const char *const __rcs_file_version__ = "$Revision: 24984 $";
+static const char *const __rcs_file_version__ = "$Revision: 25247 $";
#include "config.h"
#include "launchd_core_logic.h"
#include <System/sys/spawn.h>
#include <spawn.h>
#include <time.h>
+#include <libinfo.h>
#include <libproc.h>
#include <malloc/malloc.h>
#if TARGET_OS_EMBEDDED
#include <sys/kern_memorystatus.h>
#else
+extern int gL1CacheEnabled;
/* To make my life easier. */
typedef struct jetsam_priority_entry {
pid_t pid;
#if !TARGET_OS_EMBEDDED
#include "domainServer.h"
#include "init.h"
-#endif
+#endif /* !TARGET_OS_EMBEDDED */
#include "eventsServer.h"
#ifndef POSIX_SPAWN_OSX_TALAPP_START
static struct machservice *machservice_new(job_t j, const char *name, mach_port_t *serviceport, bool pid_local);
#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
static struct machservice *machservice_new_alias(job_t aj, struct machservice *orig);
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
static void machservice_ignore(job_t j, struct machservice *ms);
static void machservice_watch(job_t j, struct machservice *ms);
static void machservice_delete(job_t j, struct machservice *, bool port_died);
static jobmgr_t _s_xpc_system_domain;
static LIST_HEAD(, jobmgr_s) _s_xpc_user_domains;
static LIST_HEAD(, jobmgr_s) _s_xpc_session_domains;
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
#define jobmgr_assumes(jm, e) \
(unlikely(!(e)) ? jobmgr_log_bug(jm, __LINE__), false : true)
static jobmgr_t jobmgr_find_xpc_per_user_domain(jobmgr_t jm, uid_t uid);
static jobmgr_t jobmgr_find_xpc_per_session_domain(jobmgr_t jm, au_asid_t asid);
static job_t xpc_domain_import_service(jobmgr_t jm, launch_data_t pload);
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
static job_t jobmgr_import2(jobmgr_t jm, launch_data_t pload);
static jobmgr_t jobmgr_parent(jobmgr_t jm);
static jobmgr_t jobmgr_do_garbage_collection(jobmgr_t jm);
static job_t job_new(jobmgr_t jm, const char *label, const char *prog, const char *const *argv) __attribute__((malloc, nonnull(1,2), warn_unused_result));
#ifndef __LAUNCH_DISABLE_XPC_SUPPORT__
static job_t job_new_alias(jobmgr_t jm, job_t src);
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
static job_t job_new_via_mach_init(job_t j, const char *cmd, uid_t uid, bool ond) __attribute__((malloc, nonnull, warn_unused_result));
static job_t job_new_subjob(job_t j, uuid_t identifier);
static void job_kill(job_t j);
(void)jobmgr_assumes(jm, kr == KERN_SUCCESS);
}
}
-#endif
+#endif /* !TARGET_OS_EMBEDDED */
if (jm->req_ctx) {
(void)jobmgr_assumes(jm, vm_deallocate(mach_task_self(), jm->req_ctx, jm->req_ctx_sz) == KERN_SUCCESS);
}
if (j->shutdown_monitor) {
_s_shutdown_monitor = NULL;
}
- if (j->workaround9359725) {
- /* We may have forcibly removed this job by simulating an exit. If this
- * is the case, we don't want to hear about these events anymore, lest
- * we get a stale context pointer and crash trying to dereference it.
- */
- kevent_mod((uintptr_t)j->p, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
- }
-
+
kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
-
+
LIST_REMOVE(j, sle);
LIST_REMOVE(j, label_hash_sle);
job_log(j, LOG_DEBUG, "Removed");
+ j->kqjob_callback = (kq_callback)0x8badf00d;
free(j);
}
return j;
}
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
job_t
job_import(launch_data_t pload)
else if (strcasecmp(value, LAUNCH_KEY_POSIXSPAWNTYPE_IOSAPP) == 0) {
j->pstype = POSIX_SPAWN_IOS_APP_START;
}
-#endif
+#endif /* TARGET_OS_EMBEDDED */
else {
job_log(j, LOG_ERR, "Unknown value for key %s: %s", key, value);
}
(void)job_assumes(j, host_reboot(mach_host_self(), HOST_REBOOT_DEBUGGER) == KERN_SUCCESS);
}
+ /* We've simulated the exit, so we have to cancel the kevent for
+ * this job, otherwise we may get a kevent later down the road that
+ * has a stale context pointer (if we've removed the job). Or worse,
+ * it'll corrupt our data structures if the job still exists or the
+ * allocation was recycled.
+ *
+ * If the failing process had a tracer attached to it, we need to
+ * remove out NOTE_EXIT for that tracer too, otherwise the same
+ * thing might happen.
+ *
+ * Note that, if we're not shutting down, this will result in a
+ * zombie process just hanging around forever. But if the process
+ * didn't exit after receiving SIGKILL, odds are it would've just
+ * stuck around forever anyway.
+ *
+ * See <rdar://problem/9481630>.
+ */
+ kevent_mod((uintptr_t)j->p, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+ if (j->tracing_pid) {
+ kevent_mod((uintptr_t)j->tracing_pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+ }
+
struct kevent bogus_exit;
EV_SET(&bogus_exit, j->p, EVFILT_PROC, 0, NOTE_EXIT, 0, 0);
jobmgr_callback(j->mgr, &bogus_exit);
free(pids);
}
+static struct passwd *
+job_getpwnam(job_t j, const char *name)
+{
+ /*
+ * methodology for system daemons
+ *
+ * first lookup user record without any opendirectoryd interaction,
+ * we don't know what interprocess dependencies might be in flight.
+ * if that fails, we re-enable opendirectoryd interaction and
+ * re-issue the lookup. We have to disable the libinfo L1 cache
+ * otherwise libinfo will return the negative cache entry on the retry
+ */
+
+#if !TARGET_OS_EMBEDDED
+ struct passwd *pw = NULL;
+
+ if (pid1_magic && j->mgr == root_jobmgr) {
+ si_search_module_set_flags("ds", 1 /* SEARCH_MODULE_FLAG_DISABLED */);
+ gL1CacheEnabled = false;
+
+ pw = getpwnam(name);
+
+ si_search_module_set_flags("ds", 0);
+ }
+
+ if (pw == NULL) {
+ pw = getpwnam(name);
+ }
+
+ return pw;
+#else
+ return getpwnam(name);
+#endif
+}
+
+static struct group *
+job_getgrnam(job_t j, const char *name)
+{
+#if !TARGET_OS_EMBEDDED
+ struct group *gr = NULL;
+
+ if (pid1_magic && j->mgr == root_jobmgr) {
+ si_search_module_set_flags("ds", 1 /* SEARCH_MODULE_FLAG_DISABLED */);
+ gL1CacheEnabled = false;
+
+ gr = getgrnam(name);
+
+ si_search_module_set_flags("ds", 0);
+ }
+
+ if (gr == NULL) {
+ gr = getgrnam(name);
+ }
+
+ return gr;
+#else
+#pragma unused (j)
+ return getgrnam(name);
+#endif
+}
+
void
job_postfork_test_user(job_t j)
{
goto out_bad;
}
- if ((pwe = getpwnam(user_env_var)) == NULL) {
+ if ((pwe = job_getpwnam(j, user_env_var)) == NULL) {
job_log(j, LOG_ERR, "The account \"%s\" has been deleted out from under us!", user_env_var);
goto out_bad;
}
}
if (j->username) {
- if ((pwe = getpwnam(j->username)) == NULL) {
+ if ((pwe = job_getpwnam(j, j->username)) == NULL) {
job_log(j, LOG_ERR, "getpwnam(\"%s\") failed", j->username);
_exit(EXIT_FAILURE);
}
if (j->groupname) {
struct group *gre;
- if (unlikely((gre = getgrnam(j->groupname)) == NULL)) {
+ if (unlikely((gre = job_getgrnam(j, j->groupname)) == NULL)) {
job_log(j, LOG_ERR, "getgrnam(\"%s\") failed", j->groupname);
_exit(EXIT_FAILURE);
}
return ms;
}
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
bootstrap_status_t
machservice_status(struct machservice *ms)
jobmgr_log(jm, LOG_DEBUG, "No submanagers left.");
} else {
jobmgr_log(jm, LOG_DEBUG, "Still have submanagers.");
+ SLIST_FOREACH(jmi, &jm->submgrs, sle) {
+ jobmgr_log(jm, LOG_DEBUG, "Submanager: %s", jmi->name);
+ }
}
size_t actives = 0;
return jmi;
}
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
job_t
jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag)
kern_return_t
job_mig_get_root_bootstrap(job_t j, mach_port_t *rootbsp)
{
+ if (!j) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
if (inherited_bootstrap_port == MACH_PORT_NULL) {
*rootbsp = root_jobmgr->jm_port;
(void)job_assumes(j, launchd_mport_make_send(root_jobmgr->jm_port) == KERN_SUCCESS);
kern_return_t
job_mig_transaction_count_for_pid(job_t j, pid_t p, int32_t *cnt, boolean_t *condemned)
{
+ if (!j) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
kern_return_t kr = KERN_FAILURE;
struct ldcred *ldc = runtime_get_caller_creds();
if ((ldc->euid != geteuid()) && (ldc->euid != 0)) {
kern_return_t
job_mig_port_for_label(job_t j __attribute__((unused)), name_t label, mach_port_t *mp)
{
+ if (!j) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
struct ldcred *ldc = runtime_get_caller_creds();
kern_return_t kr = BOOTSTRAP_NOT_PRIVILEGED;
kern_return_t
job_mig_set_security_session(job_t j, uuid_t uuid, mach_port_t asport)
{
+ if (!j) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
uuid_string_t uuid_str;
uuid_unparse(uuid, uuid_str);
job_log(j, LOG_DEBUG, "Setting session %u for UUID %s...", asport, uuid_str);
kern_return_t
job_mig_init_session(job_t j, name_t session_type, mach_port_t asport)
{
+ if (!j) {
+ return BOOTSTRAP_NO_MEMORY;
+ }
+
job_t j2;
kern_return_t kr = BOOTSTRAP_NO_MEMORY;
return BOOTSTRAP_NO_MEMORY;
}
+ if (j->mgr->shutting_down) {
+ return BOOTSTRAP_UNKNOWN_SERVICE;
+ }
+
job_log(j, LOG_DEBUG, "Job wants to move to %s session.", session_name);
if (!job_assumes(j, pid1_magic == false)) {
if (!launchd_assumes(j != NULL)) {
return BOOTSTRAP_NO_MEMORY;
}
+ if (j->mgr->shutting_down) {
+ return BOOTSTRAP_UNKNOWN_SERVICE;
+ }
jmr = j->mgr;
job_log(j, LOG_ERR, "XPC domains may only reside in PID 1.");
return BOOTSTRAP_NOT_PRIVILEGED;
}
- if (!MACH_PORT_VALID(reqport)) {
+ if (!j || !MACH_PORT_VALID(reqport)) {
return BOOTSTRAP_UNKNOWN_SERVICE;
}
+ if (root_jobmgr->shutting_down) {
+ jobmgr_log(root_jobmgr, LOG_ERR, "Attempt to create new domain while shutting down.");
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
kern_return_t kr = BOOTSTRAP_NO_MEMORY;
/* All XPC domains are children of the root job manager. What we're creating
(void)strlcpy(name, ms->name, sizeof(event_name_t));
return BOOTSTRAP_SUCCESS;
}
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
kern_return_t
xpc_events_get_channel_name(job_t j __attribute__((unused)), event_name_t stream __attribute__((unused)), uint64_t token __attribute__((unused)), event_name_t name __attribute__((unused)))
msi->event_channel = true;
*p = sp;
- machservice_watch(j, msi);
+ (void)job_dispatch(j, false);
} else {
errno = BOOTSTRAP_NO_MEMORY;
}
kern_return_t
job_mig_event_set_state(job_t j, name_t name, uint64_t token, boolean_t state)
{
- if (!j->event_monitor) {
+ if (!j || !j->event_monitor) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
_s_xpc_system_domain->req_asid = g_audit_session;
_s_xpc_system_domain->req_asport = g_audit_session_port;
_s_xpc_system_domain->shortdesc = "system";
-#endif
+#endif /* __LAUNCH_DISABLE_XPC_SUPPORT__ */
if (pid1_magic) {
root_jobmgr->monitor_shutdown = true;
}