codesign-watch.d
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 */ 10 typedef uint64_t DTHandle; /* generic API handle (NOT a pointer) */ 11 typedef uint8_t Hash[20]; /* SHA-1 */ 12 13 typedef 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 */ 24 self 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 */ 48 struct { 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 */ 60 typedef 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; 67 DiskRep rep[DTHandle]; /* all the DiskReps we've seen */ 68 69 self uint64_t ctx; /* passes construction context, NULL if none */ 70 71 codesign$1:::diskrep-create-* /* preset none */ 72 { self->ctx = 0; } 73 74 codesign$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 83 codesign$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 93 codesign$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 105 codesign$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 117 codesign$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 126 self DiskRepContext *ctxp; 127 128 codesign$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 139 codesign$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 */ 150 typedef struct { 151 DTHandle me; 152 DTHandle host; 153 DTHandle staticCode; /* lazily acquired */ 154 uint8_t *hash; /* dynamic hash from identify() */ 155 } Code; 156 Code code[DTHandle]; 157 158 typedef struct { 159 DTHandle me; 160 DTHandle rep; 161 uint8_t *hash; /* static hash from ...::cdHash() */ 162 } StaticCode; 163 StaticCode staticCode[DTHandle]; 164 165 166 codesign$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 175 codesign$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 184 codesign$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 192 codesign$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 200 codesign$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 209 security_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 217 security_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 */ 229 codesign$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 237 codesign$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 245 codesign$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 */ 257 typedef struct { 258 DTHandle guest; 259 string path; 260 uint32_t status; 261 uint8_t *hash; 262 } SDGuest; 263 SDGuest guests[DTHandle, DTHandle]; /* host x guest */ 264 265 securityd*:::host-register 266 { 267 printf("%8u HOST DYNAMIC(%p,%d)\n", 268 timestamp, arg0, arg1); 269 } 270 271 securityd*:::host-proxy 272 { 273 printf("%8u HOST PROXY(%p,%d)\n", 274 timestamp, arg0, arg1); 275 } 276 277 securityd*:::host-unregister 278 { 279 printf("%8u HOST DESTROYED(%p)\n", 280 timestamp, arg0); 281 } 282 283 securityd*:::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 293 securityd*:::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 303 securityd*:::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 310 securityd*:::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 317 securityd*:::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 */ 328 codesign$1:::allocate-arch 329 { 330 printf("%8u %s[%d]%s(%s,%d)\n", 331 timestamp, execname, pid, probename, copyinstr(arg0), arg1); 332 } 333 334 codesign$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 340 codesign$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 347 codesign$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 */ 357 codesign$1:::eval-dynamic-start 358 { 359 printf("%8u %s[%d]%s(%p,%s)\n", 360 timestamp, execname, pid, probename, arg0, copyinstr(arg1)); 361 } 362 363 codesign$1:::eval-dynamic-end 364 { 365 printf("%8u %s[%d]%s(%p)\n", 366 timestamp, execname, pid, probename, arg0); 367 } 368