Print this page
2917 DTrace in a zone should have limited provider access
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/intel/dtrace/sdt.c
+++ new/usr/src/uts/intel/dtrace/sdt.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 +/*
27 + * Copyright (c) 2012, Joyent, Inc. All rights reserved.
28 + */
26 29
27 30 #include <sys/modctl.h>
28 31 #include <sys/sunddi.h>
29 32 #include <sys/dtrace.h>
30 33 #include <sys/kobj.h>
31 34 #include <sys/stat.h>
32 35 #include <sys/conf.h>
33 36 #include <vm/seg_kmem.h>
34 37 #include <sys/stack.h>
35 38 #include <sys/frame.h>
36 39 #include <sys/dtrace_impl.h>
37 40 #include <sys/cmn_err.h>
38 41 #include <sys/sysmacros.h>
39 42 #include <sys/privregs.h>
40 43 #include <sys/sdt_impl.h>
41 44
42 45 #define SDT_PATCHVAL 0xf0
43 46 #define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask)
44 47 #define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */
45 48
46 49 static dev_info_t *sdt_devi;
47 50 static int sdt_verbose = 0;
48 51 static sdt_probe_t **sdt_probetab;
49 52 static int sdt_probetab_size;
50 53 static int sdt_probetab_mask;
51 54
52 55 /*ARGSUSED*/
53 56 static int
54 57 sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
55 58 {
56 59 uintptr_t stack0, stack1, stack2, stack3, stack4;
57 60 int i = 0;
58 61 sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)];
59 62
60 63 #ifdef __amd64
61 64 /*
62 65 * On amd64, stack[0] contains the dereferenced stack pointer,
63 66 * stack[1] contains savfp, stack[2] contains savpc. We want
64 67 * to step over these entries.
65 68 */
66 69 i += 3;
67 70 #endif
68 71
69 72 for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
70 73 if ((uintptr_t)sdt->sdp_patchpoint == addr) {
71 74 /*
72 75 * When accessing the arguments on the stack, we must
73 76 * protect against accessing beyond the stack. We can
74 77 * safely set NOFAULT here -- we know that interrupts
75 78 * are already disabled.
76 79 */
77 80 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
78 81 stack0 = stack[i++];
79 82 stack1 = stack[i++];
80 83 stack2 = stack[i++];
81 84 stack3 = stack[i++];
82 85 stack4 = stack[i++];
83 86 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
84 87 CPU_DTRACE_BADADDR);
85 88
86 89 dtrace_probe(sdt->sdp_id, stack0, stack1,
87 90 stack2, stack3, stack4);
88 91
89 92 return (DTRACE_INVOP_NOP);
90 93 }
91 94 }
92 95
93 96 return (0);
94 97 }
95 98
96 99 /*ARGSUSED*/
97 100 static void
98 101 sdt_provide_module(void *arg, struct modctl *ctl)
99 102 {
100 103 struct module *mp = ctl->mod_mp;
101 104 char *modname = ctl->mod_modname;
102 105 sdt_probedesc_t *sdpd;
103 106 sdt_probe_t *sdp, *old;
104 107 sdt_provider_t *prov;
105 108 int len;
106 109
107 110 /*
108 111 * One for all, and all for one: if we haven't yet registered all of
109 112 * our providers, we'll refuse to provide anything.
110 113 */
111 114 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
112 115 if (prov->sdtp_id == DTRACE_PROVNONE)
113 116 return;
114 117 }
115 118
116 119 if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL)
117 120 return;
118 121
119 122 for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) {
120 123 char *name = sdpd->sdpd_name, *func, *nname;
121 124 int i, j;
122 125 sdt_provider_t *prov;
123 126 ulong_t offs;
124 127 dtrace_id_t id;
125 128
126 129 for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) {
127 130 char *prefix = prov->sdtp_prefix;
128 131
129 132 if (strncmp(name, prefix, strlen(prefix)) == 0) {
130 133 name += strlen(prefix);
131 134 break;
132 135 }
133 136 }
134 137
135 138 nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP);
136 139
137 140 for (i = 0, j = 0; name[j] != '\0'; i++) {
138 141 if (name[j] == '_' && name[j + 1] == '_') {
139 142 nname[i] = '-';
140 143 j += 2;
141 144 } else {
142 145 nname[i] = name[j++];
143 146 }
144 147 }
145 148
146 149 nname[i] = '\0';
147 150
148 151 sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP);
149 152 sdp->sdp_loadcnt = ctl->mod_loadcnt;
150 153 sdp->sdp_ctl = ctl;
151 154 sdp->sdp_name = nname;
152 155 sdp->sdp_namelen = len;
153 156 sdp->sdp_provider = prov;
154 157
155 158 func = kobj_searchsym(mp, sdpd->sdpd_offset, &offs);
156 159
157 160 if (func == NULL)
158 161 func = "<unknown>";
159 162
160 163 /*
161 164 * We have our provider. Now create the probe.
162 165 */
163 166 if ((id = dtrace_probe_lookup(prov->sdtp_id, modname,
164 167 func, nname)) != DTRACE_IDNONE) {
165 168 old = dtrace_probe_arg(prov->sdtp_id, id);
166 169 ASSERT(old != NULL);
167 170
168 171 sdp->sdp_next = old->sdp_next;
169 172 sdp->sdp_id = id;
170 173 old->sdp_next = sdp;
171 174 } else {
172 175 sdp->sdp_id = dtrace_probe_create(prov->sdtp_id,
173 176 modname, func, nname, 3, sdp);
174 177
175 178 mp->sdt_nprobes++;
176 179 }
177 180
178 181 sdp->sdp_hashnext =
179 182 sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)];
180 183 sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp;
181 184
182 185 sdp->sdp_patchval = SDT_PATCHVAL;
183 186 sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset;
184 187 sdp->sdp_savedval = *sdp->sdp_patchpoint;
185 188 }
186 189 }
187 190
188 191 /*ARGSUSED*/
189 192 static void
190 193 sdt_destroy(void *arg, dtrace_id_t id, void *parg)
191 194 {
192 195 sdt_probe_t *sdp = parg, *old, *last, *hash;
193 196 struct modctl *ctl = sdp->sdp_ctl;
194 197 int ndx;
195 198
196 199 if (ctl != NULL && ctl->mod_loadcnt == sdp->sdp_loadcnt) {
197 200 if ((ctl->mod_loadcnt == sdp->sdp_loadcnt &&
198 201 ctl->mod_loaded)) {
199 202 ((struct module *)(ctl->mod_mp))->sdt_nprobes--;
200 203 }
201 204 }
202 205
203 206 while (sdp != NULL) {
204 207 old = sdp;
205 208
206 209 /*
207 210 * Now we need to remove this probe from the sdt_probetab.
208 211 */
209 212 ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint);
210 213 last = NULL;
211 214 hash = sdt_probetab[ndx];
212 215
213 216 while (hash != sdp) {
214 217 ASSERT(hash != NULL);
215 218 last = hash;
216 219 hash = hash->sdp_hashnext;
217 220 }
218 221
219 222 if (last != NULL) {
220 223 last->sdp_hashnext = sdp->sdp_hashnext;
221 224 } else {
222 225 sdt_probetab[ndx] = sdp->sdp_hashnext;
223 226 }
224 227
225 228 kmem_free(sdp->sdp_name, sdp->sdp_namelen);
226 229 sdp = sdp->sdp_next;
227 230 kmem_free(old, sizeof (sdt_probe_t));
228 231 }
229 232 }
230 233
231 234 /*ARGSUSED*/
232 235 static int
233 236 sdt_enable(void *arg, dtrace_id_t id, void *parg)
234 237 {
235 238 sdt_probe_t *sdp = parg;
236 239 struct modctl *ctl = sdp->sdp_ctl;
237 240
238 241 ctl->mod_nenabled++;
239 242
240 243 /*
241 244 * If this module has disappeared since we discovered its probes,
242 245 * refuse to enable it.
243 246 */
244 247 if (!ctl->mod_loaded) {
245 248 if (sdt_verbose) {
246 249 cmn_err(CE_NOTE, "sdt is failing for probe %s "
247 250 "(module %s unloaded)",
248 251 sdp->sdp_name, ctl->mod_modname);
249 252 }
250 253 goto err;
251 254 }
252 255
253 256 /*
254 257 * Now check that our modctl has the expected load count. If it
255 258 * doesn't, this module must have been unloaded and reloaded -- and
256 259 * we're not going to touch it.
257 260 */
258 261 if (ctl->mod_loadcnt != sdp->sdp_loadcnt) {
259 262 if (sdt_verbose) {
260 263 cmn_err(CE_NOTE, "sdt is failing for probe %s "
261 264 "(module %s reloaded)",
262 265 sdp->sdp_name, ctl->mod_modname);
263 266 }
264 267 goto err;
265 268 }
266 269
267 270 while (sdp != NULL) {
268 271 *sdp->sdp_patchpoint = sdp->sdp_patchval;
269 272 sdp = sdp->sdp_next;
270 273 }
271 274 err:
272 275 return (0);
273 276 }
274 277
275 278 /*ARGSUSED*/
276 279 static void
277 280 sdt_disable(void *arg, dtrace_id_t id, void *parg)
278 281 {
279 282 sdt_probe_t *sdp = parg;
280 283 struct modctl *ctl = sdp->sdp_ctl;
281 284
282 285 ctl->mod_nenabled--;
283 286
284 287 if (!ctl->mod_loaded || ctl->mod_loadcnt != sdp->sdp_loadcnt)
285 288 goto err;
286 289
287 290 while (sdp != NULL) {
288 291 *sdp->sdp_patchpoint = sdp->sdp_savedval;
289 292 sdp = sdp->sdp_next;
290 293 }
291 294
292 295 err:
293 296 ;
294 297 }
295 298
296 299 /*ARGSUSED*/
297 300 uint64_t
298 301 sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
299 302 {
300 303 uintptr_t val;
301 304 struct frame *fp = (struct frame *)dtrace_getfp();
302 305 uintptr_t *stack;
303 306 int i;
304 307 #if defined(__amd64)
305 308 /*
306 309 * A total of 6 arguments are passed via registers; any argument with
307 310 * index of 5 or lower is therefore in a register.
308 311 */
309 312 int inreg = 5;
310 313 #endif
311 314
312 315 for (i = 1; i <= aframes; i++) {
313 316 fp = (struct frame *)(fp->fr_savfp);
314 317
315 318 if (fp->fr_savpc == (pc_t)dtrace_invop_callsite) {
316 319 #if !defined(__amd64)
317 320 /*
318 321 * If we pass through the invalid op handler, we will
319 322 * use the pointer that it passed to the stack as the
320 323 * second argument to dtrace_invop() as the pointer to
321 324 * the stack.
322 325 */
323 326 stack = ((uintptr_t **)&fp[1])[1];
324 327 #else
325 328 /*
326 329 * In the case of amd64, we will use the pointer to the
327 330 * regs structure that was pushed when we took the
328 331 * trap. To get this structure, we must increment
329 332 * beyond the frame structure. If the argument that
330 333 * we're seeking is passed on the stack, we'll pull
331 334 * the true stack pointer out of the saved registers
332 335 * and decrement our argument by the number of
333 336 * arguments passed in registers; if the argument
334 337 * we're seeking is passed in regsiters, we can just
335 338 * load it directly.
336 339 */
337 340 struct regs *rp = (struct regs *)((uintptr_t)&fp[1] +
338 341 sizeof (uintptr_t));
339 342
340 343 if (argno <= inreg) {
341 344 stack = (uintptr_t *)&rp->r_rdi;
342 345 } else {
343 346 stack = (uintptr_t *)(rp->r_rsp);
344 347 argno -= (inreg + 1);
345 348 }
346 349 #endif
347 350 goto load;
348 351 }
349 352 }
350 353
351 354 /*
352 355 * We know that we did not come through a trap to get into
353 356 * dtrace_probe() -- the provider simply called dtrace_probe()
354 357 * directly. As this is the case, we need to shift the argument
355 358 * that we're looking for: the probe ID is the first argument to
356 359 * dtrace_probe(), so the argument n will actually be found where
357 360 * one would expect to find argument (n + 1).
358 361 */
359 362 argno++;
360 363
361 364 #if defined(__amd64)
362 365 if (argno <= inreg) {
363 366 /*
364 367 * This shouldn't happen. If the argument is passed in a
365 368 * register then it should have been, well, passed in a
366 369 * register...
367 370 */
368 371 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
369 372 return (0);
370 373 }
371 374
372 375 argno -= (inreg + 1);
373 376 #endif
374 377 stack = (uintptr_t *)&fp[1];
375 378
376 379 load:
377 380 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
378 381 val = stack[argno];
379 382 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
380 383
381 384 return (val);
382 385 }
383 386
384 387 static dtrace_pops_t sdt_pops = {
385 388 NULL,
386 389 sdt_provide_module,
387 390 sdt_enable,
388 391 sdt_disable,
389 392 NULL,
390 393 NULL,
391 394 sdt_getargdesc,
392 395 sdt_getarg,
393 396 NULL,
394 397 sdt_destroy
395 398 };
396 399
397 400 /*ARGSUSED*/
398 401 static int
399 402 sdt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
400 403 {
401 404 sdt_provider_t *prov;
402 405
403 406 if (ddi_create_minor_node(devi, "sdt", S_IFCHR,
404 407 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
405 408 cmn_err(CE_NOTE, "/dev/sdt couldn't create minor node");
406 409 ddi_remove_minor_node(devi, NULL);
407 410 return (DDI_FAILURE);
408 411 }
409 412
410 413 ddi_report_dev(devi);
411 414 sdt_devi = devi;
↓ open down ↓ |
376 lines elided |
↑ open up ↑ |
412 415
413 416 if (sdt_probetab_size == 0)
414 417 sdt_probetab_size = SDT_PROBETAB_SIZE;
415 418
416 419 sdt_probetab_mask = sdt_probetab_size - 1;
417 420 sdt_probetab =
418 421 kmem_zalloc(sdt_probetab_size * sizeof (sdt_probe_t *), KM_SLEEP);
419 422 dtrace_invop_add(sdt_invop);
420 423
421 424 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
425 + uint32_t priv;
426 +
427 + if (prov->sdtp_priv == DTRACE_PRIV_NONE) {
428 + priv = DTRACE_PRIV_KERNEL;
429 + sdt_pops.dtps_mode = NULL;
430 + } else {
431 + priv = prov->sdtp_priv;
432 + ASSERT(priv == DTRACE_PRIV_USER);
433 + sdt_pops.dtps_mode = sdt_mode;
434 + }
435 +
422 436 if (dtrace_register(prov->sdtp_name, prov->sdtp_attr,
423 - DTRACE_PRIV_KERNEL, NULL,
424 - &sdt_pops, prov, &prov->sdtp_id) != 0) {
437 + priv, NULL, &sdt_pops, prov, &prov->sdtp_id) != 0) {
425 438 cmn_err(CE_WARN, "failed to register sdt provider %s",
426 439 prov->sdtp_name);
427 440 }
428 441 }
429 442
430 443 return (DDI_SUCCESS);
431 444 }
432 445
433 446 /*ARGSUSED*/
434 447 static int
435 448 sdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
436 449 {
437 450 sdt_provider_t *prov;
438 451
439 452 switch (cmd) {
440 453 case DDI_DETACH:
441 454 break;
442 455
443 456 case DDI_SUSPEND:
444 457 return (DDI_SUCCESS);
445 458
446 459 default:
447 460 return (DDI_FAILURE);
448 461 }
449 462
450 463 for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
451 464 if (prov->sdtp_id != DTRACE_PROVNONE) {
452 465 if (dtrace_unregister(prov->sdtp_id) != 0)
453 466 return (DDI_FAILURE);
454 467
455 468 prov->sdtp_id = DTRACE_PROVNONE;
456 469 }
457 470 }
458 471
459 472 dtrace_invop_remove(sdt_invop);
460 473 kmem_free(sdt_probetab, sdt_probetab_size * sizeof (sdt_probe_t *));
461 474
462 475 return (DDI_SUCCESS);
463 476 }
464 477
465 478 /*ARGSUSED*/
466 479 static int
467 480 sdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
468 481 {
469 482 int error;
470 483
471 484 switch (infocmd) {
472 485 case DDI_INFO_DEVT2DEVINFO:
473 486 *result = (void *)sdt_devi;
474 487 error = DDI_SUCCESS;
475 488 break;
476 489 case DDI_INFO_DEVT2INSTANCE:
477 490 *result = (void *)0;
478 491 error = DDI_SUCCESS;
479 492 break;
480 493 default:
481 494 error = DDI_FAILURE;
482 495 }
483 496 return (error);
484 497 }
485 498
486 499 /*ARGSUSED*/
487 500 static int
488 501 sdt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
489 502 {
490 503 return (0);
491 504 }
492 505
493 506 static struct cb_ops sdt_cb_ops = {
494 507 sdt_open, /* open */
495 508 nodev, /* close */
496 509 nulldev, /* strategy */
497 510 nulldev, /* print */
498 511 nodev, /* dump */
499 512 nodev, /* read */
500 513 nodev, /* write */
501 514 nodev, /* ioctl */
502 515 nodev, /* devmap */
503 516 nodev, /* mmap */
504 517 nodev, /* segmap */
505 518 nochpoll, /* poll */
506 519 ddi_prop_op, /* cb_prop_op */
507 520 0, /* streamtab */
508 521 D_NEW | D_MP /* Driver compatibility flag */
509 522 };
510 523
511 524 static struct dev_ops sdt_ops = {
512 525 DEVO_REV, /* devo_rev, */
513 526 0, /* refcnt */
514 527 sdt_info, /* get_dev_info */
515 528 nulldev, /* identify */
516 529 nulldev, /* probe */
517 530 sdt_attach, /* attach */
518 531 sdt_detach, /* detach */
519 532 nodev, /* reset */
520 533 &sdt_cb_ops, /* driver operations */
521 534 NULL, /* bus operations */
522 535 nodev, /* dev power */
523 536 ddi_quiesce_not_needed, /* quiesce */
524 537 };
525 538
526 539 /*
527 540 * Module linkage information for the kernel.
528 541 */
529 542 static struct modldrv modldrv = {
530 543 &mod_driverops, /* module type (this is a pseudo driver) */
531 544 "Statically Defined Tracing", /* name of module */
532 545 &sdt_ops, /* driver ops */
533 546 };
534 547
535 548 static struct modlinkage modlinkage = {
536 549 MODREV_1,
537 550 (void *)&modldrv,
538 551 NULL
539 552 };
540 553
541 554 int
542 555 _init(void)
543 556 {
544 557 return (mod_install(&modlinkage));
545 558 }
546 559
547 560 int
548 561 _info(struct modinfo *modinfop)
549 562 {
550 563 return (mod_info(&modlinkage, modinfop));
551 564 }
552 565
553 566 int
554 567 _fini(void)
555 568 {
556 569 return (mod_remove(&modlinkage));
557 570 }
↓ open down ↓ |
123 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX