-
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
Conversation
Explicitly truncate a file name if it is longer than UINT16_MAX
Explicitly truncate file names to UINT16_MAX Before, they got implicitly truncated, meaning a UINT16_MAX + 1 file name, went to 0 file name (because of modulo 65536)
and explicitly truncating filename's length
especially increasing padding_len size
Codecov Report
@@ Coverage Diff @@
## master #6676 +/- ##
==========================================
- Coverage 77.19% 74.37% -2.83%
==========================================
Files 613 613
Lines 185646 185652 +6
==========================================
- Hits 143310 138073 -5237
- Misses 42336 47579 +5243
Flags with carried forward coverage won't be shown. Click here to find out more. |
Information: QA ran without warnings. Pipeline 5146 |
@@ -642,14 +642,18 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, | |||
* Min size has been checked in FTPParseRequestCommand | |||
* PATH_MAX includes the null | |||
*/ | |||
int file_name_len = MIN(PATH_MAX - 1, state->current_line_len - 5); | |||
uint32_t file_name_len = MIN(PATH_MAX - 1, state->current_line_len - 5); | |||
if (file_name_len > UINT16_MAX) { |
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
#if PATH_MAX > UINT16_MAX
#error PATH_MAX is greater than UINT16_MAX
#endif
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.
why not use the thing that is designed to do this, meaning static assertions?
For what I knew #error
is designed to do this, I did not know about static assertions
They 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 ?
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
should this not be unsigned int
as the values are defined in an enum
?
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.
An enum value such as HTTP_DECODER_EVENT_UNKNOWN_ERROR
should be defined as an int
(signed)
But we can safely cast it to uint8_t
as we do not have more than 256 values. I even think that this is some kind of preprocessing that acts as #define
Furthermore, we later call HTPSetEvent
which uses uint8_t
(because it calls AppLayerDecoderEventsSetEventRaw
which uses uint8_t
)
And it does not look like there is warning flag for Wimplicit-enum-int-conversion
cf https://releases.llvm.org/11.0.0/tools/clang/docs/DiagnosticsReference.html#wenum-conversion
So, I think this patch is right
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Wonder what that means for using enums in Rust - C - FFI.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Wonder what that means for using enums in Rust - C - FFI.
I guess it means the enums should be defined in Rust, and exported to be used in C with cbindgen :-p
cbindgen outputs the following, I guess in a way to fix the type:
enum HTTP2TransactionState {
HTTP2StateIdle = 0,
HTTP2StateOpen = 1,
HTTP2StateReserved = 2,
HTTP2StateDataClient = 3,
HTTP2StateHalfClosedClient = 4,
HTTP2StateDataServer = 5,
HTTP2StateHalfClosedServer = 6,
HTTP2StateClosed = 7,
HTTP2StateGlobal = 8,
};
typedef uint8_t HTTP2TransactionState;
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
So, let's rustify all the things
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Could not cbindgen generate one header file per rust module/directory ?
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.
@@ -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 comment
The 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 PATH_MAX
to be 4k for example.
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Event seems relevant.
PATH_MAX
seems a better limit as well.
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Going with SC_FILENAME_MAX
@@ -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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
@@ -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 comment
The 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 comment
The 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?
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 UINT16_MAX
)
app-layer-smtp.c:1157:25: warning: implicit conversion loses integer precision: 'int' to 'uint16_t' (aka 'unsigned short') [-Wimplicit-int-conversion]
*target_len = spc_i - i;
So, should I rather increase the sizes of uint16_t helo_len;
and such ?
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
Replaced by #6690 |
Link to redmine ticket:
https://redmine.openinfosecfoundation.org/issues/4527
Describe changes:
libhtp-pr: 339
There remains one warning about the use of
StreamTcpUpdateAppLayerProgress
cf discussion in #6649
Changes #6674 to get gcc happy about
u16 + 2 < u32
whereu16 + 2
should not become a signed integer