75 #include <sys/kmem.h>
76 #include <sys/strsubr.h>
77 #include <sys/sysmacros.h>
78 #include <sys/dtrace_impl.h>
79 #include <sys/atomic.h>
80 #include <sys/cmn_err.h>
81 #include <sys/mutex_impl.h>
82 #include <sys/rwlock_impl.h>
83 #include <sys/ctf_api.h>
84 #include <sys/panic.h>
85 #include <sys/priv_impl.h>
86 #include <sys/policy.h>
87 #include <sys/cred_impl.h>
88 #include <sys/procfs_isa.h>
89 #include <sys/taskq.h>
90 #include <sys/mkdev.h>
91 #include <sys/kdi.h>
92 #include <sys/zone.h>
93 #include <sys/socket.h>
94 #include <netinet/in.h>
95
96 /*
97 * DTrace Tunable Variables
98 *
99 * The following variables may be tuned by adding a line to /etc/system that
100 * includes both the name of the DTrace module ("dtrace") and the name of the
101 * variable. For example:
102 *
103 * set dtrace:dtrace_destructive_disallow = 1
104 *
105 * In general, the only variables that one should be tuning this way are those
106 * that affect system-wide DTrace behavior, and for which the default behavior
107 * is undesirable. Most of these variables are tunable on a per-consumer
108 * basis using DTrace options, and need not be tuned on a system-wide basis.
109 * When tuning these variables, avoid pathological values; while some attempt
110 * is made to verify the integrity of these variables, they are not considered
111 * part of the supported interface to DTrace, and they are therefore not
112 * checked comprehensively. Further, these variables should not be tuned
113 * dynamically via "mdb -kw" or other means; they should only be tuned via
114 * /etc/system.
842 size_t sz;
843 ASSERT(type->dtdt_flags & DIF_TF_BYREF);
844
845 /*
846 * If we hold the privilege to read from kernel memory, then
847 * everything is readable.
848 */
849 if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0)
850 return (1);
851
852 if (type->dtdt_kind == DIF_TYPE_STRING)
853 sz = dtrace_strlen(src,
854 vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE]) + 1;
855 else
856 sz = type->dtdt_size;
857
858 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
859 }
860
861 /*
862 * Compare two strings using safe loads.
863 */
864 static int
865 dtrace_strncmp(char *s1, char *s2, size_t limit)
866 {
867 uint8_t c1, c2;
868 volatile uint16_t *flags;
869
870 if (s1 == s2 || limit == 0)
871 return (0);
872
873 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
874
875 do {
876 if (s1 == NULL) {
877 c1 = '\0';
878 } else {
879 c1 = dtrace_load8((uintptr_t)s1++);
880 }
881
3318 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3319 return (0);
3320
3321 /*
3322 * It is always safe to dereference one's own t_lwp pointer in
3323 * the event that this pointer is non-NULL. (This is true
3324 * because threads and lwps don't clean up their own state --
3325 * they leave that task to whomever reaps them.)
3326 */
3327 if ((lwp = curthread->t_lwp) == NULL)
3328 return (0);
3329
3330 return ((uint64_t)lwp->lwp_errno);
3331 }
3332 default:
3333 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3334 return (0);
3335 }
3336 }
3337
3338 /*
3339 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3340 * Notice that we don't bother validating the proper number of arguments or
3341 * their types in the tuple stack. This isn't needed because all argument
3342 * interpretation is safe because of our load safety -- the worst that can
3343 * happen is that a bogus program can obtain bogus results.
3344 */
3345 static void
3346 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3347 dtrace_key_t *tupregs, int nargs,
3348 dtrace_mstate_t *mstate, dtrace_state_t *state)
3349 {
3350 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3351 volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3352 dtrace_vstate_t *vstate = &state->dts_vstate;
3353
3354 union {
3355 mutex_impl_t mi;
3356 uint64_t mx;
3357 } m;
4018 if (index >= len || index < 0) {
4019 remaining = 0;
4020 } else if (remaining < 0) {
4021 remaining += len - index;
4022 } else if (index + remaining > size) {
4023 remaining = size - index;
4024 }
4025
4026 for (i = 0; i < remaining; i++) {
4027 if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4028 break;
4029 }
4030
4031 d[i] = '\0';
4032
4033 mstate->dtms_scratch_ptr += size;
4034 regs[rd] = (uintptr_t)d;
4035 break;
4036 }
4037
4038 case DIF_SUBR_TOUPPER:
4039 case DIF_SUBR_TOLOWER: {
4040 uintptr_t s = tupregs[0].dttk_value;
4041 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4042 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4043 size_t len = dtrace_strlen((char *)s, size);
4044 char lower, upper, convert;
4045 int64_t i;
4046
4047 if (subr == DIF_SUBR_TOUPPER) {
4048 lower = 'a';
4049 upper = 'z';
4050 convert = 'A';
4051 } else {
4052 lower = 'A';
4053 upper = 'Z';
4054 convert = 'a';
4055 }
4056
4057 if (!dtrace_canload(s, len + 1, mstate, vstate)) {
4325
4326 for (;;) {
4327 if (i >= size) {
4328 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4329 regs[rd] = NULL;
4330 break;
4331 }
4332
4333 if ((d[i++] = dtrace_load8(s2++)) == '\0')
4334 break;
4335 }
4336
4337 if (i < size) {
4338 mstate->dtms_scratch_ptr += i;
4339 regs[rd] = (uintptr_t)d;
4340 }
4341
4342 break;
4343 }
4344
4345 case DIF_SUBR_LLTOSTR: {
4346 int64_t i = (int64_t)tupregs[0].dttk_value;
4347 uint64_t val, digit;
4348 uint64_t size = 65; /* enough room for 2^64 in binary */
4349 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4350 int base = 10;
4351
4352 if (nargs > 1) {
4353 if ((base = tupregs[1].dttk_value) <= 1 ||
4354 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4355 *flags |= CPU_DTRACE_ILLOP;
4356 break;
4357 }
4358 }
4359
4360 val = (base == 10 && i < 0) ? i * -1 : i;
4361
4362 if (!DTRACE_INSCRATCH(mstate, size)) {
4363 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4364 regs[rd] = NULL;
8844 case DIF_OP_LDTAA:
8845 err += efunc(pc, "illegal dynamic variable load\n");
8846 break;
8847
8848 case DIF_OP_STTS:
8849 case DIF_OP_STGAA:
8850 case DIF_OP_STTAA:
8851 err += efunc(pc, "illegal dynamic variable store\n");
8852 break;
8853
8854 case DIF_OP_CALL:
8855 if (subr == DIF_SUBR_ALLOCA ||
8856 subr == DIF_SUBR_BCOPY ||
8857 subr == DIF_SUBR_COPYIN ||
8858 subr == DIF_SUBR_COPYINTO ||
8859 subr == DIF_SUBR_COPYINSTR ||
8860 subr == DIF_SUBR_INDEX ||
8861 subr == DIF_SUBR_INET_NTOA ||
8862 subr == DIF_SUBR_INET_NTOA6 ||
8863 subr == DIF_SUBR_INET_NTOP ||
8864 subr == DIF_SUBR_LLTOSTR ||
8865 subr == DIF_SUBR_RINDEX ||
8866 subr == DIF_SUBR_STRCHR ||
8867 subr == DIF_SUBR_STRJOIN ||
8868 subr == DIF_SUBR_STRRCHR ||
8869 subr == DIF_SUBR_STRSTR ||
8870 subr == DIF_SUBR_HTONS ||
8871 subr == DIF_SUBR_HTONL ||
8872 subr == DIF_SUBR_HTONLL ||
8873 subr == DIF_SUBR_NTOHS ||
8874 subr == DIF_SUBR_NTOHL ||
8875 subr == DIF_SUBR_NTOHLL)
8876 break;
8877
8878 err += efunc(pc, "invalid subr %u\n", subr);
8879 break;
8880
8881 default:
8882 err += efunc(pc, "invalid opcode %u\n",
8883 DIF_INSTR_OP(instr));
8884 }
|
75 #include <sys/kmem.h>
76 #include <sys/strsubr.h>
77 #include <sys/sysmacros.h>
78 #include <sys/dtrace_impl.h>
79 #include <sys/atomic.h>
80 #include <sys/cmn_err.h>
81 #include <sys/mutex_impl.h>
82 #include <sys/rwlock_impl.h>
83 #include <sys/ctf_api.h>
84 #include <sys/panic.h>
85 #include <sys/priv_impl.h>
86 #include <sys/policy.h>
87 #include <sys/cred_impl.h>
88 #include <sys/procfs_isa.h>
89 #include <sys/taskq.h>
90 #include <sys/mkdev.h>
91 #include <sys/kdi.h>
92 #include <sys/zone.h>
93 #include <sys/socket.h>
94 #include <netinet/in.h>
95 #include "strtolctype.h"
96
97 /*
98 * DTrace Tunable Variables
99 *
100 * The following variables may be tuned by adding a line to /etc/system that
101 * includes both the name of the DTrace module ("dtrace") and the name of the
102 * variable. For example:
103 *
104 * set dtrace:dtrace_destructive_disallow = 1
105 *
106 * In general, the only variables that one should be tuning this way are those
107 * that affect system-wide DTrace behavior, and for which the default behavior
108 * is undesirable. Most of these variables are tunable on a per-consumer
109 * basis using DTrace options, and need not be tuned on a system-wide basis.
110 * When tuning these variables, avoid pathological values; while some attempt
111 * is made to verify the integrity of these variables, they are not considered
112 * part of the supported interface to DTrace, and they are therefore not
113 * checked comprehensively. Further, these variables should not be tuned
114 * dynamically via "mdb -kw" or other means; they should only be tuned via
115 * /etc/system.
843 size_t sz;
844 ASSERT(type->dtdt_flags & DIF_TF_BYREF);
845
846 /*
847 * If we hold the privilege to read from kernel memory, then
848 * everything is readable.
849 */
850 if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0)
851 return (1);
852
853 if (type->dtdt_kind == DIF_TYPE_STRING)
854 sz = dtrace_strlen(src,
855 vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE]) + 1;
856 else
857 sz = type->dtdt_size;
858
859 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
860 }
861
862 /*
863 * Convert a string to a signed integer using safe loads.
864 *
865 * NOTE: This function uses various macros from strtolctype.h to manipulate
866 * digit values, etc -- these have all been checked to ensure they make
867 * no additional function calls.
868 */
869 static int64_t
870 dtrace_strtoll(char *input, int base, size_t limit)
871 {
872 uintptr_t pos = (uintptr_t)input;
873 int64_t val = 0;
874 int x;
875 boolean_t neg = B_FALSE;
876 char c, cc, ccc;
877 uintptr_t end = pos + limit;
878
879 /*
880 * Consume any whitespace preceding digits.
881 */
882 while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
883 pos++;
884
885 /*
886 * Handle an explicit sign if one is present.
887 */
888 if (c == '-' || c == '+') {
889 if (c == '-')
890 neg = B_TRUE;
891 c = dtrace_load8(++pos);
892 }
893
894 /*
895 * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
896 * if present.
897 */
898 if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
899 cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
900 pos += 2;
901 c = ccc;
902 }
903
904 /*
905 * Read in contiguous digits until the first non-digit character.
906 */
907 for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
908 c = dtrace_load8(++pos))
909 val = val * base + x;
910
911 return (neg ? -val : val);
912 }
913
914 /*
915 * Compare two strings using safe loads.
916 */
917 static int
918 dtrace_strncmp(char *s1, char *s2, size_t limit)
919 {
920 uint8_t c1, c2;
921 volatile uint16_t *flags;
922
923 if (s1 == s2 || limit == 0)
924 return (0);
925
926 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
927
928 do {
929 if (s1 == NULL) {
930 c1 = '\0';
931 } else {
932 c1 = dtrace_load8((uintptr_t)s1++);
933 }
934
3371 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3372 return (0);
3373
3374 /*
3375 * It is always safe to dereference one's own t_lwp pointer in
3376 * the event that this pointer is non-NULL. (This is true
3377 * because threads and lwps don't clean up their own state --
3378 * they leave that task to whomever reaps them.)
3379 */
3380 if ((lwp = curthread->t_lwp) == NULL)
3381 return (0);
3382
3383 return ((uint64_t)lwp->lwp_errno);
3384 }
3385 default:
3386 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3387 return (0);
3388 }
3389 }
3390
3391
3392 typedef enum dtrace_json_state {
3393 DTRACE_JSON_REST = 1,
3394 DTRACE_JSON_OBJECT,
3395 DTRACE_JSON_STRING,
3396 DTRACE_JSON_STRING_ESCAPE,
3397 DTRACE_JSON_STRING_ESCAPE_UNICODE,
3398 DTRACE_JSON_COLON,
3399 DTRACE_JSON_COMMA,
3400 DTRACE_JSON_VALUE,
3401 DTRACE_JSON_IDENTIFIER,
3402 DTRACE_JSON_NUMBER,
3403 DTRACE_JSON_NUMBER_FRAC,
3404 DTRACE_JSON_NUMBER_EXP,
3405 DTRACE_JSON_COLLECT_OBJECT
3406 } dtrace_json_state_t;
3407
3408 /*
3409 * This function possesses just enough knowledge about JSON to extract a single
3410 * value from a JSON string and store it in the scratch buffer. It is able
3411 * to extract nested object values, and members of arrays by index.
3412 *
3413 * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
3414 * be looked up as we descend into the object tree. e.g.
3415 *
3416 * foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
3417 * with nelems = 5.
3418 *
3419 * The run time of this function must be bounded above by strsize to limit the
3420 * amount of work done in probe context. As such, it is implemented as a
3421 * simple state machine, reading one character at a time using safe loads
3422 * until we find the requested element, hit a parsing error or run off the
3423 * end of the object or string.
3424 *
3425 * As there is no way for a subroutine to return an error without interrupting
3426 * clause execution, we simply return NULL in the event of a missing key or any
3427 * other error condition. Each NULL return in this function is commented with
3428 * the error condition it represents -- parsing or otherwise.
3429 *
3430 * The set of states for the state machine closely matches the JSON
3431 * specification (http://json.org/). Briefly:
3432 *
3433 * DTRACE_JSON_REST:
3434 * Skip whitespace until we find either a top-level Object, moving
3435 * to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
3436 *
3437 * DTRACE_JSON_OBJECT:
3438 * Locate the next key String in an Object. Sets a flag to denote
3439 * the next String as a key string and moves to DTRACE_JSON_STRING.
3440 *
3441 * DTRACE_JSON_COLON:
3442 * Skip whitespace until we find the colon that separates key Strings
3443 * from their values. Once found, move to DTRACE_JSON_VALUE.
3444 *
3445 * DTRACE_JSON_VALUE:
3446 * Detects the type of the next value (String, Number, Identifier, Object
3447 * or Array) and routes to the states that process that type. Here we also
3448 * deal with the element selector list if we are requested to traverse down
3449 * into the object tree.
3450 *
3451 * DTRACE_JSON_COMMA:
3452 * Skip whitespace until we find the comma that separates key-value pairs
3453 * in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
3454 * (similarly DTRACE_JSON_VALUE). All following literal value processing
3455 * states return to this state at the end of their value, unless otherwise
3456 * noted.
3457 *
3458 * DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
3459 * Processes a Number literal from the JSON, including any exponent
3460 * component that may be present. Numbers are returned as strings, which
3461 * may be passed to strtoll() if an integer is required.
3462 *
3463 * DTRACE_JSON_IDENTIFIER:
3464 * Processes a "true", "false" or "null" literal in the JSON.
3465 *
3466 * DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
3467 * DTRACE_JSON_STRING_ESCAPE_UNICODE:
3468 * Processes a String literal from the JSON, whether the String denotes
3469 * a key, a value or part of a larger Object. Handles all escape sequences
3470 * present in the specification, including four-digit unicode characters,
3471 * but merely includes the escape sequence without converting it to the
3472 * actual escaped character. If the String is flagged as a key, we
3473 * move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
3474 *
3475 * DTRACE_JSON_COLLECT_OBJECT:
3476 * This state collects an entire Object (or Array), correctly handling
3477 * embedded strings. If the full element selector list matches this nested
3478 * object, we return the Object in full as a string. If not, we use this
3479 * state to skip to the next value at this level and continue processing.
3480 *
3481 * NOTE: This function uses various macros from strtolctype.h to manipulate
3482 * digit values, etc -- these have all been checked to ensure they make
3483 * no additional function calls.
3484 */
3485 static char *
3486 dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
3487 char *dest)
3488 {
3489 dtrace_json_state_t state = DTRACE_JSON_REST;
3490 int64_t array_elem = INT64_MIN;
3491 int64_t array_pos = 0;
3492 uint8_t escape_unicount = 0;
3493 boolean_t string_is_key = B_FALSE;
3494 boolean_t collect_object = B_FALSE;
3495 boolean_t found_key = B_FALSE;
3496 boolean_t in_array = B_FALSE;
3497 uint32_t braces = 0, brackets = 0;
3498 char *elem = elemlist;
3499 char *dd = dest;
3500 uintptr_t cur;
3501
3502 for (cur = json; cur < json + size; cur++) {
3503 char cc = dtrace_load8(cur);
3504 if (cc == '\0')
3505 return (NULL);
3506
3507 switch (state) {
3508 case DTRACE_JSON_REST:
3509 if (isspace(cc))
3510 break;
3511
3512 if (cc == '{') {
3513 state = DTRACE_JSON_OBJECT;
3514 break;
3515 }
3516
3517 if (cc == '[') {
3518 in_array = B_TRUE;
3519 array_pos = 0;
3520 array_elem = dtrace_strtoll(elem, 10, size);
3521 found_key = array_elem == 0 ? B_TRUE : B_FALSE;
3522 state = DTRACE_JSON_VALUE;
3523 break;
3524 }
3525
3526 /*
3527 * ERROR: expected to find a top-level object or array.
3528 */
3529 return (NULL);
3530 case DTRACE_JSON_OBJECT:
3531 if (isspace(cc))
3532 break;
3533
3534 if (cc == '"') {
3535 state = DTRACE_JSON_STRING;
3536 string_is_key = B_TRUE;
3537 break;
3538 }
3539
3540 /*
3541 * ERROR: either the object did not start with a key
3542 * string, or we've run off the end of the object
3543 * without finding the requested key.
3544 */
3545 return (NULL);
3546 case DTRACE_JSON_STRING:
3547 if (cc == '\\') {
3548 *dd++ = '\\';
3549 state = DTRACE_JSON_STRING_ESCAPE;
3550 break;
3551 }
3552
3553 if (cc == '"') {
3554 if (collect_object) {
3555 /*
3556 * We don't reset the dest here, as
3557 * the string is part of a larger
3558 * object being collected.
3559 */
3560 *dd++ = cc;
3561 collect_object = B_FALSE;
3562 state = DTRACE_JSON_COLLECT_OBJECT;
3563 break;
3564 }
3565 *dd = '\0';
3566 dd = dest; /* reset string buffer */
3567 if (string_is_key) {
3568 if (dtrace_strncmp(dest, elem,
3569 size) == 0)
3570 found_key = B_TRUE;
3571 } else if (found_key) {
3572 if (nelems > 1) {
3573 /*
3574 * We expected an object, not
3575 * this string.
3576 */
3577 return (NULL);
3578 }
3579 return (dest);
3580 }
3581 state = string_is_key ? DTRACE_JSON_COLON :
3582 DTRACE_JSON_COMMA;
3583 string_is_key = B_FALSE;
3584 break;
3585 }
3586
3587 *dd++ = cc;
3588 break;
3589 case DTRACE_JSON_STRING_ESCAPE:
3590 *dd++ = cc;
3591 if (cc == 'u') {
3592 escape_unicount = 0;
3593 state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
3594 } else {
3595 state = DTRACE_JSON_STRING;
3596 }
3597 break;
3598 case DTRACE_JSON_STRING_ESCAPE_UNICODE:
3599 if (!isxdigit(cc)) {
3600 /*
3601 * ERROR: invalid unicode escape, expected
3602 * four valid hexidecimal digits.
3603 */
3604 return (NULL);
3605 }
3606
3607 *dd++ = cc;
3608 if (++escape_unicount == 4)
3609 state = DTRACE_JSON_STRING;
3610 break;
3611 case DTRACE_JSON_COLON:
3612 if (isspace(cc))
3613 break;
3614
3615 if (cc == ':') {
3616 state = DTRACE_JSON_VALUE;
3617 break;
3618 }
3619
3620 /*
3621 * ERROR: expected a colon.
3622 */
3623 return (NULL);
3624 case DTRACE_JSON_COMMA:
3625 if (isspace(cc))
3626 break;
3627
3628 if (cc == ',') {
3629 if (in_array) {
3630 state = DTRACE_JSON_VALUE;
3631 if (++array_pos == array_elem)
3632 found_key = B_TRUE;
3633 } else {
3634 state = DTRACE_JSON_OBJECT;
3635 }
3636 break;
3637 }
3638
3639 /*
3640 * ERROR: either we hit an unexpected character, or
3641 * we reached the end of the object or array without
3642 * finding the requested key.
3643 */
3644 return (NULL);
3645 case DTRACE_JSON_IDENTIFIER:
3646 if (islower(cc)) {
3647 *dd++ = cc;
3648 break;
3649 }
3650
3651 *dd = '\0';
3652 dd = dest; /* reset string buffer */
3653
3654 if (dtrace_strncmp(dest, "true", 5) == 0 ||
3655 dtrace_strncmp(dest, "false", 6) == 0 ||
3656 dtrace_strncmp(dest, "null", 5) == 0) {
3657 if (found_key) {
3658 if (nelems > 1) {
3659 /*
3660 * ERROR: We expected an object,
3661 * not this identifier.
3662 */
3663 return (NULL);
3664 }
3665 return (dest);
3666 } else {
3667 cur--;
3668 state = DTRACE_JSON_COMMA;
3669 break;
3670 }
3671 }
3672
3673 /*
3674 * ERROR: we did not recognise the identifier as one
3675 * of those in the JSON specification.
3676 */
3677 return (NULL);
3678 case DTRACE_JSON_NUMBER:
3679 if (cc == '.') {
3680 *dd++ = cc;
3681 state = DTRACE_JSON_NUMBER_FRAC;
3682 break;
3683 }
3684
3685 if (cc == 'x' || cc == 'X') {
3686 /*
3687 * ERROR: specification explicitly excludes
3688 * hexidecimal or octal numbers.
3689 */
3690 return (NULL);
3691 }
3692
3693 /* FALLTHRU */
3694 case DTRACE_JSON_NUMBER_FRAC:
3695 if (cc == 'e' || cc == 'E') {
3696 *dd++ = cc;
3697 state = DTRACE_JSON_NUMBER_EXP;
3698 break;
3699 }
3700
3701 if (cc == '+' || cc == '-') {
3702 /*
3703 * ERROR: expect sign as part of exponent only.
3704 */
3705 return (NULL);
3706 }
3707 /* FALLTHRU */
3708 case DTRACE_JSON_NUMBER_EXP:
3709 if (isdigit(cc) || cc == '+' || cc == '-') {
3710 *dd++ = cc;
3711 break;
3712 }
3713
3714 *dd = '\0';
3715 dd = dest; /* reset string buffer */
3716 if (found_key) {
3717 if (nelems > 1) {
3718 /*
3719 * ERROR: We expected an object, not
3720 * this number.
3721 */
3722 return (NULL);
3723 }
3724 return (dest);
3725 }
3726
3727 cur--;
3728 state = DTRACE_JSON_COMMA;
3729 break;
3730 case DTRACE_JSON_VALUE:
3731 if (isspace(cc))
3732 break;
3733
3734 if (cc == '{' || cc == '[') {
3735 if (nelems > 1 && found_key) {
3736 in_array = cc == '[' ? B_TRUE : B_FALSE;
3737 /*
3738 * If our element selector directs us
3739 * to descend into this nested object,
3740 * then move to the next selector
3741 * element in the list and restart the
3742 * state machine.
3743 */
3744 while (*elem != '\0')
3745 elem++;
3746 elem++; /* skip the inter-element NUL */
3747 nelems--;
3748 dd = dest;
3749 if (in_array) {
3750 state = DTRACE_JSON_VALUE;
3751 array_pos = 0;
3752 array_elem = dtrace_strtoll(
3753 elem, 10, size);
3754 found_key = array_elem == 0 ?
3755 B_TRUE : B_FALSE;
3756 } else {
3757 found_key = B_FALSE;
3758 state = DTRACE_JSON_OBJECT;
3759 }
3760 break;
3761 }
3762
3763 /*
3764 * Otherwise, we wish to either skip this
3765 * nested object or return it in full.
3766 */
3767 if (cc == '[')
3768 brackets = 1;
3769 else
3770 braces = 1;
3771 *dd++ = cc;
3772 state = DTRACE_JSON_COLLECT_OBJECT;
3773 break;
3774 }
3775
3776 if (cc == '"') {
3777 state = DTRACE_JSON_STRING;
3778 break;
3779 }
3780
3781 if (islower(cc)) {
3782 /*
3783 * Here we deal with true, false and null.
3784 */
3785 *dd++ = cc;
3786 state = DTRACE_JSON_IDENTIFIER;
3787 break;
3788 }
3789
3790 if (cc == '-' || isdigit(cc)) {
3791 *dd++ = cc;
3792 state = DTRACE_JSON_NUMBER;
3793 break;
3794 }
3795
3796 /*
3797 * ERROR: unexpected character at start of value.
3798 */
3799 return (NULL);
3800 case DTRACE_JSON_COLLECT_OBJECT:
3801 if (cc == '\0')
3802 /*
3803 * ERROR: unexpected end of input.
3804 */
3805 return (NULL);
3806
3807 *dd++ = cc;
3808 if (cc == '"') {
3809 collect_object = B_TRUE;
3810 state = DTRACE_JSON_STRING;
3811 break;
3812 }
3813
3814 if (cc == ']') {
3815 if (brackets-- == 0) {
3816 /*
3817 * ERROR: unbalanced brackets.
3818 */
3819 return (NULL);
3820 }
3821 } else if (cc == '}') {
3822 if (braces-- == 0) {
3823 /*
3824 * ERROR: unbalanced braces.
3825 */
3826 return (NULL);
3827 }
3828 } else if (cc == '{') {
3829 braces++;
3830 } else if (cc == '[') {
3831 brackets++;
3832 }
3833
3834 if (brackets == 0 && braces == 0) {
3835 if (found_key) {
3836 *dd = '\0';
3837 return (dest);
3838 }
3839 dd = dest; /* reset string buffer */
3840 state = DTRACE_JSON_COMMA;
3841 }
3842 break;
3843 }
3844 }
3845 return (NULL);
3846 }
3847
3848 /*
3849 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3850 * Notice that we don't bother validating the proper number of arguments or
3851 * their types in the tuple stack. This isn't needed because all argument
3852 * interpretation is safe because of our load safety -- the worst that can
3853 * happen is that a bogus program can obtain bogus results.
3854 */
3855 static void
3856 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3857 dtrace_key_t *tupregs, int nargs,
3858 dtrace_mstate_t *mstate, dtrace_state_t *state)
3859 {
3860 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3861 volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3862 dtrace_vstate_t *vstate = &state->dts_vstate;
3863
3864 union {
3865 mutex_impl_t mi;
3866 uint64_t mx;
3867 } m;
4528 if (index >= len || index < 0) {
4529 remaining = 0;
4530 } else if (remaining < 0) {
4531 remaining += len - index;
4532 } else if (index + remaining > size) {
4533 remaining = size - index;
4534 }
4535
4536 for (i = 0; i < remaining; i++) {
4537 if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4538 break;
4539 }
4540
4541 d[i] = '\0';
4542
4543 mstate->dtms_scratch_ptr += size;
4544 regs[rd] = (uintptr_t)d;
4545 break;
4546 }
4547
4548 case DIF_SUBR_JSON: {
4549 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4550 uintptr_t json = tupregs[0].dttk_value;
4551 size_t jsonlen = dtrace_strlen((char *)json, size);
4552 uintptr_t elem = tupregs[1].dttk_value;
4553 size_t elemlen = dtrace_strlen((char *)elem, size);
4554
4555 char *dest = (char *)mstate->dtms_scratch_ptr;
4556 char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1;
4557 char *ee = elemlist;
4558 int nelems = 1;
4559 uintptr_t cur;
4560
4561 if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
4562 !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
4563 regs[rd] = NULL;
4564 break;
4565 }
4566
4567 if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
4568 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4569 regs[rd] = NULL;
4570 break;
4571 }
4572
4573 /*
4574 * Read the element selector and split it up into a packed list
4575 * of strings.
4576 */
4577 for (cur = elem; cur < elem + elemlen; cur++) {
4578 char cc = dtrace_load8(cur);
4579
4580 if (cur == elem && cc == '[') {
4581 /*
4582 * If the first element selector key is
4583 * actually an array index then ignore the
4584 * bracket.
4585 */
4586 continue;
4587 }
4588
4589 if (cc == ']')
4590 continue;
4591
4592 if (cc == '.' || cc == '[') {
4593 nelems++;
4594 cc = '\0';
4595 }
4596
4597 *ee++ = cc;
4598 }
4599 *ee++ = '\0';
4600
4601 if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
4602 nelems, dest)) != NULL)
4603 mstate->dtms_scratch_ptr += jsonlen + 1;
4604 break;
4605 }
4606
4607 case DIF_SUBR_TOUPPER:
4608 case DIF_SUBR_TOLOWER: {
4609 uintptr_t s = tupregs[0].dttk_value;
4610 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4611 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4612 size_t len = dtrace_strlen((char *)s, size);
4613 char lower, upper, convert;
4614 int64_t i;
4615
4616 if (subr == DIF_SUBR_TOUPPER) {
4617 lower = 'a';
4618 upper = 'z';
4619 convert = 'A';
4620 } else {
4621 lower = 'A';
4622 upper = 'Z';
4623 convert = 'a';
4624 }
4625
4626 if (!dtrace_canload(s, len + 1, mstate, vstate)) {
4894
4895 for (;;) {
4896 if (i >= size) {
4897 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4898 regs[rd] = NULL;
4899 break;
4900 }
4901
4902 if ((d[i++] = dtrace_load8(s2++)) == '\0')
4903 break;
4904 }
4905
4906 if (i < size) {
4907 mstate->dtms_scratch_ptr += i;
4908 regs[rd] = (uintptr_t)d;
4909 }
4910
4911 break;
4912 }
4913
4914 case DIF_SUBR_STRTOLL: {
4915 uintptr_t s = tupregs[0].dttk_value;
4916 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4917 int base = 10;
4918
4919 if (nargs > 1) {
4920 if ((base = tupregs[1].dttk_value) <= 1 ||
4921 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4922 *flags |= CPU_DTRACE_ILLOP;
4923 break;
4924 }
4925 }
4926
4927 if (!dtrace_strcanload(s, size, mstate, vstate)) {
4928 regs[rd] = INT64_MIN;
4929 break;
4930 }
4931
4932 regs[rd] = dtrace_strtoll((char *)s, base, size);
4933 break;
4934 }
4935
4936 case DIF_SUBR_LLTOSTR: {
4937 int64_t i = (int64_t)tupregs[0].dttk_value;
4938 uint64_t val, digit;
4939 uint64_t size = 65; /* enough room for 2^64 in binary */
4940 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4941 int base = 10;
4942
4943 if (nargs > 1) {
4944 if ((base = tupregs[1].dttk_value) <= 1 ||
4945 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4946 *flags |= CPU_DTRACE_ILLOP;
4947 break;
4948 }
4949 }
4950
4951 val = (base == 10 && i < 0) ? i * -1 : i;
4952
4953 if (!DTRACE_INSCRATCH(mstate, size)) {
4954 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4955 regs[rd] = NULL;
9435 case DIF_OP_LDTAA:
9436 err += efunc(pc, "illegal dynamic variable load\n");
9437 break;
9438
9439 case DIF_OP_STTS:
9440 case DIF_OP_STGAA:
9441 case DIF_OP_STTAA:
9442 err += efunc(pc, "illegal dynamic variable store\n");
9443 break;
9444
9445 case DIF_OP_CALL:
9446 if (subr == DIF_SUBR_ALLOCA ||
9447 subr == DIF_SUBR_BCOPY ||
9448 subr == DIF_SUBR_COPYIN ||
9449 subr == DIF_SUBR_COPYINTO ||
9450 subr == DIF_SUBR_COPYINSTR ||
9451 subr == DIF_SUBR_INDEX ||
9452 subr == DIF_SUBR_INET_NTOA ||
9453 subr == DIF_SUBR_INET_NTOA6 ||
9454 subr == DIF_SUBR_INET_NTOP ||
9455 subr == DIF_SUBR_JSON ||
9456 subr == DIF_SUBR_LLTOSTR ||
9457 subr == DIF_SUBR_STRTOLL ||
9458 subr == DIF_SUBR_RINDEX ||
9459 subr == DIF_SUBR_STRCHR ||
9460 subr == DIF_SUBR_STRJOIN ||
9461 subr == DIF_SUBR_STRRCHR ||
9462 subr == DIF_SUBR_STRSTR ||
9463 subr == DIF_SUBR_HTONS ||
9464 subr == DIF_SUBR_HTONL ||
9465 subr == DIF_SUBR_HTONLL ||
9466 subr == DIF_SUBR_NTOHS ||
9467 subr == DIF_SUBR_NTOHL ||
9468 subr == DIF_SUBR_NTOHLL)
9469 break;
9470
9471 err += efunc(pc, "invalid subr %u\n", subr);
9472 break;
9473
9474 default:
9475 err += efunc(pc, "invalid opcode %u\n",
9476 DIF_INSTR_OP(instr));
9477 }
|