static int ByteTest12 (void) { const char *str = "-1234567890"; int32_t val = -1234567890; int32_t i32 = 0xbfbfbfbf; int ret = ByteExtractStringInt32(&i32, 10, strlen(str), str); if ((ret == 11) && (i32 == val)) { return 1; } return 0; }
DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) { DetectBytejumpData *data = NULL; char *args[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int numargs = 0; int i = 0; uint32_t nbytes; char *str_ptr; char *end_ptr; /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 2 || ret > 10) { SCLogError(SC_ERR_PCRE_PARSE,"parse error, ret %" PRId32 ", string \"%s\"", ret, optstr); goto error; } /* The first two arguments are stashed in the first PCRE substring. * This is because byte_jump can take 10 arguments, but PCRE only * supports 9 substrings, sigh. */ res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, 1, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed " "for arg 1"); goto error; } /* Break up first substring into two parameters * * NOTE: Because of this, we cannot free args[1] as it is part of args[0], * and *yes* this *is* ugly. */ end_ptr = str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++; *(end_ptr++) = '\0'; args[0] = str_ptr; numargs++; str_ptr = end_ptr; while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++; end_ptr = str_ptr; while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0')) end_ptr++; *(end_ptr++) = '\0'; args[1] = str_ptr; numargs++; /* The remaining args are directly from PCRE substrings */ for (i = 1; i < (ret - 1); i++) { res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, (const char **)&str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed for arg %d", i + 1); goto error; } args[i+1] = str_ptr; numargs++; } /* Initialize the data */ data = SCMalloc(sizeof(DetectBytejumpData)); if (unlikely(data == NULL)) goto error; data->base = DETECT_BYTEJUMP_BASE_UNSET; data->flags = 0; data->multiplier = 1; data->post_offset = 0; /* * The first two options are required and positional. The * remaining arguments are flags and are not positional. */ /* Number of bytes */ if (ByteExtractStringUint32(&nbytes, 10, strlen(args[0]), args[0]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", optstr); goto error; } /* Offset */ if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_jump supplied with " "var name for offset. \"value\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[1]); if (*offset == NULL) goto error; } else { if (ByteExtractStringInt32(&data->offset, 0, strlen(args[1]), args[1]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed offset: %s", optstr); goto error; } } /* The remaining options are flags. */ /** \todo Error on dups? */ for (i = 2; i < numargs; i++) { if (strcmp("relative", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_RELATIVE; } else if (strcasecmp("string", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_STRING; } else if (strcasecmp("dec", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_DEC; } else if (strcasecmp("hex", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_HEX; } else if (strcasecmp("oct", args[i]) == 0) { data->base |= DETECT_BYTEJUMP_BASE_OCT; } else if (strcasecmp("big", args[i]) == 0) { if (data->flags & DETECT_BYTEJUMP_LITTLE) { data->flags ^= DETECT_BYTEJUMP_LITTLE; } data->flags |= DETECT_BYTEJUMP_BIG; } else if (strcasecmp("little", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_LITTLE; } else if (strcasecmp("from_beginning", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_BEGIN; } else if (strcasecmp("align", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_ALIGN; } else if (strncasecmp("multiplier ", args[i], 11) == 0) { if (ByteExtractStringUint32(&data->multiplier, 10, strlen(args[i]) - 11, args[i] + 11) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed multiplier: %s", optstr); goto error; } } else if (strncasecmp("post_offset ", args[i], 12) == 0) { if (ByteExtractStringInt32(&data->post_offset, 10, strlen(args[i]) - 12, args[i] + 12) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed post_offset: %s", optstr); goto error; } } else if (strcasecmp("dce", args[i]) == 0) { data->flags |= DETECT_BYTEJUMP_DCE; } else { SCLogError(SC_ERR_INVALID_VALUE, "Unknown option: \"%s\"", args[i]); goto error; } } if (data->flags & DETECT_BYTEJUMP_STRING) { /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow uint64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "01777777777777777777777" = 0xffffffffffffffff */ if (nbytes > 23) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes " "with \"string\": %s", optstr); goto error; } } else { if (nbytes > 8) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes " "without \"string\": %s\n", optstr); goto error; } if (data->base != DETECT_BYTEJUMP_BASE_UNSET) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base " "without \"string\": %s", optstr); goto error; } } /* This is max 23 so it will fit in a byte (see above) */ data->nbytes = (uint8_t)nbytes; for (i = 0; i < numargs; i++){ if (i == 1) continue; /* args[1] is part of args[0] */ if (args[i] != NULL) SCFree(args[i]); } return data; error: for (i = 0; i < numargs; i++){ if (i == 1) continue; /* args[1] is part of args[0] */ if (args[i] != NULL) SCFree(args[i]); } if (data != NULL) DetectBytejumpFree(data); return NULL; }
static DetectBytetestData *DetectBytetestParse(const char *optstr, char **value, char **offset) { DetectBytetestData *data = NULL; char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; uint32_t nbytes; const char *str_ptr = NULL; /* Execute the regex and populate args with captures. */ ret = pcre_exec(parse_regex, parse_regex_study, optstr, strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 6 || ret > 10) { SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32 ", string %s", ret, optstr); goto error; } for (i = 0; i < (ret - 1); i++) { res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for arg %d", i + 1); goto error; } args[i] = (char *)str_ptr; } /* Initialize the data */ data = SCMalloc(sizeof(DetectBytetestData)); if (unlikely(data == NULL)) goto error; data->base = DETECT_BYTETEST_BASE_UNSET; data->flags = 0; /* * The first four options are required and positional. The * remaining arguments are flags and are not positional. */ /* Number of bytes */ if (ByteExtractStringUint32(&nbytes, 10, 0, args[0]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", str_ptr); goto error; } /* Operator is next two args: neg + op */ data->op = 0; if (args[1] != NULL && *args[1] == '!') { data->flags |= DETECT_BYTETEST_NEGOP; } if (args[2] != NULL) { if ((strcmp("=", args[2]) == 0) || ((data->flags & DETECT_BYTETEST_NEGOP) && strcmp("", args[2]) == 0)) { data->op |= DETECT_BYTETEST_OP_EQ; } else if (strcmp("<", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_LT; } else if (strcmp(">", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_GT; } else if (strcmp("&", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_AND; } else if (strcmp("^", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_OR; } else if (strcmp(">=", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_GE; } else if (strcmp("<=", args[2]) == 0) { data->op |= DETECT_BYTETEST_OP_LE; } else { SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator"); goto error; } } /* Value */ if (args[3][0] != '-' && isalpha((unsigned char)args[3][0])) { if (value == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with " "var name for value. \"value\" argument supplied to " "this function has to be non-NULL"); goto error; } *value = SCStrdup(args[3]); if (*value == NULL) goto error; } else { if (ByteExtractStringUint64(&data->value, 0, 0, args[3]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed value: %s", str_ptr); goto error; } } /* Offset */ if (args[4][0] != '-' && isalpha((unsigned char)args[4][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with " "var name for offset. \"offset\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[4]); if (*offset == NULL) goto error; } else { if (ByteExtractStringInt32(&data->offset, 0, 0, args[4]) <= 0) { SCLogError(SC_ERR_INVALID_VALUE, " Malformed offset: %s", str_ptr); goto error; } } /* The remaining options are flags. */ /** \todo Error on dups? */ for (i = 5; i < (ret - 1); i++) { if (args[i] != NULL) { if (strcmp("relative", args[i]) == 0) { data->flags |= DETECT_BYTETEST_RELATIVE; } else if (strcasecmp("string", args[i]) == 0) { data->flags |= DETECT_BYTETEST_STRING; } else if (strcasecmp("dec", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_DEC; } else if (strcasecmp("hex", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_HEX; } else if (strcasecmp("oct", args[i]) == 0) { data->base |= DETECT_BYTETEST_BASE_OCT; } else if (strcasecmp("big", args[i]) == 0) { if (data->flags & DETECT_BYTETEST_LITTLE) { data->flags ^= DETECT_BYTETEST_LITTLE; } data->flags |= DETECT_BYTETEST_BIG; } else if (strcasecmp("little", args[i]) == 0) { data->flags |= DETECT_BYTETEST_LITTLE; } else if (strcasecmp("dce", args[i]) == 0) { data->flags |= DETECT_BYTETEST_DCE; } else { SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown value: \"%s\"", args[i]); goto error; } } } if (data->flags & DETECT_BYTETEST_STRING) { /* 23 - This is the largest string (octal, with a zero prefix) that * will not overflow uint64_t. The only way this length * could be over 23 and still not overflow is if it were zero * prefixed and we only support 1 byte of zero prefix for octal. * * "01777777777777777777777" = 0xffffffffffffffff */ if (nbytes > 23) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes with \"string\": %s", optstr); goto error; } } else { if (nbytes > 8) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes without \"string\": %s", optstr); goto error; } if (data->base != DETECT_BYTETEST_BASE_UNSET) { SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base without \"string\": %s", optstr); goto error; } } /* This is max 23 so it will fit in a byte (see above) */ data->nbytes = (uint8_t)nbytes; for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } return data; error: for (i = 0; i < (ret - 1); i++){ if (args[i] != NULL) SCFree(args[i]); } if (data != NULL) DetectBytetestFree(data); return NULL; }