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.
860 if (state != NULL) {
861 strsize = state->dts_options[DTRACEOPT_STRSIZE];
862 } else {
863 /*
864 * In helper context, we have a NULL state; fall back
865 * to using the system-wide default for the string size
866 * in this case.
867 */
868 strsize = dtrace_strsize_default;
869 }
870
871 sz = dtrace_strlen(src, strsize) + 1;
872 } else {
873 sz = type->dtdt_size;
874 }
875
876 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
877 }
878
879 /*
880 * Compare two strings using safe loads.
881 */
882 static int
883 dtrace_strncmp(char *s1, char *s2, size_t limit)
884 {
885 uint8_t c1, c2;
886 volatile uint16_t *flags;
887
888 if (s1 == s2 || limit == 0)
889 return (0);
890
891 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
892
893 do {
894 if (s1 == NULL) {
895 c1 = '\0';
896 } else {
897 c1 = dtrace_load8((uintptr_t)s1++);
898 }
899
3336 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3337 return (0);
3338
3339 /*
3340 * It is always safe to dereference one's own t_lwp pointer in
3341 * the event that this pointer is non-NULL. (This is true
3342 * because threads and lwps don't clean up their own state --
3343 * they leave that task to whomever reaps them.)
3344 */
3345 if ((lwp = curthread->t_lwp) == NULL)
3346 return (0);
3347
3348 return ((uint64_t)lwp->lwp_errno);
3349 }
3350 default:
3351 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3352 return (0);
3353 }
3354 }
3355
3356 /*
3357 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3358 * Notice that we don't bother validating the proper number of arguments or
3359 * their types in the tuple stack. This isn't needed because all argument
3360 * interpretation is safe because of our load safety -- the worst that can
3361 * happen is that a bogus program can obtain bogus results.
3362 */
3363 static void
3364 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3365 dtrace_key_t *tupregs, int nargs,
3366 dtrace_mstate_t *mstate, dtrace_state_t *state)
3367 {
3368 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3369 volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3370 dtrace_vstate_t *vstate = &state->dts_vstate;
3371
3372 union {
3373 mutex_impl_t mi;
3374 uint64_t mx;
3375 } m;
3376
4036 if (index >= len || index < 0) {
4037 remaining = 0;
4038 } else if (remaining < 0) {
4039 remaining += len - index;
4040 } else if (index + remaining > size) {
4041 remaining = size - index;
4042 }
4043
4044 for (i = 0; i < remaining; i++) {
4045 if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4046 break;
4047 }
4048
4049 d[i] = '\0';
4050
4051 mstate->dtms_scratch_ptr += size;
4052 regs[rd] = (uintptr_t)d;
4053 break;
4054 }
4055
4056 case DIF_SUBR_TOUPPER:
4057 case DIF_SUBR_TOLOWER: {
4058 uintptr_t s = tupregs[0].dttk_value;
4059 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4060 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4061 size_t len = dtrace_strlen((char *)s, size);
4062 char lower, upper, convert;
4063 int64_t i;
4064
4065 if (subr == DIF_SUBR_TOUPPER) {
4066 lower = 'a';
4067 upper = 'z';
4068 convert = 'A';
4069 } else {
4070 lower = 'A';
4071 upper = 'Z';
4072 convert = 'a';
4073 }
4074
4075 if (!dtrace_canload(s, len + 1, mstate, vstate)) {
4343
4344 for (;;) {
4345 if (i >= size) {
4346 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4347 regs[rd] = NULL;
4348 break;
4349 }
4350
4351 if ((d[i++] = dtrace_load8(s2++)) == '\0')
4352 break;
4353 }
4354
4355 if (i < size) {
4356 mstate->dtms_scratch_ptr += i;
4357 regs[rd] = (uintptr_t)d;
4358 }
4359
4360 break;
4361 }
4362
4363 case DIF_SUBR_LLTOSTR: {
4364 int64_t i = (int64_t)tupregs[0].dttk_value;
4365 uint64_t val, digit;
4366 uint64_t size = 65; /* enough room for 2^64 in binary */
4367 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4368 int base = 10;
4369
4370 if (nargs > 1) {
4371 if ((base = tupregs[1].dttk_value) <= 1 ||
4372 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4373 *flags |= CPU_DTRACE_ILLOP;
4374 break;
4375 }
4376 }
4377
4378 val = (base == 10 && i < 0) ? i * -1 : i;
4379
4380 if (!DTRACE_INSCRATCH(mstate, size)) {
4381 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4382 regs[rd] = NULL;
8872 case DIF_OP_LDTAA:
8873 err += efunc(pc, "illegal dynamic variable load\n");
8874 break;
8875
8876 case DIF_OP_STTS:
8877 case DIF_OP_STGAA:
8878 case DIF_OP_STTAA:
8879 err += efunc(pc, "illegal dynamic variable store\n");
8880 break;
8881
8882 case DIF_OP_CALL:
8883 if (subr == DIF_SUBR_ALLOCA ||
8884 subr == DIF_SUBR_BCOPY ||
8885 subr == DIF_SUBR_COPYIN ||
8886 subr == DIF_SUBR_COPYINTO ||
8887 subr == DIF_SUBR_COPYINSTR ||
8888 subr == DIF_SUBR_INDEX ||
8889 subr == DIF_SUBR_INET_NTOA ||
8890 subr == DIF_SUBR_INET_NTOA6 ||
8891 subr == DIF_SUBR_INET_NTOP ||
8892 subr == DIF_SUBR_LLTOSTR ||
8893 subr == DIF_SUBR_RINDEX ||
8894 subr == DIF_SUBR_STRCHR ||
8895 subr == DIF_SUBR_STRJOIN ||
8896 subr == DIF_SUBR_STRRCHR ||
8897 subr == DIF_SUBR_STRSTR ||
8898 subr == DIF_SUBR_HTONS ||
8899 subr == DIF_SUBR_HTONL ||
8900 subr == DIF_SUBR_HTONLL ||
8901 subr == DIF_SUBR_NTOHS ||
8902 subr == DIF_SUBR_NTOHL ||
8903 subr == DIF_SUBR_NTOHLL)
8904 break;
8905
8906 err += efunc(pc, "invalid subr %u\n", subr);
8907 break;
8908
8909 default:
8910 err += efunc(pc, "invalid opcode %u\n",
8911 DIF_INSTR_OP(instr));
8912 }
|
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.
861 if (state != NULL) {
862 strsize = state->dts_options[DTRACEOPT_STRSIZE];
863 } else {
864 /*
865 * In helper context, we have a NULL state; fall back
866 * to using the system-wide default for the string size
867 * in this case.
868 */
869 strsize = dtrace_strsize_default;
870 }
871
872 sz = dtrace_strlen(src, strsize) + 1;
873 } else {
874 sz = type->dtdt_size;
875 }
876
877 return (dtrace_canload((uintptr_t)src, sz, mstate, vstate));
878 }
879
880 /*
881 * Convert a string to a signed integer using safe loads.
882 *
883 * NOTE: This function uses various macros from strtolctype.h to manipulate
884 * digit values, etc -- these have all been checked to ensure they make
885 * no additional function calls.
886 */
887 static int64_t
888 dtrace_strtoll(char *input, int base, size_t limit)
889 {
890 uintptr_t pos = (uintptr_t)input;
891 int64_t val = 0;
892 int x;
893 boolean_t neg = B_FALSE;
894 char c, cc, ccc;
895 uintptr_t end = pos + limit;
896
897 /*
898 * Consume any whitespace preceding digits.
899 */
900 while ((c = dtrace_load8(pos)) == ' ' || c == '\t')
901 pos++;
902
903 /*
904 * Handle an explicit sign if one is present.
905 */
906 if (c == '-' || c == '+') {
907 if (c == '-')
908 neg = B_TRUE;
909 c = dtrace_load8(++pos);
910 }
911
912 /*
913 * Check for an explicit hexadecimal prefix ("0x" or "0X") and skip it
914 * if present.
915 */
916 if (base == 16 && c == '0' && ((cc = dtrace_load8(pos + 1)) == 'x' ||
917 cc == 'X') && isxdigit(ccc = dtrace_load8(pos + 2))) {
918 pos += 2;
919 c = ccc;
920 }
921
922 /*
923 * Read in contiguous digits until the first non-digit character.
924 */
925 for (; pos < end && c != '\0' && lisalnum(c) && (x = DIGIT(c)) < base;
926 c = dtrace_load8(++pos))
927 val = val * base + x;
928
929 return (neg ? -val : val);
930 }
931
932 /*
933 * Compare two strings using safe loads.
934 */
935 static int
936 dtrace_strncmp(char *s1, char *s2, size_t limit)
937 {
938 uint8_t c1, c2;
939 volatile uint16_t *flags;
940
941 if (s1 == s2 || limit == 0)
942 return (0);
943
944 flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
945
946 do {
947 if (s1 == NULL) {
948 c1 = '\0';
949 } else {
950 c1 = dtrace_load8((uintptr_t)s1++);
951 }
952
3389 if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))
3390 return (0);
3391
3392 /*
3393 * It is always safe to dereference one's own t_lwp pointer in
3394 * the event that this pointer is non-NULL. (This is true
3395 * because threads and lwps don't clean up their own state --
3396 * they leave that task to whomever reaps them.)
3397 */
3398 if ((lwp = curthread->t_lwp) == NULL)
3399 return (0);
3400
3401 return ((uint64_t)lwp->lwp_errno);
3402 }
3403 default:
3404 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
3405 return (0);
3406 }
3407 }
3408
3409
3410 typedef enum dtrace_json_state {
3411 DTRACE_JSON_REST = 1,
3412 DTRACE_JSON_OBJECT,
3413 DTRACE_JSON_STRING,
3414 DTRACE_JSON_STRING_ESCAPE,
3415 DTRACE_JSON_STRING_ESCAPE_UNICODE,
3416 DTRACE_JSON_COLON,
3417 DTRACE_JSON_COMMA,
3418 DTRACE_JSON_VALUE,
3419 DTRACE_JSON_IDENTIFIER,
3420 DTRACE_JSON_NUMBER,
3421 DTRACE_JSON_NUMBER_FRAC,
3422 DTRACE_JSON_NUMBER_EXP,
3423 DTRACE_JSON_COLLECT_OBJECT
3424 } dtrace_json_state_t;
3425
3426 /*
3427 * This function possesses just enough knowledge about JSON to extract a single
3428 * value from a JSON string and store it in the scratch buffer. It is able
3429 * to extract nested object values, and members of arrays by index.
3430 *
3431 * elemlist is a list of JSON keys, stored as packed NUL-terminated strings, to
3432 * be looked up as we descend into the object tree. e.g.
3433 *
3434 * foo[0].bar.baz[32] --> "foo" NUL "0" NUL "bar" NUL "baz" NUL "32" NUL
3435 * with nelems = 5.
3436 *
3437 * The run time of this function must be bounded above by strsize to limit the
3438 * amount of work done in probe context. As such, it is implemented as a
3439 * simple state machine, reading one character at a time using safe loads
3440 * until we find the requested element, hit a parsing error or run off the
3441 * end of the object or string.
3442 *
3443 * As there is no way for a subroutine to return an error without interrupting
3444 * clause execution, we simply return NULL in the event of a missing key or any
3445 * other error condition. Each NULL return in this function is commented with
3446 * the error condition it represents -- parsing or otherwise.
3447 *
3448 * The set of states for the state machine closely matches the JSON
3449 * specification (http://json.org/). Briefly:
3450 *
3451 * DTRACE_JSON_REST:
3452 * Skip whitespace until we find either a top-level Object, moving
3453 * to DTRACE_JSON_OBJECT; or an Array, moving to DTRACE_JSON_VALUE.
3454 *
3455 * DTRACE_JSON_OBJECT:
3456 * Locate the next key String in an Object. Sets a flag to denote
3457 * the next String as a key string and moves to DTRACE_JSON_STRING.
3458 *
3459 * DTRACE_JSON_COLON:
3460 * Skip whitespace until we find the colon that separates key Strings
3461 * from their values. Once found, move to DTRACE_JSON_VALUE.
3462 *
3463 * DTRACE_JSON_VALUE:
3464 * Detects the type of the next value (String, Number, Identifier, Object
3465 * or Array) and routes to the states that process that type. Here we also
3466 * deal with the element selector list if we are requested to traverse down
3467 * into the object tree.
3468 *
3469 * DTRACE_JSON_COMMA:
3470 * Skip whitespace until we find the comma that separates key-value pairs
3471 * in Objects (returning to DTRACE_JSON_OBJECT) or values in Arrays
3472 * (similarly DTRACE_JSON_VALUE). All following literal value processing
3473 * states return to this state at the end of their value, unless otherwise
3474 * noted.
3475 *
3476 * DTRACE_JSON_NUMBER, DTRACE_JSON_NUMBER_FRAC, DTRACE_JSON_NUMBER_EXP:
3477 * Processes a Number literal from the JSON, including any exponent
3478 * component that may be present. Numbers are returned as strings, which
3479 * may be passed to strtoll() if an integer is required.
3480 *
3481 * DTRACE_JSON_IDENTIFIER:
3482 * Processes a "true", "false" or "null" literal in the JSON.
3483 *
3484 * DTRACE_JSON_STRING, DTRACE_JSON_STRING_ESCAPE,
3485 * DTRACE_JSON_STRING_ESCAPE_UNICODE:
3486 * Processes a String literal from the JSON, whether the String denotes
3487 * a key, a value or part of a larger Object. Handles all escape sequences
3488 * present in the specification, including four-digit unicode characters,
3489 * but merely includes the escape sequence without converting it to the
3490 * actual escaped character. If the String is flagged as a key, we
3491 * move to DTRACE_JSON_COLON rather than DTRACE_JSON_COMMA.
3492 *
3493 * DTRACE_JSON_COLLECT_OBJECT:
3494 * This state collects an entire Object (or Array), correctly handling
3495 * embedded strings. If the full element selector list matches this nested
3496 * object, we return the Object in full as a string. If not, we use this
3497 * state to skip to the next value at this level and continue processing.
3498 *
3499 * NOTE: This function uses various macros from strtolctype.h to manipulate
3500 * digit values, etc -- these have all been checked to ensure they make
3501 * no additional function calls.
3502 */
3503 static char *
3504 dtrace_json(uint64_t size, uintptr_t json, char *elemlist, int nelems,
3505 char *dest)
3506 {
3507 dtrace_json_state_t state = DTRACE_JSON_REST;
3508 int64_t array_elem = INT64_MIN;
3509 int64_t array_pos = 0;
3510 uint8_t escape_unicount = 0;
3511 boolean_t string_is_key = B_FALSE;
3512 boolean_t collect_object = B_FALSE;
3513 boolean_t found_key = B_FALSE;
3514 boolean_t in_array = B_FALSE;
3515 uint32_t braces = 0, brackets = 0;
3516 char *elem = elemlist;
3517 char *dd = dest;
3518 uintptr_t cur;
3519
3520 for (cur = json; cur < json + size; cur++) {
3521 char cc = dtrace_load8(cur);
3522 if (cc == '\0')
3523 return (NULL);
3524
3525 switch (state) {
3526 case DTRACE_JSON_REST:
3527 if (isspace(cc))
3528 break;
3529
3530 if (cc == '{') {
3531 state = DTRACE_JSON_OBJECT;
3532 break;
3533 }
3534
3535 if (cc == '[') {
3536 in_array = B_TRUE;
3537 array_pos = 0;
3538 array_elem = dtrace_strtoll(elem, 10, size);
3539 found_key = array_elem == 0 ? B_TRUE : B_FALSE;
3540 state = DTRACE_JSON_VALUE;
3541 break;
3542 }
3543
3544 /*
3545 * ERROR: expected to find a top-level object or array.
3546 */
3547 return (NULL);
3548 case DTRACE_JSON_OBJECT:
3549 if (isspace(cc))
3550 break;
3551
3552 if (cc == '"') {
3553 state = DTRACE_JSON_STRING;
3554 string_is_key = B_TRUE;
3555 break;
3556 }
3557
3558 /*
3559 * ERROR: either the object did not start with a key
3560 * string, or we've run off the end of the object
3561 * without finding the requested key.
3562 */
3563 return (NULL);
3564 case DTRACE_JSON_STRING:
3565 if (cc == '\\') {
3566 *dd++ = '\\';
3567 state = DTRACE_JSON_STRING_ESCAPE;
3568 break;
3569 }
3570
3571 if (cc == '"') {
3572 if (collect_object) {
3573 /*
3574 * We don't reset the dest here, as
3575 * the string is part of a larger
3576 * object being collected.
3577 */
3578 *dd++ = cc;
3579 collect_object = B_FALSE;
3580 state = DTRACE_JSON_COLLECT_OBJECT;
3581 break;
3582 }
3583 *dd = '\0';
3584 dd = dest; /* reset string buffer */
3585 if (string_is_key) {
3586 if (dtrace_strncmp(dest, elem,
3587 size) == 0)
3588 found_key = B_TRUE;
3589 } else if (found_key) {
3590 if (nelems > 1) {
3591 /*
3592 * We expected an object, not
3593 * this string.
3594 */
3595 return (NULL);
3596 }
3597 return (dest);
3598 }
3599 state = string_is_key ? DTRACE_JSON_COLON :
3600 DTRACE_JSON_COMMA;
3601 string_is_key = B_FALSE;
3602 break;
3603 }
3604
3605 *dd++ = cc;
3606 break;
3607 case DTRACE_JSON_STRING_ESCAPE:
3608 *dd++ = cc;
3609 if (cc == 'u') {
3610 escape_unicount = 0;
3611 state = DTRACE_JSON_STRING_ESCAPE_UNICODE;
3612 } else {
3613 state = DTRACE_JSON_STRING;
3614 }
3615 break;
3616 case DTRACE_JSON_STRING_ESCAPE_UNICODE:
3617 if (!isxdigit(cc)) {
3618 /*
3619 * ERROR: invalid unicode escape, expected
3620 * four valid hexidecimal digits.
3621 */
3622 return (NULL);
3623 }
3624
3625 *dd++ = cc;
3626 if (++escape_unicount == 4)
3627 state = DTRACE_JSON_STRING;
3628 break;
3629 case DTRACE_JSON_COLON:
3630 if (isspace(cc))
3631 break;
3632
3633 if (cc == ':') {
3634 state = DTRACE_JSON_VALUE;
3635 break;
3636 }
3637
3638 /*
3639 * ERROR: expected a colon.
3640 */
3641 return (NULL);
3642 case DTRACE_JSON_COMMA:
3643 if (isspace(cc))
3644 break;
3645
3646 if (cc == ',') {
3647 if (in_array) {
3648 state = DTRACE_JSON_VALUE;
3649 if (++array_pos == array_elem)
3650 found_key = B_TRUE;
3651 } else {
3652 state = DTRACE_JSON_OBJECT;
3653 }
3654 break;
3655 }
3656
3657 /*
3658 * ERROR: either we hit an unexpected character, or
3659 * we reached the end of the object or array without
3660 * finding the requested key.
3661 */
3662 return (NULL);
3663 case DTRACE_JSON_IDENTIFIER:
3664 if (islower(cc)) {
3665 *dd++ = cc;
3666 break;
3667 }
3668
3669 *dd = '\0';
3670 dd = dest; /* reset string buffer */
3671
3672 if (dtrace_strncmp(dest, "true", 5) == 0 ||
3673 dtrace_strncmp(dest, "false", 6) == 0 ||
3674 dtrace_strncmp(dest, "null", 5) == 0) {
3675 if (found_key) {
3676 if (nelems > 1) {
3677 /*
3678 * ERROR: We expected an object,
3679 * not this identifier.
3680 */
3681 return (NULL);
3682 }
3683 return (dest);
3684 } else {
3685 cur--;
3686 state = DTRACE_JSON_COMMA;
3687 break;
3688 }
3689 }
3690
3691 /*
3692 * ERROR: we did not recognise the identifier as one
3693 * of those in the JSON specification.
3694 */
3695 return (NULL);
3696 case DTRACE_JSON_NUMBER:
3697 if (cc == '.') {
3698 *dd++ = cc;
3699 state = DTRACE_JSON_NUMBER_FRAC;
3700 break;
3701 }
3702
3703 if (cc == 'x' || cc == 'X') {
3704 /*
3705 * ERROR: specification explicitly excludes
3706 * hexidecimal or octal numbers.
3707 */
3708 return (NULL);
3709 }
3710
3711 /* FALLTHRU */
3712 case DTRACE_JSON_NUMBER_FRAC:
3713 if (cc == 'e' || cc == 'E') {
3714 *dd++ = cc;
3715 state = DTRACE_JSON_NUMBER_EXP;
3716 break;
3717 }
3718
3719 if (cc == '+' || cc == '-') {
3720 /*
3721 * ERROR: expect sign as part of exponent only.
3722 */
3723 return (NULL);
3724 }
3725 /* FALLTHRU */
3726 case DTRACE_JSON_NUMBER_EXP:
3727 if (isdigit(cc) || cc == '+' || cc == '-') {
3728 *dd++ = cc;
3729 break;
3730 }
3731
3732 *dd = '\0';
3733 dd = dest; /* reset string buffer */
3734 if (found_key) {
3735 if (nelems > 1) {
3736 /*
3737 * ERROR: We expected an object, not
3738 * this number.
3739 */
3740 return (NULL);
3741 }
3742 return (dest);
3743 }
3744
3745 cur--;
3746 state = DTRACE_JSON_COMMA;
3747 break;
3748 case DTRACE_JSON_VALUE:
3749 if (isspace(cc))
3750 break;
3751
3752 if (cc == '{' || cc == '[') {
3753 if (nelems > 1 && found_key) {
3754 in_array = cc == '[' ? B_TRUE : B_FALSE;
3755 /*
3756 * If our element selector directs us
3757 * to descend into this nested object,
3758 * then move to the next selector
3759 * element in the list and restart the
3760 * state machine.
3761 */
3762 while (*elem != '\0')
3763 elem++;
3764 elem++; /* skip the inter-element NUL */
3765 nelems--;
3766 dd = dest;
3767 if (in_array) {
3768 state = DTRACE_JSON_VALUE;
3769 array_pos = 0;
3770 array_elem = dtrace_strtoll(
3771 elem, 10, size);
3772 found_key = array_elem == 0 ?
3773 B_TRUE : B_FALSE;
3774 } else {
3775 found_key = B_FALSE;
3776 state = DTRACE_JSON_OBJECT;
3777 }
3778 break;
3779 }
3780
3781 /*
3782 * Otherwise, we wish to either skip this
3783 * nested object or return it in full.
3784 */
3785 if (cc == '[')
3786 brackets = 1;
3787 else
3788 braces = 1;
3789 *dd++ = cc;
3790 state = DTRACE_JSON_COLLECT_OBJECT;
3791 break;
3792 }
3793
3794 if (cc == '"') {
3795 state = DTRACE_JSON_STRING;
3796 break;
3797 }
3798
3799 if (islower(cc)) {
3800 /*
3801 * Here we deal with true, false and null.
3802 */
3803 *dd++ = cc;
3804 state = DTRACE_JSON_IDENTIFIER;
3805 break;
3806 }
3807
3808 if (cc == '-' || isdigit(cc)) {
3809 *dd++ = cc;
3810 state = DTRACE_JSON_NUMBER;
3811 break;
3812 }
3813
3814 /*
3815 * ERROR: unexpected character at start of value.
3816 */
3817 return (NULL);
3818 case DTRACE_JSON_COLLECT_OBJECT:
3819 if (cc == '\0')
3820 /*
3821 * ERROR: unexpected end of input.
3822 */
3823 return (NULL);
3824
3825 *dd++ = cc;
3826 if (cc == '"') {
3827 collect_object = B_TRUE;
3828 state = DTRACE_JSON_STRING;
3829 break;
3830 }
3831
3832 if (cc == ']') {
3833 if (brackets-- == 0) {
3834 /*
3835 * ERROR: unbalanced brackets.
3836 */
3837 return (NULL);
3838 }
3839 } else if (cc == '}') {
3840 if (braces-- == 0) {
3841 /*
3842 * ERROR: unbalanced braces.
3843 */
3844 return (NULL);
3845 }
3846 } else if (cc == '{') {
3847 braces++;
3848 } else if (cc == '[') {
3849 brackets++;
3850 }
3851
3852 if (brackets == 0 && braces == 0) {
3853 if (found_key) {
3854 *dd = '\0';
3855 return (dest);
3856 }
3857 dd = dest; /* reset string buffer */
3858 state = DTRACE_JSON_COMMA;
3859 }
3860 break;
3861 }
3862 }
3863 return (NULL);
3864 }
3865
3866 /*
3867 * Emulate the execution of DTrace ID subroutines invoked by the call opcode.
3868 * Notice that we don't bother validating the proper number of arguments or
3869 * their types in the tuple stack. This isn't needed because all argument
3870 * interpretation is safe because of our load safety -- the worst that can
3871 * happen is that a bogus program can obtain bogus results.
3872 */
3873 static void
3874 dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
3875 dtrace_key_t *tupregs, int nargs,
3876 dtrace_mstate_t *mstate, dtrace_state_t *state)
3877 {
3878 volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
3879 volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;
3880 dtrace_vstate_t *vstate = &state->dts_vstate;
3881
3882 union {
3883 mutex_impl_t mi;
3884 uint64_t mx;
3885 } m;
3886
4546 if (index >= len || index < 0) {
4547 remaining = 0;
4548 } else if (remaining < 0) {
4549 remaining += len - index;
4550 } else if (index + remaining > size) {
4551 remaining = size - index;
4552 }
4553
4554 for (i = 0; i < remaining; i++) {
4555 if ((d[i] = dtrace_load8(s + index + i)) == '\0')
4556 break;
4557 }
4558
4559 d[i] = '\0';
4560
4561 mstate->dtms_scratch_ptr += size;
4562 regs[rd] = (uintptr_t)d;
4563 break;
4564 }
4565
4566 case DIF_SUBR_JSON: {
4567 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4568 uintptr_t json = tupregs[0].dttk_value;
4569 size_t jsonlen = dtrace_strlen((char *)json, size);
4570 uintptr_t elem = tupregs[1].dttk_value;
4571 size_t elemlen = dtrace_strlen((char *)elem, size);
4572
4573 char *dest = (char *)mstate->dtms_scratch_ptr;
4574 char *elemlist = (char *)mstate->dtms_scratch_ptr + jsonlen + 1;
4575 char *ee = elemlist;
4576 int nelems = 1;
4577 uintptr_t cur;
4578
4579 if (!dtrace_canload(json, jsonlen + 1, mstate, vstate) ||
4580 !dtrace_canload(elem, elemlen + 1, mstate, vstate)) {
4581 regs[rd] = NULL;
4582 break;
4583 }
4584
4585 if (!DTRACE_INSCRATCH(mstate, jsonlen + 1 + elemlen + 1)) {
4586 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4587 regs[rd] = NULL;
4588 break;
4589 }
4590
4591 /*
4592 * Read the element selector and split it up into a packed list
4593 * of strings.
4594 */
4595 for (cur = elem; cur < elem + elemlen; cur++) {
4596 char cc = dtrace_load8(cur);
4597
4598 if (cur == elem && cc == '[') {
4599 /*
4600 * If the first element selector key is
4601 * actually an array index then ignore the
4602 * bracket.
4603 */
4604 continue;
4605 }
4606
4607 if (cc == ']')
4608 continue;
4609
4610 if (cc == '.' || cc == '[') {
4611 nelems++;
4612 cc = '\0';
4613 }
4614
4615 *ee++ = cc;
4616 }
4617 *ee++ = '\0';
4618
4619 if ((regs[rd] = (uintptr_t)dtrace_json(size, json, elemlist,
4620 nelems, dest)) != NULL)
4621 mstate->dtms_scratch_ptr += jsonlen + 1;
4622 break;
4623 }
4624
4625 case DIF_SUBR_TOUPPER:
4626 case DIF_SUBR_TOLOWER: {
4627 uintptr_t s = tupregs[0].dttk_value;
4628 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4629 char *dest = (char *)mstate->dtms_scratch_ptr, c;
4630 size_t len = dtrace_strlen((char *)s, size);
4631 char lower, upper, convert;
4632 int64_t i;
4633
4634 if (subr == DIF_SUBR_TOUPPER) {
4635 lower = 'a';
4636 upper = 'z';
4637 convert = 'A';
4638 } else {
4639 lower = 'A';
4640 upper = 'Z';
4641 convert = 'a';
4642 }
4643
4644 if (!dtrace_canload(s, len + 1, mstate, vstate)) {
4912
4913 for (;;) {
4914 if (i >= size) {
4915 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4916 regs[rd] = NULL;
4917 break;
4918 }
4919
4920 if ((d[i++] = dtrace_load8(s2++)) == '\0')
4921 break;
4922 }
4923
4924 if (i < size) {
4925 mstate->dtms_scratch_ptr += i;
4926 regs[rd] = (uintptr_t)d;
4927 }
4928
4929 break;
4930 }
4931
4932 case DIF_SUBR_STRTOLL: {
4933 uintptr_t s = tupregs[0].dttk_value;
4934 uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
4935 int base = 10;
4936
4937 if (nargs > 1) {
4938 if ((base = tupregs[1].dttk_value) <= 1 ||
4939 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4940 *flags |= CPU_DTRACE_ILLOP;
4941 break;
4942 }
4943 }
4944
4945 if (!dtrace_strcanload(s, size, mstate, vstate)) {
4946 regs[rd] = INT64_MIN;
4947 break;
4948 }
4949
4950 regs[rd] = dtrace_strtoll((char *)s, base, size);
4951 break;
4952 }
4953
4954 case DIF_SUBR_LLTOSTR: {
4955 int64_t i = (int64_t)tupregs[0].dttk_value;
4956 uint64_t val, digit;
4957 uint64_t size = 65; /* enough room for 2^64 in binary */
4958 char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
4959 int base = 10;
4960
4961 if (nargs > 1) {
4962 if ((base = tupregs[1].dttk_value) <= 1 ||
4963 base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
4964 *flags |= CPU_DTRACE_ILLOP;
4965 break;
4966 }
4967 }
4968
4969 val = (base == 10 && i < 0) ? i * -1 : i;
4970
4971 if (!DTRACE_INSCRATCH(mstate, size)) {
4972 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
4973 regs[rd] = NULL;
9463 case DIF_OP_LDTAA:
9464 err += efunc(pc, "illegal dynamic variable load\n");
9465 break;
9466
9467 case DIF_OP_STTS:
9468 case DIF_OP_STGAA:
9469 case DIF_OP_STTAA:
9470 err += efunc(pc, "illegal dynamic variable store\n");
9471 break;
9472
9473 case DIF_OP_CALL:
9474 if (subr == DIF_SUBR_ALLOCA ||
9475 subr == DIF_SUBR_BCOPY ||
9476 subr == DIF_SUBR_COPYIN ||
9477 subr == DIF_SUBR_COPYINTO ||
9478 subr == DIF_SUBR_COPYINSTR ||
9479 subr == DIF_SUBR_INDEX ||
9480 subr == DIF_SUBR_INET_NTOA ||
9481 subr == DIF_SUBR_INET_NTOA6 ||
9482 subr == DIF_SUBR_INET_NTOP ||
9483 subr == DIF_SUBR_JSON ||
9484 subr == DIF_SUBR_LLTOSTR ||
9485 subr == DIF_SUBR_STRTOLL ||
9486 subr == DIF_SUBR_RINDEX ||
9487 subr == DIF_SUBR_STRCHR ||
9488 subr == DIF_SUBR_STRJOIN ||
9489 subr == DIF_SUBR_STRRCHR ||
9490 subr == DIF_SUBR_STRSTR ||
9491 subr == DIF_SUBR_HTONS ||
9492 subr == DIF_SUBR_HTONL ||
9493 subr == DIF_SUBR_HTONLL ||
9494 subr == DIF_SUBR_NTOHS ||
9495 subr == DIF_SUBR_NTOHL ||
9496 subr == DIF_SUBR_NTOHLL)
9497 break;
9498
9499 err += efunc(pc, "invalid subr %u\n", subr);
9500 break;
9501
9502 default:
9503 err += efunc(pc, "invalid opcode %u\n",
9504 DIF_INSTR_OP(instr));
9505 }
|