]> git.saurik.com Git - apple/libsecurity_codesigning.git/blobdiff - lib/cskernel.cpp
libsecurity_codesigning-55037.15.tar.gz
[apple/libsecurity_codesigning.git] / lib / cskernel.cpp
index bd39355d668f81f92909d1e27e94664fef29519b..9821465db9645e6482c38e0ce331cc31ee0001ad 100644 (file)
  */
 
 //
-// cskernel - Kernel implementation of the Code Signing Host Interface
+// cskernel - Kernel implementation of the Code Signing Host Interface.
+//
+// The kernel host currently supports only UNIX processes as guests.
+// It tracks then by their pid. Perhaps one day we'll get a more stable
+// means of tracking processes that doesn't involve reusing identifiers.
+//
+// The kernel host could represent non-process guests one day. One candidate
+// are Kernel Extensions.
 //
 #include "cskernel.h"
 #include "csprocess.h"
 #include "kerneldiskrep.h"
+#include "machorep.h"
 #include <libproc.h>
 #include <sys/codesign.h>
 #include <sys/param.h> // MAXPATHLEN
@@ -58,10 +66,11 @@ KernelStaticCode::KernelStaticCode()
 
 
 //
-// We locate a guest (process) by invoking a kernel service.
-// The only attributes supported are ("pid", pid_t).
-// (We could also support task ports if we liked, but those can be translated
-// to pids by the caller without trouble.)
+// Identify our guests (UNIX processes) by attribute.
+// The only supported lookup attribute is currently the pid. (We could support
+// task ports, but those can easily be mapped to pids.)
+// Note that we don't actually validate the pid here; if it's invalid, we'll notice
+// when we try to ask the kernel about it later.
 //
 SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
 {
@@ -78,14 +87,36 @@ SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
 
 //
 // We map guests to disk by calling a kernel service.
+// It is here that we verify that our user-space concept of the code identity
+// matches the kernel's idea (to defeat just-in-time switching attacks).
 //
-SecStaticCode *KernelCode::mapGuestToStatic(SecCode *iguest)
+SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
 {
        if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
                char path[2 * MAXPATHLEN];      // reasonable upper limit
-               if (::proc_pidpath(guest->pid(), path, sizeof(path)))
-                       return (new ProcessStaticCode(DiskRep::bestGuess(path)))->retain();
-               else
+               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, offset));
+                       CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
+                       if (cdhash) {
+                               SHA1::Digest kernelHash;
+                               if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
+                                       switch (errno) {
+                                       case EBADEXEC:          // means "no CodeDirectory hash for this program"
+                                               *cdhash = NULL;
+                                               break;
+                                       case ESRCH:
+                                               MacOSError::throwMe(errSecCSNoSuchCode);
+                                       default:
+                                               UnixError::throwMe();
+                                       }
+                               else    // succeeded
+                                       *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
+                               CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
+                       }
+                       return code.yield();
+               } else
                        UnixError::throwMe();
        }
        MacOSError::throwMe(errSecCSNoSuchCode);
@@ -95,41 +126,68 @@ SecStaticCode *KernelCode::mapGuestToStatic(SecCode *iguest)
 //
 // We obtain the guest's status by asking the kernel
 //
-uint32_t KernelCode::getGuestStatus(SecCode *iguest)
+SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
 {
        if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
                uint32_t pFlags;
-               if (::csops(guest->pid(), CS_OPS_STATUS, &pFlags, 0) == -1) {
-                       secdebug("kcode", "cannot get guest status of %p(%d) errno=%d",
-                               guest, guest->pid(), errno);
-                       switch (errno) {
-                       case ESRCH:
-                               MacOSError::throwMe(errSecCSNoSuchCode);
-                       default:
-                               UnixError::throwMe();
-                       }
-               }
+               csops(guest, CS_OPS_STATUS, &pFlags);
                secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
-               
-#if defined(USERSPACE_VALIDATION)
-               // Former static substitute for dynamic kernel validation of executable pages.
-               // This is now done in the kernel's page-in path.
-               guest->staticCode()->validateExecutable();
-#endif //USERSPACE_VALIDATION
-               
                return pFlags;
        } else
                MacOSError::throwMe(errSecCSNoSuchCode);
 }
 
 
+//
+// We tell the kernel to make status changes
+//
+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);
+}
+
+
 //
 // The StaticCode for the running kernel is explicit.
 // We can't ask our own host for it, naturally.
 //
-SecStaticCode *KernelCode::getStaticCode()
+void KernelCode::identify()
 {
-       return globals().staticCode->retain();
+       mStaticCode.take(globals().staticCode->retain());
+       // the kernel isn't currently signed, so we don't get a cdHash for it
+}
+
+
+//
+// Interface to kernel csops() system call.
+//
+void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
+{
+       if (::csops(proc->pid(), op, addr, length) == -1) {
+               switch (errno) {
+               case ESRCH:
+                       MacOSError::throwMe(errSecCSNoSuchCode);
+               default:
+                       UnixError::throwMe();
+               }
+       }
 }