-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integer overflow 4527 v2 #6676
Integer overflow 4527 v2 #6676
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -524,7 +524,7 @@ static uint32_t AppLayerHtpComputeChunkLength(uint64_t content_len_so_far, uint3 | |
/* below error messages updated up to libhtp 0.5.7 (git 379632278b38b9a792183694a4febb9e0dbd1e7a) */ | ||
struct { | ||
const char *msg; | ||
int de; | ||
uint8_t de; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this not be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An enum value such as And it does not look like there is warning flag for Wimplicit-enum-int-conversion So, I think this patch is right There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm I always thought an enum would be an unsigned int, and be 32 bits. But now I'm reading that it may actually be up to the compiler to pick a type as long as it fits? Wonder what that means for using enums in Rust - C - FFI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess it means the enums should be defined in Rust, and exported to be used in C with cbindgen :-p There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
cbindgen outputs the following, I guess in a way to fix the type:
So that is one option. But it looks like the representation of enums has been an issue where the compilers use a different algorithm for layout, like rustc and msvc: Luckily it looks like rustc, clang, gcc all agree here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, let's rustify all the things There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it puts us on a path of one big super header file for C. Not sure if thats really that bad of a thing tho. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could not cbindgen generate one header file per rust module/directory ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No, thats not really how its designed. You could call it for each file manually and put those into headers. Then you'd have to worry about ordering of dependent data structures and so on. |
||
} htp_errors[] = { | ||
{ "GZip decompressor: inflateInit2 failed", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, | ||
{ "Request field invalid: colon missing", HTTP_DECODER_EVENT_REQUEST_FIELD_MISSING_COLON}, | ||
|
@@ -547,7 +547,7 @@ struct { | |
|
||
struct { | ||
const char *msg; | ||
int de; | ||
uint8_t de; | ||
} htp_warnings[] = { | ||
{ "GZip decompressor:", HTTP_DECODER_EVENT_GZIP_DECOMPRESSION_FAILED}, | ||
{ "Request field invalid", HTTP_DECODER_EVENT_REQUEST_HEADER_INVALID}, | ||
|
@@ -594,7 +594,7 @@ struct { | |
* | ||
* \retval id the id or 0 in case of not found | ||
*/ | ||
static int HTPHandleWarningGetId(const char *msg) | ||
static uint8_t HTPHandleWarningGetId(const char *msg) | ||
{ | ||
SCLogDebug("received warning \"%s\"", msg); | ||
size_t idx; | ||
|
@@ -618,7 +618,7 @@ static int HTPHandleWarningGetId(const char *msg) | |
* | ||
* \retval id the id or 0 in case of not found | ||
*/ | ||
static int HTPHandleErrorGetId(const char *msg) | ||
static uint8_t HTPHandleErrorGetId(const char *msg) | ||
{ | ||
SCLogDebug("received error \"%s\"", msg); | ||
|
||
|
@@ -675,7 +675,7 @@ static void HTPHandleError(HtpState *s, const uint8_t dir) | |
|
||
SCLogDebug("message %s", log->msg); | ||
|
||
int id = HTPHandleErrorGetId(log->msg); | ||
uint8_t id = HTPHandleErrorGetId(log->msg); | ||
if (id == 0) { | ||
id = HTPHandleWarningGetId(log->msg); | ||
if (id == 0) | ||
|
@@ -1255,9 +1255,9 @@ static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, | |
ft_len = USHRT_MAX; | ||
|
||
*filename = fn; | ||
*filename_len = fn_len; | ||
*filename_len = (uint16_t)fn_len; | ||
*filetype = ft; | ||
*filetype_len = ft_len; | ||
*filetype_len = (uint16_t)ft_len; | ||
} | ||
|
||
/** | ||
|
@@ -1304,8 +1304,8 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, | |
{ | ||
int result = 0; | ||
uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ | ||
uint32_t expected_boundary_len = htud->boundary_len + 2; | ||
uint32_t expected_boundary_end_len = htud->boundary_len + 4; | ||
uint16_t expected_boundary_len = htud->boundary_len + 2; | ||
uint16_t expected_boundary_end_len = htud->boundary_len + 4; | ||
int tx_progress = 0; | ||
|
||
#ifdef PRINT | ||
|
@@ -1434,7 +1434,7 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, | |
/* skip empty records */ | ||
if (expected_boundary_len == header_len) { | ||
goto next; | ||
} else if ((expected_boundary_len + 2) <= header_len) { | ||
} else if ((uint32_t)(expected_boundary_len + 2) <= header_len) { | ||
header_len -= (expected_boundary_len + 2); | ||
header = (uint8_t *)header_start + (expected_boundary_len + 2); // + for 0d 0a | ||
} | ||
|
@@ -1536,7 +1536,7 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, | |
SCLogDebug("offset %u", offset); | ||
htud->request_body.body_parsed += offset; | ||
|
||
if (filedata_len >= (expected_boundary_len + 2)) { | ||
if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) { | ||
filedata_len -= (expected_boundary_len + 2 - 1); | ||
SCLogDebug("opening file with partial data"); | ||
} else { | ||
|
@@ -1630,7 +1630,11 @@ static int HtpRequestBodyHandlePOSTorPUT(HtpState *hstate, HtpTxUserData *htud, | |
} | ||
|
||
if (filename != NULL) { | ||
result = HTPFileOpen(hstate, htud, filename, (uint32_t)filename_len, data, data_len, | ||
if (filename_len > UINT16_MAX) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this lead to an event? Also 64k seems very high still. If we consider There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we also have to consider that a 64k name leads to JSON records > 64k There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Event seems relevant. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I would like us to define our own PATH_MAX(-like) limit, as I think this behaviour in suri should not depend on whatever an OS might define. Since on Linux the default seems 4k I think that might be a good value to pick. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going with |
||
// explicitly truncate the file name if too long | ||
filename_len = UINT16_MAX; | ||
} | ||
result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, | ||
HtpGetActiveRequestTxID(hstate), STREAM_TOSERVER); | ||
if (result == -1) { | ||
goto end; | ||
|
@@ -1703,11 +1707,15 @@ static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, | |
if (filename != NULL) { | ||
// set range if present | ||
htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range"); | ||
if (filename_len > UINT16_MAX) { | ||
// explicitly truncate the file name if too long | ||
filename_len = UINT16_MAX; | ||
} | ||
if (h_content_range != NULL) { | ||
result = HTPFileOpenWithRange(hstate, htud, filename, (uint32_t)filename_len, data, | ||
result = HTPFileOpenWithRange(hstate, htud, filename, (uint16_t)filename_len, data, | ||
data_len, HtpGetActiveResponseTxID(hstate), h_content_range->value, htud); | ||
} else { | ||
result = HTPFileOpen(hstate, htud, filename, (uint32_t)filename_len, data, data_len, | ||
result = HTPFileOpen(hstate, htud, filename, (uint16_t)filename_len, data, data_len, | ||
HtpGetActiveResponseTxID(hstate), STREAM_TOCLIENT); | ||
} | ||
SCLogDebug("result %d", result); | ||
|
@@ -3025,7 +3033,7 @@ static int HTPRegisterPatternsForProtocolDetection(void) | |
* but the pattern matching should only be one char | ||
*/ | ||
register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, | ||
method_buffer, strlen(method_buffer) - 3, 0, STREAM_TOSERVER); | ||
method_buffer, (uint16_t)strlen(method_buffer) - 3, 0, STREAM_TOSERVER); | ||
if (register_result < 0) { | ||
return -1; | ||
} | ||
|
@@ -3035,7 +3043,8 @@ static int HTPRegisterPatternsForProtocolDetection(void) | |
/* Loop through all the http verions patterns that are TO_CLIENT */ | ||
for (versions_pos = 0; versions[versions_pos]; versions_pos++) { | ||
register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP1, | ||
versions[versions_pos], strlen(versions[versions_pos]), 0, STREAM_TOCLIENT); | ||
versions[versions_pos], (uint16_t)strlen(versions[versions_pos]), 0, | ||
STREAM_TOCLIENT); | ||
if (register_result < 0) { | ||
return -1; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -457,9 +457,12 @@ int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, | |
SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32, depth); | ||
StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth); | ||
|
||
uint16_t flen = (uint16_t)entity->filename_len; | ||
if (entity->filename_len > UINT16_MAX) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as for http: this seems far to big There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
flen = UINT16_MAX; | ||
} | ||
if (FileOpenFileWithId(files, &smtp_config.sbcfg, smtp_state->file_track_id++, | ||
(uint8_t *) entity->filename, entity->filename_len, | ||
(uint8_t *) chunk, len, flags) != 0) { | ||
(uint8_t *)entity->filename, flen, (uint8_t *)chunk, len, flags) != 0) { | ||
ret = MIME_DEC_ERR_DATA; | ||
SCLogDebug("FileOpenFile() failed"); | ||
} | ||
|
@@ -1154,7 +1157,11 @@ static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8 | |
return -1; | ||
memcpy(*target, state->current_line + i, spc_i - i); | ||
(*target)[spc_i - i] = '\0'; | ||
*target_len = spc_i - i; | ||
if (spc_i - i > UINT16_MAX) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this mean we're limiting lines to a max length now where previously we didn't? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Eheh no it does not mean that Previously (that is currently), we are already limiting lines to a max length But as there is an implicit cast from 'int' to 'uint16_t', if the line length is 65536, it will turn to zero (instead of saturating it to
So, should I rather increase the sizes of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. No lets not allow for ridiculously long lines. But I think it should lead to another event if we reach the limit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do |
||
*target_len = UINT16_MAX; | ||
} else { | ||
*target_len = (uint16_t)(spc_i - i); | ||
} | ||
|
||
return 0; | ||
} | ||
|
@@ -1215,6 +1222,9 @@ static int NoNewTx(SMTPState *state) | |
return 0; | ||
} | ||
|
||
/* XXX have a better name */ | ||
#define rawmsgname "rawmsg" | ||
|
||
static int SMTPProcessRequest(SMTPState *state, Flow *f, | ||
AppLayerParserState *pstate) | ||
{ | ||
|
@@ -1255,7 +1265,6 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, | |
SCMemcmpLowercase("data", state->current_line, 4) == 0) { | ||
state->current_command = SMTP_COMMAND_DATA; | ||
if (smtp_config.raw_extraction) { | ||
const char *msgname = "rawmsg"; /* XXX have a better name */ | ||
if (state->files_ts == NULL) | ||
state->files_ts = FileContainerAlloc(); | ||
if (state->files_ts == NULL) { | ||
|
@@ -1272,10 +1281,9 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, | |
TAILQ_INSERT_TAIL(&state->tx_list, tx, next); | ||
tx->tx_id = state->tx_cnt++; | ||
} | ||
if (FileOpenFileWithId(state->files_ts, &smtp_config.sbcfg, | ||
state->file_track_id++, | ||
(uint8_t*) msgname, strlen(msgname), NULL, 0, | ||
FILE_NOMD5|FILE_NOMAGIC|FILE_USE_DETECT) == 0) { | ||
if (FileOpenFileWithId(state->files_ts, &smtp_config.sbcfg, state->file_track_id++, | ||
(uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0, | ||
FILE_NOMD5 | FILE_NOMAGIC | FILE_USE_DETECT) == 0) { | ||
SMTPNewFile(state->curr_tx, state->files_ts->tail); | ||
} | ||
} else if (smtp_config.decode_mime) { | ||
|
@@ -1378,10 +1386,9 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, | |
} | ||
} | ||
|
||
static AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state, | ||
AppLayerParserState *pstate, const uint8_t *input, | ||
uint32_t input_len, | ||
SMTPThreadCtx *thread_data) | ||
static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state, | ||
AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len, | ||
SMTPThreadCtx *thread_data) | ||
{ | ||
SCEnter(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a runtime check for something that shouldn't be possible in practice, as iirc PATH_MAX is 4k. Should we use a static assertion here?
https://riptutorial.com/c/example/1842/static-assertion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to clarify: if we have a static assert that PATH_MAX < UINT16_MAX we can get rid of a runtime check like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, will do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
I did not know about static assertions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use the thing that is designed to do this, meaning static assertions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what I knew
#error
is designed to do this, I did not know about static assertionsThey seem to be equivalent here :
https://wiki.sei.cmu.edu/confluence/display/c/DCL03-C.+Use+a+static+assertion+to+test+the+value+of+a+constant+expression
static_assert
style looks more compact.So, it is in branch v4.
Are there other comments or should I make a PR with v4 ?