diff --git a/doc/userguide/capture-hardware/pcap-file.rst b/doc/userguide/capture-hardware/pcap-file.rst index f87d259b74fb..ad5f4a1412f3 100644 --- a/doc/userguide/capture-hardware/pcap-file.rst +++ b/doc/userguide/capture-hardware/pcap-file.rst @@ -31,6 +31,10 @@ This can improve performance, especially for large files. The size can be specified through the command line option, see :ref:`--pcap-file-buffer-size ` +Setting ``buffer-size`` to ``0`` disables ``setvbuf`` buffering. This is the +explicit opt-out for non-seekable sources such as ``/dev/stdin`` or named +pipes, where buffering the underlying file descriptor is not supported. + Directory-related options ------------------------- diff --git a/doc/userguide/partials/options.rst b/doc/userguide/partials/options.rst index 170677bff226..2ea8d0cd8a3b 100644 --- a/doc/userguide/partials/options.rst +++ b/doc/userguide/partials/options.rst @@ -90,7 +90,8 @@ .. option:: --pcap-file-buffer-size Set read buffer size using ``setvbuf`` to speed up pcap reading. Valid values - are 4 KiB to 64 MiB. Default value is 128 KiB. Supported on Linux only. + are 0, which disables ``setvbuf`` buffering, or 4 KiB to 64 MiB. Default + value is 128 KiB. Supported on Linux only. .. option:: -i diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index 11de01995f67..1c3ada2ed381 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -648,6 +648,10 @@ static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserS FTPTransaction *tx = FTPGetOldestTx(state, lasttx); if (tx == NULL) { tx = FTPTransactionCreate(state); + if (tx != NULL) { + /* This is a TC only transaction, skip TS inspection. */ + tx->tx_data.flags |= APP_LAYER_TX_SKIP_INSPECT_TS; + } } if (unlikely(tx == NULL)) { SCReturnStruct(APP_LAYER_ERROR); diff --git a/src/datasets-context-json.c b/src/datasets-context-json.c index 3cc17d22f824..1f60c5aaf4f9 100644 --- a/src/datasets-context-json.c +++ b/src/datasets-context-json.c @@ -419,6 +419,10 @@ static uint32_t DatajsonAddStringElement(Dataset *set, json_t *value, char *json } *found = true; + if (!json_is_string(key)) { + FatalErrorOnInit("dataset: %s failed to get value because it is not a string", set->name); + return 0; + } const char *val_key = json_string_value(key); if (val_key == NULL) { @@ -467,6 +471,10 @@ static uint32_t DatajsonAddMd5Element(Dataset *set, json_t *value, char *json_ke *found = true; + if (!json_is_string(key)) { + FatalErrorOnInit("dataset: %s failed to get value because it is not a string", set->name); + return 0; + } const char *hash_string = json_string_value(key); if (strlen(hash_string) != SC_MD5_HEX_LEN) { FatalErrorOnInit("Not correct length for a hash"); @@ -511,6 +519,10 @@ static uint32_t DatajsonAddSha256Element(Dataset *set, json_t *value, char *json *found = true; + if (!json_is_string(key)) { + FatalErrorOnInit("dataset: %s failed to get value because it is not a string", set->name); + return 0; + } const char *hash_string = json_string_value(key); if (strlen(hash_string) != SC_SHA256_HEX_LEN) { FatalErrorOnInit("Not correct length for a hash"); @@ -556,6 +568,10 @@ static uint32_t DatajsonAddIpv4Element(Dataset *set, json_t *value, char *json_k *found = true; + if (!json_is_string(key)) { + FatalErrorOnInit("dataset: %s failed to get value because it is not a string", set->name); + return 0; + } const char *ip_string = json_string_value(key); struct in_addr in; if (inet_pton(AF_INET, ip_string, &in) != 1) { @@ -596,6 +612,10 @@ static uint32_t DatajsonAddIPv6Element(Dataset *set, json_t *value, char *json_k *found = true; + if (!json_is_string(key)) { + FatalErrorOnInit("dataset: %s failed to get value because it is not a string", set->name); + return 0; + } const char *ip_string = json_string_value(key); struct in6_addr in6; int ret = DatasetParseIpv6String(set, ip_string, &in6); diff --git a/src/detect-ftpdata.c b/src/detect-ftpdata.c index 1fc4944eb167..1ef088b3b306 100644 --- a/src/detect-ftpdata.c +++ b/src/detect-ftpdata.c @@ -105,17 +105,7 @@ static int DetectFtpdataMatch(DetectEngineThreadCtx *det_ctx, if (ftp_state == NULL) return 0; - if (ftpcommandd->command == ftp_state->command) { - /* Only match if the flow is in the good direction */ - if ((flags & STREAM_TOSERVER) && (ftpcommandd->command == FTP_COMMAND_RETR)) { - return 0; - } else if ((flags & STREAM_TOCLIENT) && (ftpcommandd->command == FTP_COMMAND_STOR)) { - return 0; - } - return 1; - } - - return 0; + return ftpcommandd->command == ftp_state->command; } /** diff --git a/src/detect-pcre.c b/src/detect-pcre.c index 1aaec6d35dfa..cc278fd7bf55 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -708,6 +708,21 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, if (capture_names == NULL || strlen(capture_names) == 0) opts |= PCRE2_NO_AUTO_CAPTURE; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // forbid use of \X Unicode extended grapheme cluster as slow + bool escape = false; + for (size_t i = 0; i < strlen(re); i++) { + if (escape) { + if (re[i] == 'X') { + goto error; + } + escape = false; + } else if (re[i] == '\\') { + escape = true; + } + } + +#endif pd->parse_regex.regex = pcre2_compile((PCRE2_SPTR8)re, PCRE2_ZERO_TERMINATED, opts, &en, &eo2, NULL); if (pd->parse_regex.regex == NULL && en == 115) { // reference to nonexistent subpattern diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c index a2c604347585..abb7b6b43ccf 100644 --- a/src/source-pcap-file-helper.c +++ b/src/source-pcap-file-helper.c @@ -210,10 +210,16 @@ TmEcode InitPcapFile(PcapFileFileVars *pfv) #if defined(HAVE_SETVBUF) && defined(OS_LINUX) if (pcap_g.read_buffer_size > 0) { - errno = 0; - if (setvbuf(pcap_file(pfv->pcap_handle), pfv->buffer, _IOFBF, pcap_g.read_buffer_size) < - 0) { - SCLogWarning("Failed to setvbuf on PCAP file handle: %s", strerror(errno)); + struct stat sb; + int fd = fileno(pcap_file(pfv->pcap_handle)); + if (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISREG(sb.st_mode)) { + SCLogInfo("%s: skipping setvbuf, underlying fd is not a regular file", pfv->filename); + } else { + errno = 0; + if (setvbuf(pcap_file(pfv->pcap_handle), pfv->buffer, _IOFBF, + pcap_g.read_buffer_size) != 0) { + SCLogWarning("Failed to setvbuf on PCAP file handle: %s", strerror(errno)); + } } } #endif diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index e8b9c6e4c6f9..22153432bb61 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2016 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -155,13 +155,19 @@ void PcapFileGlobalInit(void) if (SCConfGetNonNull("pcap-file.buffer-size", &str) == 1) { uint32_t value = 0; if (ParseSizeStringU32(str, &value) < 0) { - SCLogWarning("failed to parse pcap-file.buffer-size %s", str); - } - if (value >= PCAP_FILE_BUFFER_SIZE_MIN && value <= PCAP_FILE_BUFFER_SIZE_MAX) { - SCLogInfo("Pcap-file will use %u buffer size", value); + SCLogWarning("failed to parse pcap-file.buffer-size %s; keeping default %u", str, + PCAP_FILE_BUFFER_SIZE_DEFAULT); + } else if (value == 0 || + (value >= PCAP_FILE_BUFFER_SIZE_MIN && value <= PCAP_FILE_BUFFER_SIZE_MAX)) { + if (value == 0) { + SCLogInfo("Pcap-file buffering disabled"); + } else { + SCLogInfo("Pcap-file will use %u buffer size", value); + } pcap_g.read_buffer_size = value; } else { - SCLogWarning("pcap-file.buffer-size value of %u is invalid. Valid range is %u-%u", + SCLogWarning("pcap-file.buffer-size value of %u is invalid. Valid values are 0 to " + "disable buffering, or %u-%u", value, PCAP_FILE_BUFFER_SIZE_MIN, PCAP_FILE_BUFFER_SIZE_MAX); } }