ni-media icon indicating copy to clipboard operation
ni-media copied to clipboard

Fix potential integer overflow at end of stream in media_foundation_helper

Open wro-ableton opened this issue 11 months ago • 1 comments

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 https://github.com/NativeInstruments/ni-media/issues/73

wro-ableton avatar Feb 27 '24 11:02 wro-ableton

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

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           

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar Feb 27 '24 11:02 codecov[bot]

Looks good to me.

ni-mheppner avatar Mar 01 '24 13:03 ni-mheppner

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

wro-ableton avatar Mar 01 '24 13:03 wro-ableton

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.

ni-mheppner avatar Mar 01 '24 14:03 ni-mheppner

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 );

wro-ableton avatar Mar 01 '24 15:03 wro-ableton

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.

ni-tsmit avatar Mar 01 '24 15:03 ni-tsmit

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

wro-ableton avatar Mar 01 '24 15:03 wro-ableton