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