X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/866f8763175ff60e4fa455b92b5eb660a12fe6c7..refs/heads/master:/sectask/SecTask.c diff --git a/sectask/SecTask.c b/sectask/SecTask.c index 284a480d..4b38f13d 100644 --- a/sectask/SecTask.c +++ b/sectask/SecTask.c @@ -25,6 +25,7 @@ #include "SecTaskPriv.h" #include +#include #include #include @@ -35,14 +36,15 @@ #include #include #include +#include #include #if TARGET_OS_OSX /* These won't exist until we unify codesigning */ -#include "SecCode.h" -#include "SecCodePriv.h" -#include "SecRequirement.h" +#include +#include +#include #endif /* TARGET_OS_OSX */ struct __SecTask { @@ -132,6 +134,21 @@ SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t t return task; } +_Nullable SecTaskRef +SecTaskCreateWithXPCMessage(xpc_object_t _Nonnull message) +{ + audit_token_t token; + + if (message == NULL || xpc_get_type(message) != XPC_TYPE_DICTIONARY) { + return NULL; + } + xpc_dictionary_get_audit_token(message, &token); + + return SecTaskCreateWithAuditToken(NULL, token); +} + + + struct csheader { uint32_t magic; uint32_t length; @@ -150,8 +167,8 @@ csops_task(SecTaskRef task, int ops, void *blob, size_t size) return rc; } -CFStringRef -SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) +static CFStringRef +SecTaskCopyIdentifier(SecTaskRef task, int op, CFErrorRef *error) { CFStringRef signingId = NULL; char *data = NULL; @@ -159,7 +176,7 @@ SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) uint32_t bufferlen; int ret; - ret = csops_task(task, CS_OPS_IDENTITY, &header, sizeof(header)); + ret = csops_task(task, op, &header, sizeof(header)); if (ret != -1 || errno != ERANGE) return NULL; @@ -174,7 +191,7 @@ SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) ret = ENOMEM; goto out; } - ret = csops_task(task, CS_OPS_IDENTITY, data, bufferlen); + ret = csops_task(task, op, data, bufferlen); if (ret) { ret = errno; goto out; @@ -192,6 +209,18 @@ SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) return signingId; } +CFStringRef +SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) +{ + return SecTaskCopyIdentifier(task, CS_OPS_IDENTITY, error); +} + +CFStringRef +SecTaskCopyTeamIdentifier(SecTaskRef task, CFErrorRef *error) +{ + return SecTaskCopyIdentifier(task, CS_OPS_TEAMID, error); +} + uint32_t SecTaskGetCodeSignStatus(SecTaskRef task) { @@ -209,46 +238,44 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) uint32_t bufferlen; int ret; - ret = csops_task(task, CS_OPS_ENTITLEMENTS_BLOB, &header, sizeof(header)); /* Any other combination means no entitlements */ - if (ret == -1) { - if (errno != ERANGE) { + if (ret == -1) { + if (errno != ERANGE) { int entitlementErrno = errno; - uint32_t cs_flags = -1; + uint32_t cs_flags = -1; if (-1 == csops_task(task, CS_OPS_STATUS, &cs_flags, sizeof(cs_flags))) { syslog(LOG_NOTICE, "Failed to get cs_flags, error=%d", errno); } - if (cs_flags != 0) { // was signed - - pid_t pid; - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, pid=%d", entitlementErrno, cs_flags, pid); // to ease diagnostics - - CFStringRef description = SecTaskCopyDebugDescription(task); - char *descriptionBuf = NULL; - CFIndex descriptionSize = CFStringGetLength(description) * 4; - descriptionBuf = (char *)malloc(descriptionSize); - if (!CFStringGetCString(description, descriptionBuf, descriptionSize, kCFStringEncodingUTF8)) { - descriptionBuf[0] = 0; - } - - syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf); - CFReleaseNull(description); - free(descriptionBuf); - } - task->lastFailure = entitlementErrno; // was overwritten by csops_task(CS_OPS_STATUS) above - - // EINVAL is what the kernel says for unsigned code, so we'll have to let that pass - if (entitlementErrno == EINVAL) { - task->entitlementsLoaded = true; - return true; - } - ret = entitlementErrno; // what really went wrong - goto out; // bail out - } + if (cs_flags != 0) { // was signed + pid_t pid; + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); + syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, pid=%d", entitlementErrno, cs_flags, pid); // to ease diagnostics + + CFStringRef description = SecTaskCopyDebugDescription(task); + char *descriptionBuf = NULL; + CFIndex descriptionSize = CFStringGetLength(description) * 4; + descriptionBuf = (char *)malloc(descriptionSize); + if (!CFStringGetCString(description, descriptionBuf, descriptionSize, kCFStringEncodingUTF8)) { + descriptionBuf[0] = 0; + } + + syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf); + CFReleaseNull(description); + free(descriptionBuf); + } + task->lastFailure = entitlementErrno; // was overwritten by csops_task(CS_OPS_STATUS) above + + // EINVAL is what the kernel says for unsigned code, so we'll have to let that pass + if (entitlementErrno == EINVAL) { + task->entitlementsLoaded = true; + return true; + } + ret = entitlementErrno; // what really went wrong + goto out; // bail out + } bufferlen = ntohl(header.length); /* check for insane values */ if (bufferlen > 1024 * 1024 || bufferlen < 8) { @@ -270,10 +297,17 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) entitlements = (CFMutableDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, NULL, error); CFReleaseNull(data); - if((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){ + if ((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){ ret = EDOM; // don't use EINVAL here; it conflates problems with syscall error returns goto out; } + + bool entitlementsModified = updateCatalystEntitlements(entitlements); + if (entitlementsModified) { + pid_t pid; + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); + secinfo("SecTask", "Fixed catalyst entitlements for process %d", pid); + } } task->entitlements = entitlements ? CFRetain(entitlements) : NULL; @@ -342,7 +376,7 @@ out: return values; } -#if TARGET_OS_OSX +#if SEC_OS_OSX /* * Determine if the given task meets a specified requirement. */ @@ -373,13 +407,16 @@ SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) return status; } -#endif /* TARGET_OS_OSX */ +#endif /* SEC_OS_OSX */ Boolean SecTaskEntitlementsValidated(SecTaskRef task) { // TODO: Cache the result uint32_t csflags = 0; const uint32_t mask = CS_VALID | CS_KILL | CS_ENTITLEMENTS_VALIDATED; + const uint32_t debug_mask = CS_DEBUGGED | CS_ENTITLEMENTS_VALIDATED; int rc = csops_task(task, CS_OPS_STATUS, &csflags, sizeof(csflags)); - return rc != -1 && ((csflags & mask) == mask); + // Allow debugged processes that were valid to continue being treated as valid + // We need this all the time (not just on internal) because third parties may need to debug their entitled process in xcode + return (rc != -1) && ((mask & csflags) == mask || (debug_mask & csflags) == debug_mask); }