#include "cskernel.h"
#include "csprocess.h"
#include "kerneldiskrep.h"
#include "machorep.h"
#include <libproc.h>
#include <sys/codesign.h>
#include <bsm/libbsm.h>
#include <security_utilities/cfmunge.h>
#include <sys/param.h> // MAXPATHLEN
namespace Security {
namespace CodeSigning {
ModuleNexus<KernelCode::Globals> KernelCode::globals;
KernelCode::Globals::Globals()
{
code = new KernelCode;
staticCode = new KernelStaticCode;
}
KernelCode::KernelCode()
: SecCode(NULL)
{
}
KernelStaticCode::KernelStaticCode()
: SecStaticCode(new KernelDiskRep())
{
}
SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
{
CFNumberRef pidNumber = NULL;
CFDataRef auditData = NULL;
cfscan(attributes, "{%O=%NO}", kSecGuestAttributePid, &pidNumber);
cfscan(attributes, "{%O=%XO}", kSecGuestAttributeAudit, &auditData);
if (pidNumber == NULL && auditData == NULL)
MacOSError::throwMe(errSecCSUnsupportedGuestAttributes);
if (auditData && CFDataGetLength(auditData) != sizeof(audit_token_t))
MacOSError::throwMe(errSecCSInvalidAttributeValues);
pid_t pid = 0;
audit_token_t* audit = NULL;
if (pidNumber)
pid = cfNumber<pid_t>(pidNumber);
if (auditData)
audit = (audit_token_t*)CFDataGetBytePtr(auditData);
if (audit && pid == 0)
pid = audit_token_to_pid(*audit);
RefPointer<PidDiskRep> diskRep = NULL;
if (CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCode) != NULL) {
CFDataRef infoPlist = (CFDataRef)CFDictionaryGetValue(attributes, kSecGuestAttributeDynamicCodeInfoPlist);
if (infoPlist && CFGetTypeID(infoPlist) != CFDataGetTypeID())
MacOSError::throwMe(errSecCSInvalidAttributeValues);
try {
diskRep = new PidDiskRep(pid, infoPlist);
} catch (...) { }
}
return (new ProcessCode(pid, audit, diskRep))->retain();
}
SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
{
if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
if (guest->pidBased()) {
SecPointer<SecStaticCode> code = new ProcessDynamicCode(guest);
guest->pidBased()->setCredentials(code->codeDirectory());
SHA1::Digest kernelHash;
MacOSError::check(guest->csops(CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)));
*cdhash = makeCFData(kernelHash, sizeof(kernelHash));
return code.yield();
}
char path[2 * MAXPATHLEN]; if (::proc_pidpath(guest->pid(), path, sizeof(path))) {
off_t offset;
csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset));
SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, (size_t)offset));
CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
if (cdhash) {
SHA1::Digest kernelHash;
if (guest->csops(CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
switch (errno) {
case EBADEXEC: *cdhash = NULL;
break;
case ESRCH:
MacOSError::throwMe(errSecCSNoSuchCode);
default:
UnixError::throwMe();
}
else *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
}
return code.yield();
} else
UnixError::throwMe();
}
MacOSError::throwMe(errSecCSNoSuchCode);
}
SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
{
if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
uint32_t pFlags;
csops(guest, CS_OPS_STATUS, &pFlags);
secinfo("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
return pFlags;
} else
MacOSError::throwMe(errSecCSNoSuchCode);
}
void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
{
if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest))
switch (operation) {
case kSecCodeOperationNull:
break;
case kSecCodeOperationInvalidate:
csops(guest, CS_OPS_MARKINVALID);
break;
case kSecCodeOperationSetHard:
csops(guest, CS_OPS_MARKHARD);
break;
case kSecCodeOperationSetKill:
csops(guest, CS_OPS_MARKKILL);
break;
default:
MacOSError::throwMe(errSecCSUnimplemented);
}
else
MacOSError::throwMe(errSecCSNoSuchCode);
}
void KernelCode::identify()
{
mStaticCode.take(globals().staticCode->retain());
}
void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
{
if (proc->csops(op, addr, length) == -1) {
switch (errno) {
case ESRCH:
MacOSError::throwMe(errSecCSNoSuchCode);
default:
UnixError::throwMe();
}
}
}
} }