--- /dev/null
+#!/usr/sbin/dtrace -q -s
+/*
+ * Demonstration D script for watching Code Signing activity in the system
+ *
+ * As presented, this script will record and report all Code Signing activity
+ * in one process (argument=pid), or all processes (argument='*').
+ * You are encouraged to modify it as you will. (A good start is to comment out
+ * the print statements you don't like to see.)
+ */
+typedef uint64_t DTHandle; /* generic API handle (NOT a pointer) */
+typedef uint8_t Hash[20]; /* SHA-1 */
+
+typedef struct { /* from implementation */
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ off_t offset;
+ uint8_t fileOnly;
+} DiskRepContext;
+
+
+/*
+ * Local variables used for suitable casting (only)
+ */
+self uint8_t *hash;
+
+
+/*
+ * Startup (this may take a while)
+ */
+:::BEGIN
+{
+ printf("Ready...\n");
+}
+
+
+/*
+ * Finishing (add statistics tracers here)
+ */
+:::END
+{
+}
+
+
+/*
+ * Track kernel-related objects.
+ * Each process has their own, and they're usually created very early.
+ */
+struct {
+ DTHandle rep; /* DiskRep */
+ DTHandle staticCode; /* static code */
+ DTHandle code; /* dynamic code */
+} kernel[pid_t];
+
+
+/*
+ * Track DiskRep objects.
+ * DiskReps are drivers for on-disk formats. Beyond their natural concerns,
+ * they also carry the path information for StaticCode objects.
+ */
+typedef struct {
+ DTHandle me; /* own handle, if valid */
+ string path; /* canonical path */
+ string type; /* type string */
+ DiskRepContext ctx; /* construction context, if any */
+ DTHandle sub; /* sub-DiskRep if any */
+} DiskRep;
+DiskRep rep[DTHandle]; /* all the DiskReps we've seen */
+
+self uint64_t ctx; /* passes construction context, NULL if none */
+
+codesign$1:::diskrep-create-* /* preset none */
+{ self->ctx = 0; }
+
+codesign$1:::diskrep-create-kernel
+{
+ rep[arg0].me = kernel[pid].rep = arg0;
+ rep[arg0].path = "(kernel)";
+ rep[arg0].type = "kernel";
+ printf("%8u %s[%d]%s(%p,KERNEL)\n",
+ timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::diskrep-create-macho
+{
+ rep[arg0].me = arg0;
+ rep[arg0].path = copyinstr(arg1);
+ rep[arg0].type = "macho";
+ self->ctx = arg2;
+ printf("%8u %s[%d]%s(%p,%s)\n",
+ timestamp, execname, pid, probename, arg0, rep[arg0].path);
+}
+
+codesign$1:::diskrep-create-bundle-path
+{
+ rep[arg0].me = arg0;
+ rep[arg0].path = copyinstr(arg1);
+ rep[arg0].type = "bundle";
+ self->ctx = arg2;
+ rep[arg0].sub = arg3;
+ printf("%8u %s[%d]%s(%p,%s,%p)\n",
+ timestamp, execname, pid, probename,
+ arg0, rep[arg0].path, rep[arg0].sub);
+}
+
+codesign$1:::diskrep-create-bundle-ref
+{
+ rep[arg0].me = arg0;
+ rep[arg0].path = "(from ref)";
+ rep[arg0].type = "bundle";
+ self->ctx = arg2;
+ rep[arg0].sub = arg3;
+ printf("%8u %s[%d]%s(%p,%s,%p)\n",
+ timestamp, execname, pid, probename,
+ arg0, rep[arg0].path, rep[arg0].sub);
+}
+
+codesign$1:::diskrep-create-file
+{
+ rep[arg0].me = arg0;
+ rep[arg0].path = copyinstr(arg1);
+ rep[arg0].type = "file";
+ printf("%8u %s[%d]%s(%p,%s)\n",
+ timestamp, execname, pid, probename, arg0, rep[arg0].path);
+}
+
+self DiskRepContext *ctxp;
+
+codesign$1:::diskrep-create-*
+/ self->ctx /
+{
+ self->ctxp = (DiskRepContext *)copyin(self->ctx, sizeof(DiskRepContext));
+ rep[arg0].ctx = *self->ctxp;
+ printf("%8u %s[%d] ...context: arch=(0x%x,0x%x) offset=0x%x file=%d\n",
+ timestamp, execname, pid,
+ self->ctxp->cputype, self->ctxp->cpusubtype,
+ self->ctxp->offset, self->ctxp->fileOnly);
+}
+
+codesign$1:::diskrep-destroy
+{
+ printf("%8u %s[%d]%s(%p,%s)\n",
+ timestamp, execname, pid, probename, arg0, rep[arg0].path);
+ rep[arg0].me = 0;
+}
+
+
+/*
+ * Track Code Signing API objects
+ */
+typedef struct {
+ DTHandle me;
+ DTHandle host;
+ DTHandle staticCode; /* lazily acquired */
+ uint8_t *hash; /* dynamic hash from identify() */
+} Code;
+Code code[DTHandle];
+
+typedef struct {
+ DTHandle me;
+ DTHandle rep;
+ uint8_t *hash; /* static hash from ...::cdHash() */
+} StaticCode;
+StaticCode staticCode[DTHandle];
+
+
+codesign$1:::static-create
+/ arg1 == kernel[pid].rep /
+{
+ staticCode[arg0].me = kernel[pid].staticCode = arg0;
+ staticCode[arg0].rep = arg1;
+ printf("%8u %s[%d]%s(%p=KERNEL[%p])\n",
+ timestamp, execname, pid, probename, arg0, arg1);
+}
+
+codesign$1:::static-create
+/ arg1 != kernel[pid].rep /
+{
+ staticCode[arg0].me = arg0;
+ staticCode[arg0].rep = arg1;
+ printf("%8u %s[%d]%s(%p,%s[%p])\n",
+ timestamp, execname, pid, probename, arg0, rep[arg1].path, arg1);
+}
+
+codesign$1:::dynamic-create
+/ arg1 == 0 /
+{
+ code[arg0].me = kernel[pid].code = arg0;
+ printf("%8u %s[%d]%s(%p=KERNEL)\n",
+ timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::dynamic-create
+/ arg1 == kernel[pid].code /
+{
+ code[arg0].me = arg0;
+ printf("%8u %s[%d]%s(%p,<KERNEL>)\n",
+ timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::dynamic-create
+/ arg1 != 0 && arg1 != kernel[pid].code /
+{
+ code[arg0].me = arg0;
+ code[arg0].host = arg1;
+ printf("%8u %s[%d]%s(%p,%p)\n",
+ timestamp, execname, pid, probename, arg0, arg1);
+}
+
+security_debug$1:::sec-destroy
+/ code[arg0].me == arg0 /
+{
+ code[arg0].me = 0;
+ printf("%8u %s[%d]destroy code(%p)\n",
+ timestamp, execname, pid, arg0);
+}
+
+security_debug$1:::sec-destroy
+/ staticCode[arg0].me == arg0 /
+{
+ staticCode[arg0].me = 0;
+ printf("%8u %s[%d]destroy staticCode(%p)\n",
+ timestamp, execname, pid, arg0);
+}
+
+
+/*
+ * Identification operations
+ */
+codesign$1:::guest-identify-*
+{
+ printf("%8u %s[%d]%s(%p,%d,%s[%p])\n",
+ timestamp, execname, pid, probename,
+ arg0, arg1, rep[staticCode[arg2].rep].path, arg2);
+ code[arg0].staticCode = arg2;
+}
+
+codesign$1:::guest-cdhash-*
+{
+ self->hash = code[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
+ printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
+ timestamp, execname, pid, probename, arg0,
+ self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+codesign$1:::static-cdhash
+{
+ self->hash = staticCode[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
+ printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
+ timestamp, execname, pid, probename, arg0,
+ self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+
+/*
+ * Guest registry/proxy management in securityd
+ */
+typedef struct {
+ DTHandle guest;
+ string path;
+ uint32_t status;
+ uint8_t *hash;
+} SDGuest;
+SDGuest guests[DTHandle, DTHandle]; /* host x guest */
+
+securityd*:::host-register
+{
+ printf("%8u HOST DYNAMIC(%p,%d)\n",
+ timestamp, arg0, arg1);
+}
+
+securityd*:::host-proxy
+{
+ printf("%8u HOST PROXY(%p,%d)\n",
+ timestamp, arg0, arg1);
+}
+
+securityd*:::host-unregister
+{
+ printf("%8u HOST DESTROYED(%p)\n",
+ timestamp, arg0);
+}
+
+securityd*:::guest-create
+{
+ guests[arg0, arg2].guest = arg2;
+ guests[arg0, arg2].path = copyinstr(arg5);
+ guests[arg0, arg2].status = arg3;
+ printf("%8u GUEST CREATE(%p,%s[0x%x],host=0x%x,status=0x%x,flags=%d)\n",
+ timestamp,
+ arg0, guests[arg0, arg2].path, arg2, arg1, arg3, arg4);
+}
+
+securityd*:::guest-cdhash
+/ arg2 != 0 /
+{
+ self->hash = guests[arg0, arg1].hash = (uint8_t *)copyin(arg2, sizeof(Hash));
+ printf("%8u GUEST HASH(%p,%s[0x%x],H\"%02x%02x%02x...%02x%02x\")\n",
+ timestamp,
+ arg0, guests[arg0, arg1].path, arg1,
+ self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+securityd*:::guest-cdhash
+/ arg2 == 0 /
+{
+ printf("%8u GUEST HASH(%p,%s[0x%x],NONE)\n",
+ timestamp, arg0, guests[arg0, arg1].path, arg1);
+}
+
+securityd*:::guest-change
+{
+ printf("%8u GUEST CHANGE(%p,%s[0x%x],status=0x%x)\n",
+ timestamp,
+ arg0, guests[arg0, arg1].path, arg1, arg2);
+}
+
+securityd*:::guest-destroy
+{
+ printf("%8u GUEST DESTROY(%p,%s[0x%x])\n",
+ timestamp,
+ arg0, guests[arg0, arg1].path, arg1);
+}
+
+
+/*
+ * Signing Mach-O allocation tracking
+ */
+codesign$1:::allocate-arch
+{
+ printf("%8u %s[%d]%s(%s,%d)\n",
+ timestamp, execname, pid, probename, copyinstr(arg0), arg1);
+}
+
+codesign$1:::allocate-archn
+{
+ printf("%8u %s[%d]%s((0x%x,0x%x),%d)\n",
+ timestamp, execname, pid, probename, arg0, arg1, arg2);
+}
+
+codesign$1:::allocate-write
+{
+ printf("%8u %s[%d]%s(%s,offset 0x%x,%d of %d)\n",
+ timestamp, execname, pid, probename,
+ copyinstr(arg0), arg1, arg2, arg3);
+}
+
+codesign$1:::allocate-validate
+{
+ printf("%8u %s[%d]%s(%s,%d)\n",
+ timestamp, execname, pid, probename, copyinstr(arg0), arg1);
+}
+
+
+/*
+ * Evaluation tracking
+ */
+codesign$1:::eval-dynamic-start
+{
+ printf("%8u %s[%d]%s(%p,%s)\n",
+ timestamp, execname, pid, probename, arg0, copyinstr(arg1));
+}
+
+codesign$1:::eval-dynamic-end
+{
+ printf("%8u %s[%d]%s(%p)\n",
+ timestamp, execname, pid, probename, arg0);
+}
+