[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