X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/fa7225c82381bac4432a6edf16f53b5370238d85..bf028f67fd3bb2266df81b80fb6f25a77112e308:/sectask/SecTask.c diff --git a/sectask/SecTask.c b/sectask/SecTask.c index 70917b98..a73416c7 100644 --- a/sectask/SecTask.c +++ b/sectask/SecTask.c @@ -22,6 +22,7 @@ */ #include "SecTask.h" +#include "SecTaskPriv.h" #include @@ -34,18 +35,20 @@ #include #include #include +#include -#define USE_LIBPROC 0 -#if USE_LIBPROC -#include -#else #include -#endif + +#if TARGET_OS_OSX +/* These won't exist until we unify codesigning */ +#include +#include +#include +#endif /* TARGET_OS_OSX */ struct __SecTask { CFRuntimeBase base; - pid_t pid_self; audit_token_t token; /* Track whether we've loaded entitlements independently since after the @@ -64,11 +67,7 @@ static bool check_task(SecTaskRef task) { static void SecTaskFinalize(CFTypeRef cfTask) { SecTaskRef task = (SecTaskRef) cfTask; - - if (task->entitlements != NULL) { - CFRelease(task->entitlements); - task->entitlements = NULL; - } + CFReleaseNull(task->entitlements); } @@ -79,17 +78,8 @@ static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask) { SecTaskRef task = (SecTaskRef) cfTask; pid_t pid; - if (task->pid_self==-1) { - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - } else { - pid = task->pid_self; - } + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); -#if USE_LIBPROC -#define MAX_PROCNAME 32 - char task_name[MAX_PROCNAME + 1] = {}; - proc_name(pid, task_name, MAX_PROCNAME); -#else const char *task_name; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; struct kinfo_proc kp; @@ -98,7 +88,6 @@ static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask) task_name = strerror(errno); else task_name = kp.kp_proc.p_comm; -#endif return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("%s[%" PRIdPID "]/%d#%d LF=%d"), task_name, pid, task->entitlementsLoaded, task->entitlements ? (int)CFDictionaryGetCount(task->entitlements) : -1, task->lastFailure); @@ -117,10 +106,15 @@ SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator) SecTaskRef task = init_task_ref(allocator); if (task != NULL) { - memset(&task->token, 0, sizeof(task->token)); - task->entitlementsLoaded = false; - task->entitlements = NULL; - task->pid_self = getpid(); + kern_return_t kr = KERN_FAILURE; + mach_msg_type_number_t autoken_cnt = TASK_AUDIT_TOKEN_COUNT; + kr = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)&task->token, &autoken_cnt); + if (kr == KERN_SUCCESS) { + task->entitlementsLoaded = false; + task->entitlements = NULL; + } else { + CFReleaseNull(task); + } } return task; @@ -134,12 +128,26 @@ SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t t memcpy(&task->token, &token, sizeof(token)); task->entitlementsLoaded = false; task->entitlements = NULL; - task->pid_self = -1; } 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; @@ -149,19 +157,17 @@ static int csops_task(SecTaskRef task, int ops, void *blob, size_t size) { int rc; - if (task->pid_self==-1) { - pid_t pid; - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - rc = csops_audittoken(pid, ops, blob, size, &task->token); - } - else - rc = csops(task->pid_self, ops, blob, size); + + pid_t pid; + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); + rc = csops_audittoken(pid, ops, blob, size, &task->token); + task->lastFailure = (rc == -1) ? errno : 0; return rc; } -CFStringRef -SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) +static CFStringRef +SecTaskCopyIdentifier(SecTaskRef task, int op, CFErrorRef *error) { CFStringRef signingId = NULL; char *data = NULL; @@ -169,7 +175,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; @@ -184,7 +190,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; @@ -202,6 +208,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) { @@ -232,7 +250,10 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) } if (cs_flags != 0) { // was signed - syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, task->pid_self=%d", entitlementErrno, cs_flags, task->pid_self); // to ease diagnostics + + 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; @@ -243,7 +264,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) } syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf); - CFRelease(description); + CFReleaseNull(description); free(descriptionBuf); } task->lastFailure = entitlementErrno; // was overwritten by csops_task(CS_OPS_STATUS) above @@ -275,7 +296,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer+8, bufferlen-8, kCFAllocatorNull); entitlements = (CFMutableDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, NULL, error); - CFRelease(data); + CFReleaseNull(data); if((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){ ret = EDOM; // don't use EINVAL here; it conflates problems with syscall error returns @@ -287,8 +308,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) task->entitlementsLoaded = true; out: - if(entitlements) - CFRelease(entitlements); + CFReleaseNull(entitlements); if(buffer) free(buffer); if (ret && error && *error==NULL) @@ -349,3 +369,48 @@ CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef ent out: return values; } + +#if SEC_OS_OSX +/* + * Determine if the given task meets a specified requirement. + */ +OSStatus +SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) +{ + OSStatus status; + SecCodeRef code = NULL; + SecRequirementRef req = NULL; + + CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDataRef auditData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&task->token, sizeof(audit_token_t)); + CFDictionarySetValue(codeDict, kSecGuestAttributeAudit, auditData); + status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &code); + CFReleaseNull(codeDict); + CFReleaseNull(auditData); + + if (!status) { + status = SecRequirementCreateWithString(requirement, + kSecCSDefaultFlags, &req); + } + if (!status) { + status = SecCodeCheckValidity(code, kSecCSDefaultFlags, req); + } + + CFReleaseNull(req); + CFReleaseNull(code); + + return status; +} +#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)); + // 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); +} +