[launchd-changes] [23880] trunk/launchd/src
source_changes at macosforge.org
source_changes at macosforge.org
Thu Apr 2 18:35:20 PDT 2009
Revision: 23880
http://trac.macosforge.org/projects/launchd/changeset/23880
Author: dsorresso at apple.com
Date: 2009-04-02 18:35:19 -0700 (Thu, 02 Apr 2009)
Log Message:
-----------
Embedded security changes.
Modified Paths:
--------------
trunk/launchd/src/launch_priv.h
trunk/launchd/src/launchd_core_logic.c
trunk/launchd/src/launchd_core_logic.h
trunk/launchd/src/launchd_unix_ipc.c
trunk/launchd/src/liblaunch.c
trunk/launchd/src/vproc_priv.h
Modified: trunk/launchd/src/launch_priv.h
===================================================================
--- trunk/launchd/src/launch_priv.h 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/launch_priv.h 2009-04-03 01:35:19 UTC (rev 23880)
@@ -62,6 +62,7 @@
#define LAUNCH_JOBKEY_SECURITYSESSIONUUID "SecuritySessionUUID"
#define LAUNCH_JOBKEY_EMBEDDEDSHUTDOWNAUTHORITY "EmbeddedShutdownAuthority"
+#define LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION "EmbeddedPrivilegeDispensation"
#define LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL "EnterKernelDebuggerBeforeKill"
#define LAUNCH_JOBKEY_PERJOBMACHSERVICES "PerJobMachServices"
Modified: trunk/launchd/src/launchd_core_logic.c
===================================================================
--- trunk/launchd/src/launchd_core_logic.c 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/launchd_core_logic.c 2009-04-03 01:35:19 UTC (rev 23880)
@@ -528,7 +528,7 @@
is_bootstrapper :1, /* The job is a bootstrapper. */
has_console :1, /* The job owns the console. */
clean_exit_timer_expired :1, /* The job was clean, received SIGKILL and failed to exit after LAUNCHD_CLEAN_KILL_TIMER seconds. */
- embedded_shutdown_auth :1, /* The job is allowed to call reboot2() on embedded. */
+ embedded_special_privileges :1, /* The job runs as a non-root user on embedded but has select privileges of the root user. */
migratory :1; /* The (anonymous) job called vprocmgr_switch_to_session(). */
mode_t mask;
pid_t tracing_pid;
@@ -637,13 +637,15 @@
static job_t workaround_5477111;
static LIST_HEAD(, job_s) s_needing_sessions;
mach_port_t g_audit_session_port = MACH_PORT_NULL;
+
#if !TARGET_OS_EMBEDDED
+static job_t s_embedded_privileged_job = (job_t)&root_jobmgr;
au_asid_t g_audit_session = AU_DEFAUDITSID;
#else
+static job_t s_embedded_privileged_job = NULL;
pid_t g_audit_session = 0;
#endif
-static bool s_embedded_shutdown_right_claimed = false;
-static pid_t s_update_pid = 0;
+
static int s_no_hang_fd = -1;
/* process wide globals */
@@ -651,6 +653,7 @@
jobmgr_t root_jobmgr;
bool g_shutdown_debugging = false;
bool g_verbose_boot = false;
+bool g_embedded_privileged_action = false;
void
job_ignore(job_t j)
@@ -741,6 +744,18 @@
}
#endif
+#if TARGET_OS_EMBEDDED
+ if( g_embedded_privileged_action && s_embedded_privileged_job ) {
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return;
+ }
+#endif
+
j->sent_signal_time = runtime_get_opaque_time();
if (newval < 0) {
@@ -1016,6 +1031,18 @@
struct limititem *li;
struct envitem *ei;
+#if TARGET_OS_EMBEDDED
+ if( g_embedded_privileged_action && s_embedded_privileged_job ) {
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return;
+ }
+#endif
+
if (unlikely(j->p)) {
if (j->anonymous) {
job_reap(j);
@@ -1156,6 +1183,9 @@
if( !uuid_is_null(j->expected_audit_uuid) ) {
LIST_REMOVE(j, needing_session_sle);
}
+ if( j->embedded_special_privileges ) {
+ s_embedded_privileged_job = NULL;
+ }
kevent_mod((uintptr_t)j, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
@@ -1683,9 +1713,14 @@
} else if (strcasecmp(key, LAUNCH_JOBKEY_ENTERKERNELDEBUGGERBEFOREKILL) == 0) {
j->debug_before_kill = value;
found_key = true;
- } else if( !s_embedded_shutdown_right_claimed && strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDSHUTDOWNAUTHORITY) == 0 ) {
- j->embedded_shutdown_auth = true;
- s_embedded_shutdown_right_claimed = true;
+ } else if( strcasecmp(key, LAUNCH_JOBKEY_EMBEDDEDPRIVILEGEDISPENSATION) == 0 ) {
+ if( !s_embedded_privileged_job ) {
+ j->embedded_special_privileges = value;
+ s_embedded_privileged_job = j;
+ } else {
+ job_log(j, LOG_ERR, "Job tried to claim %s after it has already been claimed.", key);
+ }
+ found_key = true;
}
break;
case 'w':
@@ -2177,6 +2212,31 @@
return NULL;
}
+#if TARGET_OS_EMBEDDED
+ if( unlikely(g_embedded_privileged_action && s_embedded_privileged_job) ) {
+ if( unlikely(!(tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_USERNAME))) ) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ const char *username = NULL;
+ if( likely(tmp && launch_data_get_type(tmp) == LAUNCH_DATA_STRING) ) {
+ username = launch_data_get_string(tmp);
+ } else {
+ errno = EPERM;
+ return NULL;
+ }
+
+ if( unlikely(strcmp(s_embedded_privileged_job->username, username) != 0) ) {
+ errno = EPERM;
+ return NULL;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return NULL;
+ }
+#endif
+
if ((tmp = launch_data_dict_lookup(pload, LAUNCH_JOBKEY_PROGRAM)) &&
(launch_data_get_type(tmp) == LAUNCH_DATA_STRING)) {
prog = launch_data_get_string(tmp);
@@ -2886,6 +2946,18 @@
if( !uuid_is_null(j->expected_audit_uuid) ) {
return NULL;
}
+
+#if TARGET_OS_EMBEDDED
+ if( g_embedded_privileged_action && s_embedded_privileged_job ) {
+ if( strcmp(j->username, s_embedded_privileged_job->username) != 0 ) {
+ errno = EPERM;
+ return NULL;
+ }
+ } else if( g_embedded_privileged_action ) {
+ errno = EINVAL;
+ return NULL;
+ }
+#endif
/*
* The whole job removal logic needs to be consolidated. The fact that
@@ -3099,14 +3171,6 @@
log_kevent_struct(LOG_DEBUG, kev, 0);
if( fflags & NOTE_EXIT ) {
- if( s_update_pid == (pid_t)kev->ident ) {
- int status = 0;
- job_assumes(j, waitpid(s_update_pid, &status, 0) == 0);
- job_log(j, LOG_NOTICE, "Reaping update job (PID %i, exit status %i)", s_update_pid, WEXITSTATUS(status));
-
- s_update_pid = 0;
- }
-
if( j->p == (pid_t)kev->ident && !j->anonymous && !j->is_being_sampled ) {
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, j->p };
struct kinfo_proc kp;
@@ -3468,10 +3532,10 @@
}
if (likely(!j->legacy_mach_job)) {
- sipc = ( !SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices) ) && !j->deny_job_creation;
+ sipc = ((!SLIST_EMPTY(&j->sockets) || !SLIST_EMPTY(&j->machservices)) && !j->deny_job_creation) || j->embedded_special_privileges;
}
- if (sipc) {
+ if( sipc ) {
job_assumes(j, socketpair(AF_UNIX, SOCK_STREAM, 0, spair) != -1);
}
@@ -6101,6 +6165,11 @@
j->checkedin = true;
}
+bool job_is_god(job_t j)
+{
+ return j->embedded_special_privileges;
+}
+
bool
job_ack_port_destruction(mach_port_t p)
{
@@ -6612,7 +6681,17 @@
}
if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
+
+ }
+
+ if( unlikely(ldc->euid != 0 && ldc->euid != getuid()) || j->deny_job_creation ) {
+ #if TARGET_OS_EMBEDDED
+ if( !j->embedded_special_privileges ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+ #else
return BOOTSTRAP_NOT_PRIVILEGED;
+ #endif
}
#if HAVE_SANDBOX
@@ -6625,6 +6704,12 @@
return BOOTSTRAP_UNKNOWN_SERVICE;
}
+#if TARGET_OS_EMBEDDED
+ if( j->embedded_special_privileges && strcmp(j->username, otherj->username) != 0 ) {
+ return BOOTSTRAP_NOT_PRIVILEGED;
+ }
+#endif
+
if (sig == VPROC_MAGIC_UNLOAD_SIGNAL) {
bool do_block = otherj->p;
@@ -6913,6 +6998,9 @@
case VPROC_GSK_WAITFORDEBUGGER:
*outval = j->wait4debugger;
break;
+ case VPROC_GSK_EMBEDDEDROOTEQUIVALENT:
+ *outval = j->embedded_special_privileges;
+ break;
case 0:
*outval = 0;
break;
@@ -7136,7 +7224,7 @@
#if !TARGET_OS_EMBEDDED
if (unlikely(ldc->euid)) {
#else
- if( unlikely(ldc->euid) && !j->embedded_shutdown_auth ) {
+ if( unlikely(ldc->euid) && !j->embedded_special_privileges ) {
#endif
return BOOTSTRAP_NOT_PRIVILEGED;
}
@@ -8356,12 +8444,12 @@
}
#if TARGET_OS_EMBEDDED
- bool embedded_check = j->username && otherj->username && ( strcmp(j->username, otherj->username) != 0 );
+ bool allow_non_root_kickstart = j->username && otherj->username && ( strcmp(j->username, otherj->username) == 0 );
#else
- bool embedded_check = true;
+ bool allow_non_root_kickstart = false;
#endif
- if( ldc->euid != 0 && ldc->euid != geteuid() && embedded_check ) {
+ if( ldc->euid != 0 && ldc->euid != geteuid() && !allow_non_root_kickstart ) {
return BOOTSTRAP_NOT_PRIVILEGED;
}
@@ -8741,6 +8829,10 @@
#else
/* Since this is for embedded, we can assume that the root job manager holds the Jetsam jobs. */
jm = root_jobmgr;
+
+ if( !g_embedded_privileged_action ) {
+ return EPERM;
+ }
#endif
size_t npris = launch_data_array_get_count(priorities);
Modified: trunk/launchd/src/launchd_core_logic.h
===================================================================
--- trunk/launchd/src/launchd_core_logic.h 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/launchd_core_logic.h 2009-04-03 01:35:19 UTC (rev 23880)
@@ -32,6 +32,7 @@
extern mach_port_t g_audit_session_port;
extern au_asid_t g_audit_session;
extern bool g_flat_mach_namespace;
+extern bool g_embedded_privileged_action;
void jobmgr_init(bool);
jobmgr_t jobmgr_shutdown(jobmgr_t jm);
@@ -50,6 +51,7 @@
void job_stop(job_t j);
void job_checkin(job_t j);
void job_remove(job_t j);
+bool job_is_god(job_t j);
job_t job_import(launch_data_t pload);
launch_data_t job_import_bulk(launch_data_t pload);
job_t job_mig_intran(mach_port_t mp);
Modified: trunk/launchd/src/launchd_unix_ipc.c
===================================================================
--- trunk/launchd/src/launchd_unix_ipc.c 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/launchd_unix_ipc.c 2009-04-03 01:35:19 UTC (rev 23880)
@@ -354,16 +354,24 @@
}
// 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
+ * on the Desktop. On Embedded, allow all commands over the trusted socket if
+ * the job has the God Mode key set.
+ */
+#if TARGET_OS_EMBEDDED
+ bool allow_privileged_ops = ( !rmc->c->j || job_is_god(rmc->c->j) );
+#else
+ bool allow_privileged_ops = !rmc->c->j;
+#endif
- /* 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( rmc->c->j && strcmp(cmd, LAUNCH_KEY_CHECKIN) == 0 ) {
+ resp = job_export(rmc->c->j);
+ job_checkin(rmc->c->j);
+ } else if( allow_privileged_ops ) {
+ #if TARGET_OS_EMBEDDED
+ g_embedded_privileged_action = rmc->c->j && job_is_god(rmc->c->j);
+ #endif
if( data == NULL ) {
if (!strcmp(cmd, LAUNCH_KEY_SHUTDOWN)) {
launchd_shutdown();
@@ -388,20 +396,20 @@
} else {
if (!strcmp(cmd, LAUNCH_KEY_STARTJOB)) {
if ((j = job_find(launch_data_get_string(data))) != NULL) {
+ errno = 0;
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) {
+ errno = 0;
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) {
+ errno = 0;
job_remove(j);
- errno = 0;
}
resp = launch_data_new_errno(errno);
} else if (!strcmp(cmd, LAUNCH_KEY_SUBMITJOB)) {
@@ -432,6 +440,11 @@
resp = launch_data_new_errno(launchd_set_jetsam_priorities(data));
}
}
+ #if TARGET_OS_EMBEDDED
+ g_embedded_privileged_action = false;
+ #endif
+ } else {
+ resp = launch_data_new_errno(EACCES);
}
rmc->resp = resp;
Modified: trunk/launchd/src/liblaunch.c
===================================================================
--- trunk/launchd/src/liblaunch.c 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/liblaunch.c 2009-04-03 01:35:19 UTC (rev 23880)
@@ -172,6 +172,7 @@
static launch_data_t launch_msg_internal(launch_data_t d);
static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
+static int64_t s_am_embedded_god = false;
static launch_t in_flight_msg_recv_client;
static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
@@ -240,9 +241,12 @@
if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) {
goto out_bad;
}
-
+
+#if TARGET_OS_EMBEDDED
+ (void)vproc_swap_integer(NULL, VPROC_GSK_EMBEDDEDROOTEQUIVALENT, NULL, &s_am_embedded_god);
+#endif
if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) {
- if( cifd != -1 ) {
+ if( cifd != -1 || s_am_embedded_god ) {
/* 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
@@ -1018,7 +1022,7 @@
}
int fd2use = -1;
- if( launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0 ) {
+ if( (launch_data_get_type(d) == LAUNCH_DATA_STRING && strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) == 0) || s_am_embedded_god ) {
_lc->l->which = LAUNCHD_USE_CHECKIN_FD;
} else {
_lc->l->which = LAUNCHD_USE_OTHER_FD;
Modified: trunk/launchd/src/vproc_priv.h
===================================================================
--- trunk/launchd/src/vproc_priv.h 2009-04-02 22:41:10 UTC (rev 23879)
+++ trunk/launchd/src/vproc_priv.h 2009-04-03 01:35:19 UTC (rev 23880)
@@ -69,6 +69,7 @@
VPROC_GSK_PERUSER_RESUME,
VPROC_GSK_JOB_OVERRIDES_DB,
VPROC_GSK_JOB_CACHE_DB,
+ VPROC_GSK_EMBEDDEDROOTEQUIVALENT,
} vproc_gsk_t;
typedef unsigned int vproc_flags_t;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/launchd-changes/attachments/20090402/bcd7cf72/attachment-0001.html>
More information about the launchd-changes
mailing list