Skip to content
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

Fix potential integer overflow at end of stream in media_foundation_helper #74

Merged
merged 1 commit into from
Mar 1, 2024

Conversation

wro-ableton
Copy link
Contributor

If in SyncronousByteStream::Read, m_source.read() reaches the end of stream, boost::iostreams::file_descriptor returns -1 as an end of stream indicator. Previously, by casting the returned value to ULONG, an integer overflow would occur.
In the attached file, the observed behaviour then would be that the calling code in WMF would continue to attempt to read past the EOF indefinitely or until some unexpected state is reached.

To fix this, the end of stream indicator (-1) is caught and handled as "0 bytes read".

See the attached TestMp3.zip for a mp3 which triggers this edge case.

See Issue #73

Copy link

codecov bot commented Feb 27, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 83.10%. Comparing base (89eb1e3) to head (27b6639).

Additional details and impacted files
@@           Coverage Diff           @@
##           master      #74   +/-   ##
=======================================
  Coverage   83.10%   83.10%           
=======================================
  Files          82       82           
  Lines        2024     2024           
=======================================
  Hits         1682     1682           
  Misses        342      342           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ni-mheppner
Copy link
Contributor

Looks good to me.

@wro-ableton
Copy link
Contributor Author

If you all are fine with the change, feel free to merge. We'd definitely appreciate a quick fix. 😁

@ni-mheppner
Copy link
Contributor

Actually, are we sure that -1 is the only negative number a boost::iostreams::file_descriptor will ever return? According to the documentation it should be, but maybe checking the return code against negative numbers in general might be more robust.

Copy link
Collaborator

@FalconPDX FalconPDX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@@ -86,7 +86,8 @@ class SyncronousByteStream : public IMFByteStream

try
{
*read = static_cast<ULONG>( m_source.read( reinterpret_cast<char*>( buffer ), toRead ) );
const auto result = m_source.read( reinterpret_cast<char*>( buffer ), toRead );
*read = static_cast<ULONG>( result == -1 ? 0 : result );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to define -1 as "endOfSequence" for readability purposes?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to avoid magic numbers indeed.

@wro-ableton
Copy link
Contributor Author

I was wondering about that as well. It might be a bit defensive but maybe we could also catch any negative and translate the -1 end of sequence to 0, otherwise return either E_UNEXPECTED or E_FAIL. Any preference?

try
{
    const auto result =  m_source.read( reinterpret_cast<char*>( buffer ), toRead );
    if (result < -1) 
    {
        return E_FAIL;
    }
    *read = static_cast<ULONG>( result == -1 ? 0 : result );
    return S_OK;
}
catch ( const std::system_error& )
{
    return E_UNEXPECTED;
}
catch ( ... )
{
    return E_FAIL;
}

Alternatively, one could simply catch any "<0" cases with the following. S

*read = static_cast<ULONG>( result < 0 ? 0 : result );

@ni-tsmit
Copy link

ni-tsmit commented Mar 1, 2024

Looks good to me too, if read() promises non-negative or -1 as return value then I think a check against a define with endOfSequence suffices and tells the clearest story.

@wro-ableton
Copy link
Contributor Author

See fixup. So static constexpr auto endOfSequence =-1; but without the defensive return?

@@ -86,7 +86,8 @@ class SyncronousByteStream : public IMFByteStream

try
{
*read = static_cast<ULONG>( m_source.read( reinterpret_cast<char*>( buffer ), toRead ) );
const auto result = m_source.read( reinterpret_cast<char*>( buffer ), toRead );
*read = static_cast<ULONG>( result == -1 ? 0 : result );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to avoid magic numbers indeed.

If in SyncronousByteStream::Read, m_source.read() reaches the end of
stream, boost::iostreams::file_descriptor returns -1 as an end of stream
indicator. Previously, by casting the returned value to ULONG, an
integer overflow would occur. To fix this, the end of stream indicator
(-1) is caught and handled as "0 bytes read".
@ni-mheppner ni-mheppner merged commit 319c7fe into NativeInstruments:master Mar 1, 2024
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants