1#!/usr/sbin/dtrace -q -s
2/*
3 * Demonstration D script for watching Code Signing activity in the system
4 *
5 * As presented, this script will record and report all Code Signing activity
6 * in one process (argument=pid), or all processes (argument='*').
7 * You are encouraged to modify it as you will. (A good start is to comment out
8 * the print statements you don't like to see.)
9 */
10typedef uint64_t DTHandle;		/* generic API handle (NOT a pointer) */
11typedef uint8_t Hash[20];		/* SHA-1 */
12
13typedef struct {				/* from implementation */
14	uint32_t cputype;
15	uint32_t cpusubtype;
16	off_t offset;
17	uint8_t fileOnly;
18} DiskRepContext;
19
20
21/*
22 * Local variables used for suitable casting (only)
23 */
24self uint8_t *hash;
25
26
27/*
28 * Startup (this may take a while)
29 */
30:::BEGIN
31{
32	printf("Ready...\n");
33}
34
35
36/*
37 * Finishing (add statistics tracers here)
38 */
39:::END
40{
41}
42
43
44/*
45 * Track kernel-related objects.
46 * Each process has their own, and they're usually created very early.
47 */
48struct {
49	DTHandle rep;				/* DiskRep */
50	DTHandle staticCode;		/* static code */
51	DTHandle code;				/* dynamic code */
52} kernel[pid_t];
53
54
55/*
56 * Track DiskRep objects.
57 * DiskReps are drivers for on-disk formats. Beyond their natural concerns,
58 * they also carry the path information for StaticCode objects.
59 */
60typedef struct {
61	DTHandle me;				/* own handle, if valid */
62	string path;				/* canonical path */
63	string type;				/* type string */
64	DiskRepContext ctx;			/* construction context, if any */
65	DTHandle sub;				/* sub-DiskRep if any */
66} DiskRep;
67DiskRep rep[DTHandle];			/* all the DiskReps we've seen */
68
69self uint64_t ctx;				/* passes construction context, NULL if none */
70
71codesign$1:::diskrep-create-*	/* preset none */
72{ self->ctx = 0; }
73
74codesign$1:::diskrep-create-kernel
75{
76	rep[arg0].me = kernel[pid].rep = arg0;
77	rep[arg0].path = "(kernel)";
78	rep[arg0].type = "kernel";
79	printf("%8u %s[%d]%s(%p,KERNEL)\n",
80		timestamp, execname, pid, probename, arg0);
81}
82
83codesign$1:::diskrep-create-macho
84{
85	rep[arg0].me = arg0;
86	rep[arg0].path = copyinstr(arg1);
87	rep[arg0].type = "macho";
88	self->ctx = arg2;
89	printf("%8u %s[%d]%s(%p,%s)\n",
90		timestamp, execname, pid, probename, arg0, rep[arg0].path);
91}
92
93codesign$1:::diskrep-create-bundle-path
94{
95	rep[arg0].me = arg0;
96	rep[arg0].path = copyinstr(arg1);
97	rep[arg0].type = "bundle";
98	self->ctx = arg2;
99	rep[arg0].sub = arg3;
100	printf("%8u %s[%d]%s(%p,%s,%p)\n",
101		timestamp, execname, pid, probename,
102		arg0, rep[arg0].path, rep[arg0].sub);
103}
104
105codesign$1:::diskrep-create-bundle-ref
106{
107	rep[arg0].me = arg0;
108	rep[arg0].path = "(from ref)";
109	rep[arg0].type = "bundle";
110	self->ctx = arg2;
111	rep[arg0].sub = arg3;
112	printf("%8u %s[%d]%s(%p,%s,%p)\n",
113		timestamp, execname, pid, probename,
114		arg0, rep[arg0].path, rep[arg0].sub);
115}
116
117codesign$1:::diskrep-create-file
118{
119	rep[arg0].me = arg0;
120	rep[arg0].path = copyinstr(arg1);
121	rep[arg0].type = "file";
122	printf("%8u %s[%d]%s(%p,%s)\n",
123		timestamp, execname, pid, probename, arg0, rep[arg0].path);
124}
125
126self DiskRepContext *ctxp;
127
128codesign$1:::diskrep-create-*
129/ self->ctx /
130{
131	self->ctxp = (DiskRepContext *)copyin(self->ctx, sizeof(DiskRepContext));
132	rep[arg0].ctx = *self->ctxp;
133	printf("%8u %s[%d] ...context: arch=(0x%x,0x%x) offset=0x%x file=%d\n",
134		timestamp, execname, pid,
135		self->ctxp->cputype, self->ctxp->cpusubtype,
136		self->ctxp->offset, self->ctxp->fileOnly);
137}
138
139codesign$1:::diskrep-destroy
140{
141	printf("%8u %s[%d]%s(%p,%s)\n",
142		timestamp, execname, pid, probename, arg0, rep[arg0].path);
143	rep[arg0].me = 0;
144}
145
146
147/*
148 * Track Code Signing API objects
149 */
150typedef struct {
151	DTHandle me;
152	DTHandle host;
153	DTHandle staticCode;	/* lazily acquired */
154	uint8_t *hash;			/* dynamic hash from identify() */
155} Code;
156Code code[DTHandle];
157
158typedef struct {
159	DTHandle me;
160	DTHandle rep;
161	uint8_t *hash;			/* static hash from ...::cdHash() */
162} StaticCode;
163StaticCode staticCode[DTHandle];
164
165
166codesign$1:::static-create
167/ arg1 == kernel[pid].rep /
168{
169	staticCode[arg0].me = kernel[pid].staticCode = arg0;
170	staticCode[arg0].rep = arg1;
171	printf("%8u %s[%d]%s(%p=KERNEL[%p])\n",
172		timestamp, execname, pid, probename, arg0, arg1);
173}
174
175codesign$1:::static-create
176/ arg1 != kernel[pid].rep /
177{
178	staticCode[arg0].me = arg0;
179	staticCode[arg0].rep = arg1;
180	printf("%8u %s[%d]%s(%p,%s[%p])\n",
181		timestamp, execname, pid, probename, arg0, rep[arg1].path, arg1);
182}
183
184codesign$1:::dynamic-create
185/ arg1 == 0 /
186{
187	code[arg0].me = kernel[pid].code = arg0;
188	printf("%8u %s[%d]%s(%p=KERNEL)\n",
189		timestamp, execname, pid, probename, arg0);
190}
191
192codesign$1:::dynamic-create
193/ arg1 == kernel[pid].code /
194{
195	code[arg0].me = arg0;
196	printf("%8u %s[%d]%s(%p,<KERNEL>)\n",
197		timestamp, execname, pid, probename, arg0);
198}
199
200codesign$1:::dynamic-create
201/ arg1 != 0 && arg1 != kernel[pid].code /
202{
203	code[arg0].me = arg0;
204	code[arg0].host = arg1;
205	printf("%8u %s[%d]%s(%p,%p)\n",
206		timestamp, execname, pid, probename, arg0, arg1);
207}
208
209security_debug$1:::sec-destroy
210/ code[arg0].me == arg0 /
211{
212	code[arg0].me = 0;
213	printf("%8u %s[%d]destroy code(%p)\n",
214		timestamp, execname, pid, arg0);
215}
216
217security_debug$1:::sec-destroy
218/ staticCode[arg0].me == arg0 /
219{
220	staticCode[arg0].me = 0;
221	printf("%8u %s[%d]destroy staticCode(%p)\n",
222		timestamp, execname, pid, arg0);
223}
224
225
226/*
227 * Identification operations
228 */
229codesign$1:::guest-identify-*
230{
231	printf("%8u %s[%d]%s(%p,%d,%s[%p])\n",
232		timestamp, execname, pid, probename,
233		arg0, arg1, rep[staticCode[arg2].rep].path, arg2);
234	code[arg0].staticCode = arg2;
235}
236
237codesign$1:::guest-cdhash-*
238{
239	self->hash = code[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
240	printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
241		timestamp, execname, pid, probename, arg0,
242		self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
243}
244
245codesign$1:::static-cdhash
246{
247	self->hash = staticCode[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
248	printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
249		timestamp, execname, pid, probename, arg0,
250		self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
251}
252
253
254/*
255 * Guest registry/proxy management in securityd
256 */
257typedef struct {
258	DTHandle guest;
259	string path;
260	uint32_t status;
261	uint8_t *hash;
262} SDGuest;
263SDGuest guests[DTHandle, DTHandle];		/* host x guest */
264
265securityd*:::host-register
266{
267	printf("%8u HOST DYNAMIC(%p,%d)\n",
268		timestamp, arg0, arg1);
269}
270
271securityd*:::host-proxy
272{
273	printf("%8u HOST PROXY(%p,%d)\n",
274		timestamp, arg0, arg1);
275}
276
277securityd*:::host-unregister
278{
279	printf("%8u HOST DESTROYED(%p)\n",
280		timestamp, arg0);
281}
282
283securityd*:::guest-create
284{
285	guests[arg0, arg2].guest = arg2;
286	guests[arg0, arg2].path = copyinstr(arg5);
287	guests[arg0, arg2].status = arg3;
288	printf("%8u GUEST CREATE(%p,%s[0x%x],host=0x%x,status=0x%x,flags=%d)\n",
289		timestamp,
290		arg0, guests[arg0, arg2].path, arg2, arg1, arg3, arg4);
291}
292
293securityd*:::guest-cdhash
294/ arg2 != 0 /
295{
296	self->hash = guests[arg0, arg1].hash = (uint8_t *)copyin(arg2, sizeof(Hash));
297	printf("%8u GUEST HASH(%p,%s[0x%x],H\"%02x%02x%02x...%02x%02x\")\n",
298		timestamp,
299		arg0, guests[arg0, arg1].path, arg1,
300		self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
301}
302
303securityd*:::guest-cdhash
304/ arg2 == 0 /
305{
306	printf("%8u GUEST HASH(%p,%s[0x%x],NONE)\n",
307		timestamp, arg0, guests[arg0, arg1].path, arg1);
308}
309
310securityd*:::guest-change
311{
312	printf("%8u GUEST CHANGE(%p,%s[0x%x],status=0x%x)\n",
313		timestamp,
314		arg0, guests[arg0, arg1].path, arg1, arg2);
315}
316
317securityd*:::guest-destroy
318{
319	printf("%8u GUEST DESTROY(%p,%s[0x%x])\n",
320		timestamp,
321		arg0, guests[arg0, arg1].path, arg1);
322}
323
324
325/*
326 * Signing Mach-O allocation tracking
327 */
328codesign$1:::allocate-arch
329{
330	printf("%8u %s[%d]%s(%s,%d)\n",
331		timestamp, execname, pid, probename, copyinstr(arg0), arg1);
332}
333
334codesign$1:::allocate-archn
335{
336	printf("%8u %s[%d]%s((0x%x,0x%x),%d)\n",
337		timestamp, execname, pid, probename, arg0, arg1,  arg2);
338}
339
340codesign$1:::allocate-write
341{
342	printf("%8u %s[%d]%s(%s,offset 0x%x,%d of %d)\n",
343		timestamp, execname, pid, probename,
344		copyinstr(arg0), arg1, arg2, arg3);
345}
346
347codesign$1:::allocate-validate
348{
349	printf("%8u %s[%d]%s(%s,%d)\n",
350		timestamp, execname, pid, probename, copyinstr(arg0), arg1);
351}
352
353
354/*
355 * Evaluation tracking
356 */
357codesign$1:::eval-dynamic-start
358{
359	printf("%8u %s[%d]%s(%p,%s)\n",
360		timestamp, execname, pid, probename, arg0, copyinstr(arg1));
361}
362
363codesign$1:::eval-dynamic-end
364{
365	printf("%8u %s[%d]%s(%p)\n",
366		timestamp, execname, pid, probename, arg0);
367}
368
369