[launchd-changes] [23750] trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Nov 6 15:52:32 PST 2008


Revision: 23750
          http://trac.macosforge.org/projects/launchd/changeset/23750
Author:   dsorresso at apple.com
Date:     2008-11-06 15:52:32 -0800 (Thu, 06 Nov 2008)
Log Message:
-----------
<rdar://problem/4459789> Launchd does not bounds check StartCalendarInterval parameters ("input validation")
<rdar://problem/5279345> Background agents in home directory
<rdar://problem/5713335> launchd should query Seatbelt at Mach service lookup time (patch attached)
<rdar://problem/5768680> BTMM: kdcmond doesn't launch on demand when AFP is enabled
<rdar://problem/5952607> launchd is deaf to MIG requests while running 'sample'
<rdar://problem/6003804> 1/3rd fewer threads
<rdar://problem/6335516> build failures when including vproc_priv.h before vproc.h
<rdar://problem/6341358> launchctl never exits after unloading the slapd plist causing server hang
<rdar://problem/6349916> 10A208: launchctl limit core unlimited complains about maxfiles!?

Modified Paths:
--------------
    trunk/launchd/src/launchctl.c
    trunk/launchd/src/launchd.c
    trunk/launchd/src/launchd_core_logic.c
    trunk/launchd/src/launchd_core_logic.h
    trunk/launchd/src/vproc_priv.h

Removed Paths:
-------------
    trunk/Makefile

Deleted: trunk/Makefile
===================================================================
--- trunk/Makefile	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/Makefile	2008-11-06 23:52:32 UTC (rev 23750)
@@ -1,36 +0,0 @@
-ifndef SDKROOT
-export SDKROOT = /
-endif
-
-Project	= launchd
-Extra_Configure_Flags = --sbindir=/sbin --bindir=/bin --sysconfdir=/private/etc
-GnuAfterInstall = launchd_after_install
-include $(MAKEFILEPATH)/CoreOS/ReleaseControl/GNUSource.make
-Install_Flags = DESTDIR=$(DSTROOT)
-
-ifeq ($(shell tconf --test TARGET_OS_EMBEDDED),YES)
-Extra_Configure_Flags += --host=none-apple-darwin
-endif
-
-launchd_after_install::
-ifeq ($(RC_ProjectName),launchd_libs)
-	-find -d $(DSTROOT) -type f | grep -v /usr/local/lib/system | xargs rm
-	-find -d $(DSTROOT) -type l | grep -v /usr/local/lib/system | xargs rm
-	-find -d $(DSTROOT) -type d | grep -v /usr/local/lib/system | xargs rmdir
-else
-ifeq ($(shell tconf --test TARGET_OS_EMBEDDED),NO)
-	mkdir -p $(DSTROOT)/Library/StartupItems
-	chmod 755 $(DSTROOT)/Library/StartupItems
-	mkdir -p $(DSTROOT)/System/Library/StartupItems
-	chmod 755 $(DSTROOT)/System/Library/StartupItems
-endif
-	rm -rf $(DSTROOT)/usr/local/lib/system
-	cp $(OBJROOT)/src/launchd $(SYMROOT)
-	cp $(OBJROOT)/src/launchctl $(SYMROOT)
-	cp $(OBJROOT)/src/launchproxy $(SYMROOT)
-	-dsymutil $(SYMROOT)/launchd
-	-dsymutil $(SYMROOT)/launchctl
-	-dsymutil $(SYMROOT)/launchproxy
-endif
-
-launchd_libs:: install

Modified: trunk/launchd/src/launchctl.c
===================================================================
--- trunk/launchd/src/launchctl.c	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/launchd/src/launchctl.c	2008-11-06 23:52:32 UTC (rev 23750)
@@ -1633,9 +1633,12 @@
 	if (strcasecmp(session_type, "System") == 0) {
 		system_specific_bootstrap(sflag);
 	} else {
-		char *load_launchd_items[] = { "load", "-S", session_type, "-D", "all", NULL, NULL, NULL, NULL };
+		char *load_launchd_items[] = { "load", "-S", session_type, "-D", "all", NULL, NULL, NULL, NULL, NULL, NULL };
 		int the_argc = 5;
 
+		char *load_launchd_items_user[] = { "load", "-S", session_type, "-D", "user", NULL };
+		int the_argc_user = 0;
+		
 		if (is_safeboot()) {
 			load_launchd_items[4] = "system";
 		}
@@ -1650,6 +1653,17 @@
 			if (strcasecmp(session_type, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
 				load_launchd_items[the_argc] = "/etc/mach_init_per_login_session.d";
 				the_argc += 1;
+			} else {
+				/* If we're a per-user launchd initializing our Background session,
+				 * don't forget about the user's launchd jobs that may be specified as
+				 * LimitLoadToSessionType = Background. <rdar://problem/5279345> We also
+				 * must keep in mind that we need to load the user jobs last, since the
+				 * jobs in the local sessions may be responsible for mounting the home
+				 * directory.
+				 */
+				if( getppid() != 1 ) {
+					the_argc_user = 5;
+				}
 			}
 		} else if (strcasecmp(session_type, VPROCMGR_SESSION_AQUA) == 0) {
 			load_launchd_items[5] = "/etc/mach_init_per_user.d";
@@ -1663,7 +1677,21 @@
 #endif
 		}
 
-		return load_and_unload_cmd(the_argc, load_launchd_items);
+		int retval = load_and_unload_cmd(the_argc, load_launchd_items);
+		if( retval == 0 && the_argc_user != 0 ) {
+			optind = 1;
+			/* Load user jobs. But first, we tell launchd to resume listening to
+			 * other clients, since this operation could potentially block if the user's
+			 * home directory is on a network volume or something.
+			 */
+			int64_t junk = 0;
+			vproc_err_t err = vproc_swap_integer(NULL, VPROC_GSK_WEIRD_BOOTSTRAP, &junk, NULL);
+			if( !err ) {
+				retval = load_and_unload_cmd(the_argc_user, load_launchd_items_user);
+			}
+		}
+		
+		return retval;
 	}
 
 	return 0;
@@ -2353,19 +2381,21 @@
 	lmts[which].rlim_max = hlim;
 
 	bool maxfiles_exceeded = false;
-	if( argc > 2 ) {
-		maxfiles_exceeded = ( strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0 );
+	if( strncmp(argv[1], "maxfiles", sizeof("maxfiles")) == 0 ) {
+		if( argc > 2 ) {
+			maxfiles_exceeded = ( strncmp(argv[2], "unlimited", sizeof("unlimited")) == 0 );
+		}
+		
+		if( argc > 3 ) {
+			maxfiles_exceeded = ( maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0 );
+		}
+		
+		if( maxfiles_exceeded ) {
+			fprintf(stderr, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both.\n");
+			return 1;
+		}
 	}
 	
-	if( argc > 3 ) {
-		maxfiles_exceeded = ( maxfiles_exceeded || strncmp(argv[3], "unlimited", sizeof("unlimited")) == 0 );
-	}
-	
-	if( maxfiles_exceeded ) {
-		fprintf(stderr, "Neither the hard nor soft limit for \"maxfiles\" can be unlimited. Please use a numeric parameter for both.\n");
-		return 1;
-	}
-	
 	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
 	tmp = launch_data_new_opaque(lmts, lsz);
 	launch_data_dict_insert(msg, tmp, LAUNCH_KEY_SETRESOURCELIMITS);

Modified: trunk/launchd/src/launchd.c
===================================================================
--- trunk/launchd/src/launchd.c	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/launchd/src/launchd.c	2008-11-06 23:52:32 UTC (rev 23750)
@@ -156,12 +156,12 @@
 		} else {
 			if( !launchd_assumes((g_console = fopen(_PATH_CONSOLE, "w")) != NULL) ) {
 				g_console = stdout;
-			} else {
-				_fd(fileno(g_console));
 			}
 			
 			_fd(fileno(g_console));
 		}
+	} else {
+		g_console = stdout;
 	}
 
 	if (NULL == getenv("PATH")) {
@@ -330,8 +330,8 @@
 
 	now = runtime_get_wall_time();
 
-	char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination";
-	runtime_syslog(LOG_NOTICE, "%s began at: %lld.%06llu", term_who, now / USEC_PER_SEC, now % USEC_PER_SEC);
+	char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for ";
+	runtime_syslog(LOG_NOTICE, "%s%s began at: %lld.%06llu", term_who, pid1_magic ? "" : g_username, now / USEC_PER_SEC, now % USEC_PER_SEC);
 
 	launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
 }

Modified: trunk/launchd/src/launchd_core_logic.c
===================================================================
--- trunk/launchd/src/launchd_core_logic.c	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/launchd/src/launchd_core_logic.c	2008-11-06 23:52:32 UTC (rev 23750)
@@ -75,6 +75,7 @@
 #include <glob.h>
 #include <spawn.h>
 #if HAVE_SANDBOX
+#define __APPLE_API_PRIVATE
 #include <sandbox.h>
 #endif
 #if HAVE_QUARANTINE
@@ -333,6 +334,7 @@
 static void jobmgr_dequeue_next_sample(jobmgr_t jm);
 static job_t jobmgr_init_session(jobmgr_t jm, const char *session_type, bool sflag);
 static job_t jobmgr_find_by_pid(jobmgr_t jm, pid_t p, bool create_anon);
+static jobmgr_t jobmgr_find_by_name(jobmgr_t jm, const char *where);
 static job_t job_mig_intran2(jobmgr_t jm, mach_port_t mport, pid_t upid);
 static void job_export_all2(jobmgr_t jm, launch_data_t where);
 INTERNAL_ABI static void jobmgr_callback(void *obj, struct kevent *kev);
@@ -353,6 +355,7 @@
 	LIST_ENTRY(job_s) label_hash_sle;
 	LIST_ENTRY(job_s) global_env_sle;
 	LIST_ENTRY(job_s) pending_samples_sle;
+	SLIST_ENTRY(job_s) curious_jobs_sle;
 	SLIST_HEAD(, socketgroup) sockets;
 	SLIST_HEAD(, calendarinterval) cal_intervals;
 	SLIST_HEAD(, envitem) global_env;
@@ -454,7 +457,9 @@
 	     	kill_via_shmem				:1,	/* man launchd.plist --> EnableTransactions */
 	     	sent_kill_via_shmem			:1,	/* We need to 'kill_via_shmem' once-and-only-once */
 			pending_sample				:1, /* This job needs to be sampled for some reason. */
-			kill_after_sample			:1; /* The job is to be killed after sampling. */
+			kill_after_sample			:1, /* The job is to be killed after sampling. */
+			reap_after_sample			:1,	/* The job exited before sample did, so we should reap it after sample is done. */
+			nosy						:1; /* The job has an OtherJobEnabled KeepAlive criterion. */
 	mode_t mask;
 	pid_t sample_pid;
 	const char label[0];
@@ -465,8 +470,8 @@
 static LIST_HEAD(, job_s) label_hash[LABEL_HASH_SIZE];
 static size_t hash_label(const char *label) __attribute__((pure));
 static size_t hash_ms(const char *msstr) __attribute__((pure));
+static SLIST_HEAD(, job_s) s_curious_jobs;
 
-
 #define job_assumes(j, e)	\
 	(unlikely(!(e)) ? job_log_bug(j, __LINE__), false : true)
 
@@ -481,9 +486,11 @@
 static const char *job_active(job_t j);
 static void job_watch(job_t j);
 static void job_ignore(job_t j);
+static void job_reap_sample(job_t j);
 static void job_reap(job_t j);
 static bool job_useless(job_t j);
 static bool job_keepalive(job_t j);
+static void job_dispatch_curious_jobs(job_t j);
 static void job_start(job_t j);
 static void job_start_child(job_t j) __attribute__((noreturn));
 static void job_setup_attributes(job_t j);
@@ -499,9 +506,8 @@
 static void job_force_sampletool(job_t j);
 #endif
 static void job_setup_exception_port(job_t j, task_t target_task);
-static void job_reparent_hack(job_t j, const char *where);
 INTERNAL_ABI static void job_callback(void *obj, struct kevent *kev);
-static void job_callback_proc(job_t j, int fflags);
+static void job_callback_proc(job_t j, struct kevent *kev);
 static void job_callback_timer(job_t j, void *ident);
 static void job_callback_read(job_t j, int ident);
 static void job_log_stray_pg(job_t j);
@@ -564,7 +570,6 @@
 mach_port_t inherited_bootstrap_port;
 jobmgr_t root_jobmgr;
 
-
 void
 job_ignore(job_t j)
 {
@@ -1037,6 +1042,8 @@
 			return;
 		}
 	}
+	
+	job_dispatch_curious_jobs(j);
 
 	ipc_close_all_with_job(j);
 
@@ -1536,6 +1543,7 @@
 		return NULL;
 	}
 
+	job_dispatch_curious_jobs(j);
 	return job_dispatch(j, false);
 }
 
@@ -1546,7 +1554,7 @@
 	job_t *ja;
 	size_t i, c = launch_data_array_get_count(pload);
 
-	ja = alloca(c * sizeof(job_t ));
+	ja = alloca(c * sizeof(job_t));
 
 	for (i = 0; i < c; i++) {
 		if (likely(ja[i] = jobmgr_import2(root_jobmgr, launch_data_array_get_index(pload, i)))) {
@@ -1557,6 +1565,7 @@
 
 	for (i = 0; i < c; i++) {
 		if (likely(ja[i])) {
+			job_dispatch_curious_jobs(ja[i]);
 			job_dispatch(ja[i], false);
 		}
 	}
@@ -1718,7 +1727,6 @@
 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADFROMHOSTS) == 0) {
 			return;
 		} else if (strcasecmp(key, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE) == 0) {
-			job_reparent_hack(j, value);
 			return;
 		}
 		break;
@@ -2181,6 +2189,14 @@
 		argv[i] = NULL;
 	}
 
+	/* Hack to make sure the proper job manager is set the whole way through. */
+	launch_data_t session = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE);
+	if( session ) {
+		jm = jobmgr_find_by_name(jm, launch_data_get_string(session)) ?: jm;
+	}
+	
+	jobmgr_log(jm, LOG_DEBUG, "Importing %s.", label);
+	
 	if (unlikely((j = job_find(label)) != NULL)) {
 		errno = EEXIST;
 		return NULL;
@@ -2434,14 +2450,8 @@
 	}
 
 	if (unlikely(j->weird_bootstrap)) {
-		mach_msg_size_t mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
-
-		if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
-			mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
-		}
-
-		job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
-		j->weird_bootstrap = false;
+		int64_t junk = 0;
+		job_mig_swap_integer(j, VPROC_GSK_WEIRD_BOOTSTRAP, 0, 0, &junk);
 	}
 
 	if (j->log_redirect_fd && !j->legacy_LS_job) {
@@ -2522,7 +2532,7 @@
 		td_sec = td / NSEC_PER_SEC;
 		td_usec = (td % NSEC_PER_SEC) / NSEC_PER_USEC;
 
-		job_log(j, LOG_INFO, "Exited %llu.%06llu seconds after the first signal was sent", td_sec, td_usec);
+		job_log(j, LOG_NOTICE, "Exited %llu.%06llu seconds after the first signal was sent", td_sec, td_usec);
 	}
 
 	timeradd(&ru.ru_utime, &j->ru.ru_utime, &j->ru.ru_utime);
@@ -2632,12 +2642,22 @@
 	snprintf(pidstr, sizeof(pidstr), "%u", j->p);
 	snprintf(j->mgr->sample_log_file, sizeof(j->mgr->sample_log_file), SHUTDOWN_LOG_DIR "/%s-%u.sample.txt", j->label, j->p);
 	job_log(j, LOG_DEBUG | LOG_CONSOLE, "Going to write sample to %s.", j->mgr->sample_log_file);
-
+	exception_mask_t exceptions =	EXC_MASK_BAD_ACCESS			|
+									EXC_MASK_BAD_INSTRUCTION	|
+									EXC_MASK_ARITHMETIC			|
+									EXC_MASK_CRASH				;
+	
 	if (job_assumes(j, unlink(jm->sample_log_file) != -1 || errno == ENOENT)) {
 		pid_t sp = 0;
 		char *sample_args[] = { "/usr/bin/sample", pidstr, "1", "-unsupportedShowArch", "-mayDie", "-file", j->mgr->sample_log_file, NULL };
-		if (!job_assumes(j, (errno = posix_spawnp(&sp, sample_args[0], NULL, NULL, sample_args, environ)) == 0)) {
+	#if NEEDS_MULTI_THREADED_EXEC
+		posix_spawnattr_t psattr;
+		posix_spawnattr_init(psattr);
+		posix_spawnattr_setexceptionports_np(&psattr, exceptions, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0);
+		
+		if (!job_assumes(j, (errno = posix_spawnp(&sp, sample_args[0], NULL, &psattr, sample_args, environ)) == 0)) {
 			job_log(j, LOG_ERR | LOG_CONSOLE, "Sampling failed for job! Kill it! Kill it with fire!");
+			LIST_REMOVE(j, pending_samples_sle);
 			job_kill(j);
 			jobmgr_dequeue_next_sample(jm);
 		} else {
@@ -2647,9 +2667,57 @@
 			/* Let us know when sample is done. ONESHOT is implicit if we're just interested in NOTE_EXIT. */
 			job_assumes(j, kevent_mod(sp, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j) != -1);
 		}
+		
+		posix_spawnattr_destroy(&psattr);
+	#else
+		switch( (sp = vfork()) ) {
+			case 0	:
+				/* Neuter the exception port so that crashes don't hang sample, making it unreapable. */
+				task_set_exception_ports(mach_task_self(), exceptions, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0);
+				execve(sample_args[0], sample_args, environ);
+				job_log(j, LOG_NOTICE | LOG_CONSOLE, "Could not exec(2): %d", errno);
+				_exit(EXIT_FAILURE);
+			case -1	:
+				job_log(j, LOG_NOTICE | LOG_CONSOLE, "vfork(2) failed: %d", errno);
+				break;
+			default	:
+				break;
+		}
+		
+		if( sp != -1 ) {
+			j->sample_pid = sp;
+			j->pending_sample = false;
+			
+			/* Let us know when sample is done. ONESHOT is implicit if we're just interested in NOTE_EXIT. */
+			job_assumes(j, kevent_mod(sp, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, j) != -1);
+		} else {
+			job_log(j, LOG_ERR | LOG_CONSOLE, "Sampling failed for job! Kill it! Kill it with fire!");
+			LIST_REMOVE(j, pending_samples_sle);
+			job_kill(j);
+			jobmgr_dequeue_next_sample(jm);
+		}
+	#endif
 	}
 }
 
+void
+job_dispatch_curious_jobs(job_t j)
+{	
+	job_t ji = NULL;
+	SLIST_FOREACH( ji, &s_curious_jobs, curious_jobs_sle ) {
+		struct semaphoreitem *si = NULL;
+		SLIST_FOREACH( si, &ji->semaphores, sle ) {			
+			if( si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED ) {
+				if( strncmp(si->what, j->label, strlen(j->label)) == 0 ) {
+					job_log(ji, LOG_NOTICE | LOG_CONSOLE, "Dispatching out of interest in \"%s\".", j->label);
+					job_assumes(ji, job_dispatch(ji, false) != NULL);
+					break;
+				}
+			}
+		}
+	}
+}
+
 INTERNAL_ABI job_t
 job_dispatch(job_t j, bool kickstart)
 {
@@ -2800,21 +2868,17 @@
 	free(kp);
 }
 
-static void
+void
 job_reap_sample(job_t j)
 {
 	char *contents = NULL;
 	int wstatus = 0;
 	int logfile_fd = -1;
 	
-	LIST_REMOVE(j, pending_samples_sle);
-	
 	if (!job_assumes(j, waitpid(j->sample_pid, &wstatus, 0) != -1)) {
 		goto out;
 	}
 
-	j->sampled = true;
-
 	/*
 	 * This won't work if the VFS or filesystems are sick:
 	 * sync();
@@ -2874,23 +2938,41 @@
 	}
 
 	j->sample_pid = 0;
+	j->sampled = true;
+	LIST_REMOVE(j, pending_samples_sle);
+	
+	if( j->reap_after_sample ) {
+		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Sampling complete. Reaping.");
+		struct kevent kev;
+		EV_SET(&kev, 1, 0, 0, NOTE_EXIT, 0, 0);
+		
+		/* Fake a kevent to keep our logic consistent. */
+		job_callback_proc(j, &kev);
+	}
+	
 	job_log(j, LOG_DEBUG | LOG_CONSOLE, "Finished sampling.");
 	
 	jobmgr_dequeue_next_sample(j->mgr);
 }
 
 void
-job_callback_proc(job_t j, int fflags)
+job_callback_proc(job_t j, struct kevent *kev)
 {
 	bool program_changed = false;
+	int fflags = kev->fflags;
 	
-	if( j->sample_pid ) {
+	if( j->sample_pid == (pid_t)kev->ident ) {
 		job_assumes(j, (fflags & NOTE_EXIT) != 0);
 		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Sampling for job done. Reaping sample...");
 		
 		job_reap_sample(j);
 		
 		return;
+	} else if( j->sample_pid && !j->reap_after_sample ) {
+		/* The job exited before our sample completed. */
+		job_log(j, LOG_NOTICE | LOG_CONSOLE, "Job exited. Will reap after sample is complete.");
+		j->reap_after_sample = true;
+		return;
 	}
 	
 	if (fflags & NOTE_EXEC) {
@@ -2971,7 +3053,7 @@
 			td -= j->exit_timeout;
 
 			job_log(j, LOG_WARNING | LOG_CONSOLE, "Did not die after sending SIGKILL %llu seconds ago...", td);
-		} else if (!j->sampled && (!j->exit_timeout || (LAUNCHD_SAMPLE_TIMEOUT < j->exit_timeout))) {
+		} else if ((!j->sampled && !j->sample_pid) && (!j->exit_timeout || (LAUNCHD_SAMPLE_TIMEOUT < j->exit_timeout))) {
 			/* This should work even if the job changes its exit_timeout midstream */
 			job_log(j, LOG_NOTICE | LOG_CONSOLE, "Sampling timeout elapsed (%u seconds). Scheduling a sample...", LAUNCHD_SAMPLE_TIMEOUT);
 			if (j->exit_timeout) {
@@ -3101,7 +3183,7 @@
 
 	switch (kev->filter) {
 	case EVFILT_PROC:
-		return job_callback_proc(j, kev->fflags);
+		return job_callback_proc(j, kev);
 	case EVFILT_TIMER:
 		return job_callback_timer(j, (void *) kev->ident);
 	case EVFILT_VNODE:
@@ -4232,16 +4314,41 @@
 	if (val < 0) {
 		job_log(j, LOG_WARNING, "The interval for key \"%s\" is less than zero.", key);
 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MINUTE) == 0) {
-		tmptm->tm_min = (typeof(tmptm->tm_min)) val;
+		if( val > 59 ) {
+			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 59 (inclusive).", key);
+			tmptm->tm_sec = -1;
+		} else {
+			tmptm->tm_min = (typeof(tmptm->tm_min)) val;
+		}
 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_HOUR) == 0) {
-		tmptm->tm_hour = (typeof(tmptm->tm_hour)) val;
+		if( val > 23 ) {
+			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 23 (inclusive).", key);
+			tmptm->tm_sec = -1;
+		} else {
+			tmptm->tm_hour = (typeof(tmptm->tm_hour)) val;
+		}
 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_DAY) == 0) {
-		tmptm->tm_mday = (typeof(tmptm->tm_mday)) val;
+		if( val < 1 || val > 31 ) {
+			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 1 and 31 (inclusive).", key);
+			tmptm->tm_sec = -1;
+		} else {
+			tmptm->tm_mday = (typeof(tmptm->tm_mday)) val;
+		}
 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_WEEKDAY) == 0) {
-		tmptm->tm_wday = (typeof(tmptm->tm_wday)) val;
+		if( val > 7 ) {
+			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 7 (inclusive).", key);
+			tmptm->tm_sec = -1;
+		} else {
+			tmptm->tm_wday = (typeof(tmptm->tm_wday)) val;
+		}
 	} else if (strcasecmp(key, LAUNCH_JOBKEY_CAL_MONTH) == 0) {
-		tmptm->tm_mon = (typeof(tmptm->tm_mon)) val;
-		tmptm->tm_mon -= 1; /* 4798263 cron compatibility */
+		if( val > 12 ) {
+			job_log(j, LOG_WARNING, "The interval for key \"%s\" is not between 0 and 12 (inclusive).", key);
+			tmptm->tm_sec = -1;
+		} else {
+			tmptm->tm_mon = (typeof(tmptm->tm_mon)) val;
+			tmptm->tm_mon -= 1; /* 4798263 cron compatibility */
+		}
 	}
 }
 
@@ -5738,6 +5845,12 @@
 	}
 
 	SLIST_INSERT_HEAD(&j->semaphores, si, sle);
+	
+	if( (why == OTHER_JOB_ENABLED || why == OTHER_JOB_DISABLED) && !j->nosy ) {
+		job_log(j, LOG_DEBUG, "Job is interested in \"%s\".", what);
+		SLIST_INSERT_HEAD(&s_curious_jobs, j, curious_jobs_sle);
+		j->nosy = true;
+	}
 
 	semaphoreitem_runtime_mod_ref(si, true);
 
@@ -5782,6 +5895,14 @@
 		job_assumes(j, runtime_close(si->fd) != -1);
 	}
 
+	job_log(j, LOG_DEBUG, "Removing semaphore item... (what = %s, why = %u)", si->what, si->why);
+	
+	/* We'll need to rethink this if it ever becomes possible to dynamically add or remove semaphores. */
+	if( (si->why == OTHER_JOB_ENABLED || si->why == OTHER_JOB_DISABLED) && j->nosy ) {
+		j->nosy = false;
+		SLIST_REMOVE(&s_curious_jobs, j, job_s, curious_jobs_sle);
+	}
+
 	free(si);
 }
 
@@ -6088,6 +6209,18 @@
 		return BOOTSTRAP_NOT_PRIVILEGED;
 	}
 
+#if HAVE_SANDBOX
+	const char **argv = (const char **)mach_cmd2argv(server_cmd);
+	if (unlikely(argv == NULL)) {
+		return BOOTSTRAP_NO_MEMORY;
+	}
+	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_PATH, argv[0]) > 0)) {
+		free(argv);
+		return BOOTSTRAP_NOT_PRIVILEGED;
+	}
+	free(argv);
+#endif
+
 	job_log(j, LOG_DEBUG, "Server create attempt: %s", server_cmd);
 
 	if (pid1_magic) {
@@ -6449,6 +6582,19 @@
 			j->kill_via_shmem = (bool)inval;
 			job_log(j, LOG_DEBUG, "j->kill_via_shmem = %s", j->kill_via_shmem ? "true" : "false");
 		}
+	case VPROC_GSK_WEIRD_BOOTSTRAP:
+		if( job_assumes(j, j->weird_bootstrap) ) {
+			job_log(j, LOG_NOTICE, "Unsetting weird bootstrap.");
+			
+			mach_msg_size_t mxmsgsz = (typeof(mxmsgsz)) sizeof(union __RequestUnion__job_mig_protocol_vproc_subsystem);
+			
+			if (job_mig_protocol_vproc_subsystem.maxsize > mxmsgsz) {
+				mxmsgsz = job_mig_protocol_vproc_subsystem.maxsize;
+			}
+			
+			job_assumes(j, runtime_add_mport(j->mgr->jm_port, protocol_vproc_server, mxmsgsz) == KERN_SUCCESS);
+			j->weird_bootstrap = false;
+		}
 	case 0:
 		break;
 	default:
@@ -6819,6 +6965,12 @@
 		return BOOTSTRAP_NOT_PRIVILEGED;
 	}
 
+#if HAVE_SANDBOX
+	if (unlikely(sandbox_check(ldc->pid, "mach-lookup", per_pid_lookup ? SANDBOX_FILTER_LOCAL_NAME : SANDBOX_FILTER_GLOBAL_NAME, servicename) > 0)) {
+		return BOOTSTRAP_NOT_PRIVILEGED;
+	}
+#endif
+
 	if (per_pid_lookup) {
 		ms = jobmgr_lookup_service(j->mgr, servicename, false, target_pid);
 	} else {
@@ -6961,8 +7113,8 @@
 	return BOOTSTRAP_NO_MEMORY;
 }
 
-void
-job_reparent_hack(job_t j, const char *where)
+jobmgr_t 
+jobmgr_find_by_name(jobmgr_t jm, const char *where)
 {
 	jobmgr_t jmi, jmi2;
 
@@ -6970,18 +7122,23 @@
 
 	/* NULL is only passed for our custom API for LaunchServices. If that is the case, we do magic. */
 	if (where == NULL) {
-		if (strcasecmp(j->mgr->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
+		if (strcasecmp(jm->name, VPROCMGR_SESSION_LOGINWINDOW) == 0) {
 			where = VPROCMGR_SESSION_LOGINWINDOW;
 		} else {
 			where = VPROCMGR_SESSION_AQUA;
 		}
 	}
 
-	if (strcasecmp(j->mgr->name, where) == 0) {
-		return;
+	if (strcasecmp(jm->name, where) == 0) {
+		return jm;
 	}
+	
+	if( strcasecmp(where, VPROCMGR_SESSION_BACKGROUND) == 0 && !pid1_magic ) {
+		jmi = root_jobmgr;
+		goto jm_found;
+	}
 
-	SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {
+	SLIST_FOREACH(jmi, &root_jobmgr->submgrs, sle) {	
 		if (unlikely(jmi->shutting_down)) {
 			continue;
 		} else if (strcasecmp(jmi->name, where) == 0) {
@@ -6996,22 +7153,10 @@
 		}
 	}
 
+	launchd_assumes(jmi != NULL);
+	
 jm_found:
-	if (job_assumes(j, jmi != NULL)) {
-		struct machservice *msi;
-
-		SLIST_FOREACH(msi, &j->machservices, sle) {
-			LIST_REMOVE(msi, name_hash_sle);
-		}
-
-		LIST_REMOVE(j, sle);
-		LIST_INSERT_HEAD(&jmi->jobs, j, sle);
-		j->mgr = jmi;
-
-		SLIST_FOREACH(msi, &j->machservices, sle) {
-			LIST_INSERT_HEAD(&j->mgr->ms_hash[hash_ms(msi->name)], msi, name_hash_sle);
-		}
-	}
+	return jmi;
 }
 
 kern_return_t
@@ -7526,6 +7671,12 @@
 		return BOOTSTRAP_NOT_PRIVILEGED;
 	}
 
+#if HAVE_SANDBOX
+	if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) {
+		return BOOTSTRAP_NOT_PRIVILEGED;
+	}
+#endif
+
 	if (unlikely(pid1_magic && ldc->euid && ldc->uid)) {
 		job_log(j, LOG_DEBUG, "Punting spawn to per-user-context");
 		return VPROC_ERR_TRY_PER_USER;
@@ -7540,8 +7691,14 @@
 		return 1;
 	}
 
-	jr = jobmgr_import2(j->mgr, input_obj);
+	jobmgr_t target_jm = jobmgr_find_by_name(j->mgr, NULL);
+	if( !jobmgr_assumes(j->mgr, target_jm != NULL) ) {
+		jobmgr_log(j->mgr, LOG_NOTICE, "%s() can't find its session!", __func__);
+		return 1;
+	}
 	
+	jr = jobmgr_import2(target_jm ?: j->mgr, input_obj);
+	
 	if (!job_assumes(j, jr != NULL)) {
 		switch (errno) {
 		case EEXIST:
@@ -7551,8 +7708,6 @@
 		}
 	}
 
-	job_reparent_hack(jr, NULL);
-
 	if (pid1_magic) {
 		jr->mach_uid = ldc->uid;
 	}
@@ -7592,7 +7747,8 @@
 jobmgr_init(bool sflag)
 {
 	const char *root_session_type = pid1_magic ? VPROCMGR_SESSION_SYSTEM : VPROCMGR_SESSION_BACKGROUND;
-
+	SLIST_INIT(&s_curious_jobs);
+	
 	launchd_assert((root_jobmgr = jobmgr_new(NULL, MACH_PORT_NULL, MACH_PORT_NULL, sflag, root_session_type)) != NULL);
 }
 

Modified: trunk/launchd/src/launchd_core_logic.h
===================================================================
--- trunk/launchd/src/launchd_core_logic.h	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/launchd/src/launchd_core_logic.h	2008-11-06 23:52:32 UTC (rev 23750)
@@ -20,7 +20,7 @@
  * @APPLE_APACHE_LICENSE_HEADER_END@
  */
 
-#include <launchd_runtime.h>
+#include "launchd_runtime.h"
 #include "bootstrap.h"
 #include "launch.h"
 
@@ -33,6 +33,7 @@
 INTERNAL_ABI void jobmgr_init(bool);
 INTERNAL_ABI jobmgr_t jobmgr_shutdown(jobmgr_t jm);
 INTERNAL_ABI void jobmgr_dispatch_all_semaphores(jobmgr_t jm);
+void jobmgr_dispatch_all_interested(jobmgr_t jm, job_t j);
 INTERNAL_ABI jobmgr_t jobmgr_delete_anything_with_port(jobmgr_t jm, mach_port_t port);
 
 INTERNAL_ABI launch_data_t job_export_all(void);

Modified: trunk/launchd/src/vproc_priv.h
===================================================================
--- trunk/launchd/src/vproc_priv.h	2008-10-30 01:28:28 UTC (rev 23749)
+++ trunk/launchd/src/vproc_priv.h	2008-11-06 23:52:32 UTC (rev 23750)
@@ -27,6 +27,7 @@
 #include <sys/time.h>
 #include <stdbool.h>
 #include <launch.h>
+#include <vproc.h>
 
 #ifndef VPROC_HAS_TRANSACTIONS
 	#define VPROC_HAS_TRANSACTIONS
@@ -56,7 +57,8 @@
 	VPROC_GSK_GLOBAL_LOG_MASK,
 	VPROC_GSK_GLOBAL_UMASK,
 	VPROC_GSK_ABANDON_PROCESS_GROUP,
-	VPROC_GSK_TRANSACTIONS_ENABLED
+	VPROC_GSK_TRANSACTIONS_ENABLED,
+	VPROC_GSK_WEIRD_BOOTSTRAP,
 } vproc_gsk_t;
 
 vproc_err_t vproc_swap_integer(vproc_t vp, vproc_gsk_t key, int64_t *inval, int64_t *outval);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/launchd-changes/attachments/20081106/1be54ef0/attachment-0001.html>


More information about the launchd-changes mailing list