Revision: 23870 http://trac.macosforge.org/projects/launchd/changeset/23870 Author: dsorresso@apple.com Date: 2009-03-26 00:22:22 -0700 (Thu, 26 Mar 2009) Log Message: ----------- <rdar://problem/6718433> Modified Paths: -------------- trunk/launchd/src/launch_priv.h trunk/launchd/src/launchd.c trunk/launchd/src/launchd_core_logic.c trunk/launchd/src/launchd_runtime.c trunk/launchd/src/launchd_unix_ipc.c trunk/launchd/src/liblaunch.c trunk/launchd.xcodeproj/project.pbxproj Modified: trunk/launchd/src/launch_priv.h =================================================================== --- trunk/launchd/src/launch_priv.h 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/launch_priv.h 2009-03-26 07:22:22 UTC (rev 23870) @@ -78,7 +78,7 @@ typedef struct _launch *launch_t; -launch_t launchd_fdopen(int); +launch_t launchd_fdopen(int, int); int launchd_getfd(launch_t); void launchd_close(launch_t, __typeof__(close) closefunc); Modified: trunk/launchd/src/launchd.c =================================================================== --- trunk/launchd/src/launchd.c 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/launchd.c 2009-03-26 07:22:22 UTC (rev 23870) @@ -231,6 +231,7 @@ pthread_t t = NULL; int err = pthread_create(&t, NULL, update_thread, NULL); launchd_assumes(err == 0); + launchd_assumes(pthread_detach(t) == 0); } jobmgr_init(sflag); Modified: trunk/launchd/src/launchd_core_logic.c =================================================================== --- trunk/launchd/src/launchd_core_logic.c 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/launchd_core_logic.c 2009-03-26 07:22:22 UTC (rev 23870) @@ -4327,7 +4327,9 @@ bool log_to_console = pri & LOG_CONSOLE; int _pri = pri & ~LOG_CONSOLE; - struct runtime_syslog_attr attr = { g_my_label, j->label, j->mgr->name, _pri, getuid(), getpid(), j->p }; + const char *label2use = j ? j->label : "com.apple.launchd.NULL"; + const char *mgr2use = j ? j->mgr->name : "NULL"; + struct runtime_syslog_attr attr = { g_my_label, label2use, mgr2use, _pri, getuid(), getpid(), j ? j->p : 0 }; char *newmsg; int oldmask = 0; size_t newmsgsz; @@ -4348,23 +4350,23 @@ #if !TARGET_OS_EMBEDDED snprintf(newmsg, newmsgsz, "%s: %s", msg, strerror(err)); #else - snprintf(newmsg, newmsgsz, "(%s) %s: %s", j->label, msg, strerror(err)); + snprintf(newmsg, newmsgsz, "(%s) %s: %s", label2use, msg, strerror(err)); #endif } else { #if !TARGET_OS_EMBEDDED snprintf(newmsg, newmsgsz, "%s", msg); #else - snprintf(newmsg, newmsgsz, "(%s) %s", j->label, msg); + snprintf(newmsg, newmsgsz, "(%s) %s", label2use, msg); #endif } - if (unlikely(j->debug)) { + if( j && unlikely(j->debug) ) { oldmask = setlogmask(LOG_UPTO(LOG_DEBUG)); } runtime_vsyslog(&attr, log_to_console, newmsg, ap); - if (unlikely(j->debug)) { + if( j && unlikely(j->debug) ) { setlogmask(oldmask); } } @@ -6689,6 +6691,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(!(otherj = job_find(targetlabel)))) { return BOOTSTRAP_UNKNOWN_SERVICE; } @@ -7358,6 +7366,12 @@ return BOOTSTRAP_NOT_PRIVILEGED; #endif +#if HAVE_SANDBOX + if (unlikely(sandbox_check(ldc->pid, "job-creation", SANDBOX_FILTER_NONE) > 0)) { + return BOOTSTRAP_NOT_PRIVILEGED; + } +#endif + if (!launchd_assumes(j != NULL)) { return BOOTSTRAP_NO_MEMORY; } Modified: trunk/launchd/src/launchd_runtime.c =================================================================== --- trunk/launchd/src/launchd_runtime.c 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/launchd_runtime.c 2009-03-26 07:22:22 UTC (rev 23870) @@ -151,7 +151,6 @@ launchd_runtime_init(void) { mach_msg_size_t mxmsgsz; - pthread_attr_t attr; pid_t p = getpid(); launchd_assert((mainkq = kqueue()) != -1); @@ -171,13 +170,9 @@ } launchd_assert(runtime_add_mport(launchd_internal_port, launchd_internal_demux, mxmsgsz) == KERN_SUCCESS); + launchd_assert(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL) == 0); + launchd_assert(pthread_detach(kqueue_demand_thread) == 0); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - launchd_assert(pthread_create(&kqueue_demand_thread, &attr, kqueue_demand_loop, NULL) == 0); - pthread_attr_destroy(&attr); - launchd_assumes(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)) != -1); } Modified: trunk/launchd/src/launchd_unix_ipc.c =================================================================== --- trunk/launchd/src/launchd_unix_ipc.c 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/launchd_unix_ipc.c 2009-03-26 07:22:22 UTC (rev 23870) @@ -186,7 +186,12 @@ fcntl(fd, F_SETFL, O_NONBLOCK); c->kqconn_callback = ipc_callback; - c->conn = launchd_fdopen(fd); + if( j ) { + c->conn = launchd_fdopen(-1, fd); + } else { + c->conn = launchd_fdopen(fd, -1); + } + c->j = j; LIST_INSERT_HEAD(&connections, c, sle); kevent_mod(fd, EVFILT_READ, EV_ADD, 0, 0, &c->kqconn_callback); @@ -337,7 +342,6 @@ launch_data_free(rmc.resp); } - void ipc_readmsg2(launch_data_t data, const char *cmd, void *context) { @@ -349,80 +353,85 @@ return; } - //job_log(rmc->c->j, LOG_DEBUG, "Unix IPC request: %s", cmd); - - if (data == NULL) { - if (!strcmp(cmd, LAUNCH_KEY_CHECKIN)) { - if (rmc->c->j) { - resp = job_export(rmc->c->j); - job_checkin(rmc->c->j); - } else { - resp = launch_data_new_errno(EACCES); +// job_log(rmc->c->j, LOG_NOTICE, "Socket IPC request: %s.", cmd); + + /* Do not allow commands other than check-in to come over the trusted socket. */ + if( data == NULL && rmc->c->j ) { + if( strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0 ) { + resp = job_export(rmc->c->j); + job_checkin(rmc->c->j); + } else { + resp = launch_data_new_errno(EACCES); + } + } else { + if( data == NULL ) { + if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { + launchd_shutdown(); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_SINGLEUSER)) { + launchd_single_user(); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { + resp = job_export_all(); + ipc_revoke_fds(resp); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { + resp = adjust_rlimits(NULL); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + resp = launch_data_new_opaque(&rusage, sizeof(rusage)); + } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { + struct rusage rusage; + getrusage(RUSAGE_CHILDREN, &rusage); + resp = launch_data_new_opaque(&rusage, sizeof(rusage)); } - } else if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) { - launchd_shutdown(); - resp = launch_data_new_errno(0); - } else if (!strcmp(cmd, LAUNCH_KEY_SINGLEUSER)) { - launchd_single_user(); - resp = launch_data_new_errno(0); - } else if (!strcmp(cmd, LAUNCH_KEY_GETJOBS)) { - resp = job_export_all(); - ipc_revoke_fds(resp); - } else if (!strcmp(cmd, LAUNCH_KEY_GETRESOURCELIMITS)) { - resp = adjust_rlimits(NULL); - } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGESELF)) { - struct rusage rusage; - getrusage(RUSAGE_SELF, &rusage); - resp = launch_data_new_opaque(&rusage, sizeof(rusage)); - } else if (!strcmp(cmd, LAUNCH_KEY_GETRUSAGECHILDREN)) { - struct rusage rusage; - getrusage(RUSAGE_CHILDREN, &rusage); - resp = launch_data_new_opaque(&rusage, sizeof(rusage)); - } - } else if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { - if ((j = job_find(launch_data_get_string(data))) != NULL) { - job_dispatch(j, true); - errno = 0; - } - resp = launch_data_new_errno(errno); - } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { - if ((j = job_find(launch_data_get_string(data))) != NULL) { - job_stop(j); - errno = 0; - } - resp = launch_data_new_errno(errno); - } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { - if ((j = job_find(launch_data_get_string(data))) != NULL) { - job_remove(j); - errno = 0; - } - resp = launch_data_new_errno(errno); - } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { - if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { - resp = job_import_bulk(data); } else { - if (job_import(data)) { - errno = 0; + if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) { + if ((j = job_find(launch_data_get_string(data))) != NULL) { + job_dispatch(j, true); + errno = 0; + } + resp = launch_data_new_errno(errno); + } else if (!strcmp(cmd, LAUNCH_KEY_STOPJOB)) { + if ((j = job_find(launch_data_get_string(data))) != NULL) { + job_stop(j); + errno = 0; + } + resp = launch_data_new_errno(errno); + } else if (!strcmp(cmd, LAUNCH_KEY_REMOVEJOB)) { + if ((j = job_find(launch_data_get_string(data))) != NULL) { + job_remove(j); + errno = 0; + } + resp = launch_data_new_errno(errno); + } else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) { + if (launch_data_get_type(data) == LAUNCH_DATA_ARRAY) { + resp = job_import_bulk(data); + } else { + if (job_import(data)) { + errno = 0; + } + resp = launch_data_new_errno(errno); + } + } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { + unsetenv(launch_data_get_string(data)); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { + launch_data_dict_iterate(data, set_user_env, NULL); + resp = launch_data_new_errno(0); + } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { + resp = adjust_rlimits(data); + } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { + if ((j = job_find(launch_data_get_string(data))) == NULL) { + resp = launch_data_new_errno(errno); + } else { + resp = job_export(j); + ipc_revoke_fds(resp); + } + } else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) { + resp = launch_data_new_errno(launchd_set_jetsam_priorities(data)); } - resp = launch_data_new_errno(errno); } - } else if (!strcmp(cmd, LAUNCH_KEY_UNSETUSERENVIRONMENT)) { - unsetenv(launch_data_get_string(data)); - resp = launch_data_new_errno(0); - } else if (!strcmp(cmd, LAUNCH_KEY_SETUSERENVIRONMENT)) { - launch_data_dict_iterate(data, set_user_env, NULL); - resp = launch_data_new_errno(0); - } else if (!strcmp(cmd, LAUNCH_KEY_SETRESOURCELIMITS)) { - resp = adjust_rlimits(data); - } else if (!strcmp(cmd, LAUNCH_KEY_GETJOB)) { - if ((j = job_find(launch_data_get_string(data))) == NULL) { - resp = launch_data_new_errno(errno); - } else { - resp = job_export(j); - ipc_revoke_fds(resp); - } - } else if( !strcmp(cmd, LAUNCH_KEY_SETPRIORITYLIST) ) { - resp = launch_data_new_errno(launchd_set_jetsam_priorities(data)); } rmc->resp = resp; Modified: trunk/launchd/src/liblaunch.c =================================================================== --- trunk/launchd/src/liblaunch.c 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd/src/liblaunch.c 2009-03-26 07:22:22 UTC (rev 23870) @@ -147,6 +147,10 @@ }; }; +enum { + LAUNCHD_USE_CHECKIN_FD, + LAUNCHD_USE_OTHER_FD, +}; struct _launch { void *sendbuf; int *sendfds; @@ -156,10 +160,9 @@ size_t sendfdcnt; size_t recvlen; size_t recvfdcnt; + int which; + int cifd; int fd; -#if __LP64__ - int __pad; -#endif }; static launch_data_t launch_data_array_pop_first(launch_data_t where); @@ -186,7 +189,7 @@ struct sockaddr_un sun; char *where = getenv(LAUNCHD_SOCKET_ENV); char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV); - int dfd, lfd = -1; + int dfd, lfd = -1, cifd = -1; name_t spath; _lc = calloc(1, sizeof(struct _launch_client)); @@ -197,64 +200,78 @@ pthread_mutex_init(&_lc->mtx, NULL); if (_launchd_fd) { - lfd = strtol(_launchd_fd, NULL, 10); - if ((dfd = dup(lfd)) >= 0) { + cifd = strtol(_launchd_fd, NULL, 10); + if ((dfd = dup(cifd)) >= 0) { close(dfd); - _fd(lfd); + _fd(cifd); } else { - lfd = -1; + cifd = -1; } unsetenv(LAUNCHD_TRUSTED_FD_ENV); } - if (lfd == -1) { - memset(&sun, 0, sizeof(sun)); - sun.sun_family = AF_UNIX; - - /* The rules are as follows. - * - All users (including root) talk to their per-user launchd's by default. - * - If we have been invoked under sudo, talk to the system launchd. - * - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then - * talk to the system launchd. - */ - if (where && where[0] != '\0') { - strncpy(sun.sun_path, where, sizeof(sun.sun_path)); - } else { - if( _vprocmgr_getsocket(spath) == 0 ) { - if( (getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0 ) { - /* Talk to the system launchd. */ - strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); - } else { - /* Talk to our per-user launchd. */ - size_t min_len; - - min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath); - - strncpy(sun.sun_path, spath, min_len); - } + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + + /* The rules are as follows. + * - All users (including root) talk to their per-user launchd's by default. + * - If we have been invoked under sudo, talk to the system launchd. + * - If we're the root user and the __USE_SYSTEM_LAUNCHD environment variable is set, then + * talk to the system launchd. + */ + if (where && where[0] != '\0') { + strncpy(sun.sun_path, where, sizeof(sun.sun_path)); + } else { + if( _vprocmgr_getsocket(spath) == 0 ) { + if( (getenv("SUDO_COMMAND") || getenv("__USE_SYSTEM_LAUNCHD")) && geteuid() == 0 ) { + /* Talk to the system launchd. */ + strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); + } else { + /* Talk to our per-user launchd. */ + size_t min_len; + + min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath); + + strncpy(sun.sun_path, spath, min_len); } } + } - if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) { + if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) { + goto out_bad; + } + + if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) { + if( cifd != -1 ) { + /* There is NO security enforced by this check. This is just a hint to our + * library that we shouldn't error out due to failing to open this socket. If + * we inherited a trusted file descriptor, we shouldn't fail. This should be + * adequate for clients' expectations. + */ + close(lfd); + lfd = -1; + } else { goto out_bad; } - if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) { - goto out_bad; - } } - if (!(_lc->l = launchd_fdopen(lfd))) { + if (!(_lc->l = launchd_fdopen(lfd, cifd))) { goto out_bad; } + if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) { goto out_bad; } - + return; out_bad: if (_lc->l) launchd_close(_lc->l, close); else if (lfd != -1) close(lfd); + if( cifd != -1 ) { + close(cifd); + } if (_lc) free(_lc); _lc = NULL; @@ -318,7 +335,6 @@ return dict->_array_cnt / 2; } - bool launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key) { @@ -565,11 +581,11 @@ int launchd_getfd(launch_t l) { - return l->fd; + return ( l->which == LAUNCHD_USE_CHECKIN_FD ) ? l->cifd : l->fd; } launch_t -launchd_fdopen(int fd) +launchd_fdopen(int fd, int cifd) { launch_t c; @@ -578,8 +594,16 @@ return NULL; c->fd = fd; + c->cifd = cifd; + if( c->fd == -1 || (c->fd != -1 && c->cifd != -1) ) { + c->which = LAUNCHD_USE_CHECKIN_FD; + } else if( c->cifd == -1 ) { + c->which = LAUNCHD_USE_OTHER_FD; + } + fcntl(fd, F_SETFL, O_NONBLOCK); + fcntl(cifd, F_SETFL, O_NONBLOCK); if ((c->sendbuf = malloc(0)) == NULL) goto out_bad; @@ -621,6 +645,7 @@ if (lh->recvfds) free(lh->recvfds); closefunc(lh->fd); + closefunc(lh->cifd); free(lh); } @@ -801,6 +826,12 @@ size_t sentctrllen = 0; int r; + int fd2use = launchd_getfd(lh); + if( fd2use == -1 ) { + errno = EPERM; + return -1; + } + memset(&mh, 0, sizeof(mh)); /* confirm that the next hack works */ @@ -857,7 +888,7 @@ memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int)); } - if ((r = sendmsg(lh->fd, &mh, 0)) == -1) { + if ((r = sendmsg(fd2use, &mh, 0)) == -1) { return -1; } else if (r == 0) { errno = ECONNRESET; @@ -891,7 +922,6 @@ return 0; } - int launch_get_fd(void) { @@ -987,6 +1017,20 @@ return NULL; } + int fd2use = -1; + if( launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0 ) { + _lc->l->which = LAUNCHD_USE_CHECKIN_FD; + } else { + _lc->l->which = LAUNCHD_USE_OTHER_FD; + } + + fd2use = launchd_getfd(_lc->l); + + if( fd2use == -1 ) { + errno = EPERM; + return NULL; + } + #if !TARGET_OS_EMBEDDED uuid_t uuid; launch_data_t uuid_d = NULL; @@ -1035,7 +1079,7 @@ goto out; } while (launchd_msg_send(_lc->l, NULL) == -1); } - + while (resp == NULL) { if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) { resp = launch_data_array_pop_first(_lc->async_resp); @@ -1051,12 +1095,13 @@ fd_set rfds; FD_ZERO(&rfds); - FD_SET(_lc->l->fd, &rfds); + FD_SET(fd2use, &rfds); - select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL); + select(fd2use + 1, &rfds, NULL, NULL, NULL); } } } + out: #if !TARGET_OS_EMBEDDED if( !uuid_is_null(uuid) && resp && jobs_that_need_sessions > 0 ) { @@ -1110,6 +1155,12 @@ struct iovec iov; int r; + int fd2use = launchd_getfd(lh); + if( fd2use == -1 ) { + errno = EPERM; + return -1; + } + memset(&mh, 0, sizeof(mh)); mh.msg_iov = &iov; mh.msg_iovlen = 1; @@ -1121,7 +1172,7 @@ mh.msg_control = cm; mh.msg_controllen = 4096; - if ((r = recvmsg(lh->fd, &mh, 0)) == -1) + if ((r = recvmsg(fd2use, &mh, 0)) == -1) return -1; if (r == 0) { errno = ECONNRESET; Modified: trunk/launchd.xcodeproj/project.pbxproj =================================================================== --- trunk/launchd.xcodeproj/project.pbxproj 2009-03-25 21:52:29 UTC (rev 23869) +++ trunk/launchd.xcodeproj/project.pbxproj 2009-03-26 07:22:22 UTC (rev 23870) @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 45; objects = { /* Begin PBXAggregateTarget section */
participants (1)
-
source_changes@macosforge.org