codesign-watch.d   [plain text]


#!/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);
}