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

audio: fix device name use-after-free in AudioDevice::open #1012

Merged

Conversation

mautier
Copy link
Contributor

@mautier mautier commented Jun 23, 2020

Fixes a use-after-free in AudioDevice::open, which occurs when
selecting a particular device by name (as opposed to using a default
device).

Specifically, when extracting a C-style string pointer from a
Option<CString>, the option was consumed, its contents turned into a
pointer, and the original CString dropped. After that the C-style
string pointer is dangling, as its backing rust CString has been freed.

To fix this, the CString must be kept alive, which is achieved by simply
creating an intermediary Option<&CString>, and consuming that.

Example

When trying to open an audio recording device called HD Webcam C615 Analog Mono on my machine:

  • device_ptr points to @\xf4~UUU\x00\x00m C615 Analog Mono (which when interpreted as a null-terminated C string is actually just @\xf4~UUU), which shows that the user-provided name was clobbered somehow.
  • valgrind reports:
==9713== Invalid read of size 1
==9713==    at 0x4C33DA3: strcmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9713==    by 0x50D47E4: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.8.0)
==9713==    by 0x127B51: sdl2::audio::AudioDevice<CB>::open (audio.rs:658)
==9713==    by 0x1277AF: sdl2::audio::AudioDevice<CB>::open_capture (audio.rs:706)
==9713==    by 0x114F87: sdl2::audio::<impl sdl2::sdl::AudioSubsystem>::open_capture (audio.rs:93)
==9713==   [...]

==9713==  Address 0xb869fa0 is 0 bytes inside a block of size 27 free'd
==9713==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9713==    by 0x1360BD: alloc::alloc::dealloc (alloc.rs:103)
==9713==    by 0x136668: <alloc::alloc::Global as core::alloc::AllocRef>::dealloc (alloc.rs:179)
==9713==    by 0x1362CF: alloc::alloc::box_free (alloc.rs:245)
==9713==    by 0x135B06: core::ptr::drop_in_place (mod.rs:177)
==9713==    by 0x135A03: core::ptr::drop_in_place (mod.rs:177)
==9713==    by 0x1280DD: sdl2::audio::AudioDevice<CB>::open::{{closure}} (audio.rs:655)
==9713==    by 0x132A28: core::option::Option<T>::map_or (option.rs:483)
==9713==    by 0x127AC7: sdl2::audio::AudioDevice<CB>::open (audio.rs:655)
==9713==    by 0x1277AF: sdl2::audio::AudioDevice<CB>::open_capture (audio.rs:706)
==9713==    by 0x114F87: sdl2::audio::<impl sdl2::sdl::AudioSubsystem>::open_capture (audio.rs:93)
==9713==   [...]

==9713==  Block was alloc'd at
==9713==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9713==    by 0x14429E: alloc (alloc.rs:81)
==9713==    by 0x14429E: alloc (alloc.rs:172)
==9713==    by 0x14429E: allocate_in<u8,alloc::alloc::Global> (raw_vec.rs:87)
==9713==    by 0x14429E: with_capacity<u8> (raw_vec.rs:141)
==9713==    by 0x14429E: with_capacity<u8> (vec.rs:357)
==9713==    by 0x14429E: <&str as std::ffi::c_str::CString::new::SpecIntoVec>::into_vec (c_str.rs:345)
==9713==    by 0x13A397: std::ffi::c_str::CString::new (c_str.rs:351)
==9713==    by 0x127A3E: sdl2::audio::AudioDevice<CB>::open (audio.rs:652)
==9713==    by 0x1277AF: sdl2::audio::AudioDevice<CB>::open_capture (audio.rs:706)
==9713==    by 0x114F87: sdl2::audio::<impl sdl2::sdl::AudioSubsystem>::open_capture (audio.rs:93)
==9713==   [...]

After applying the proposed change, valgrind is appeased! 🌺

Fixes a use-after-free in `AudioDevice::open`, which occurs when
selecting a particular device by name (as opposed to using a default
device).

Specifically, when extracting a C-style string pointer from a
`Option<CString>`, the option was consumed, its contents turned into a
pointer, and the original `CString` dropped. After that the C-style
string pointer is dangling, as its backing rust CString has been freed.

To fix this, the CString must be kept alive, which is achieved by simply
creating an intermediary `Option<&CString>`, and consuming that.
@mautier mautier marked this pull request as ready for review June 23, 2020 22:41
@mautier
Copy link
Contributor Author

mautier commented Jun 24, 2020

After some light grepping I found an additional instance of the issue in AudioQueue::open_queue, but that's it.

I saw a number of other locations where the option.as_ref().map_or() pattern (and other similar variants) is used, so maybe the comment block warning I added is too much? If so I'm happy to remove it.

@Cobrand
Copy link
Member

Cobrand commented Jun 24, 2020

Very good catch, thanks a lot!

@Cobrand Cobrand merged commit 99afa37 into Rust-SDL2:master Jun 24, 2020
@Cobrand
Copy link
Member

Cobrand commented Jun 24, 2020

As a side note, I think these ptr related issues are detected by clippy usually, aren't they? If they are, we should run a check with clippy on the whole project to be sure, and if they aren't, we should submit an issue report to clippy to add this as an edge-case.

@mautier
Copy link
Contributor Author

mautier commented Jun 24, 2020

Sadly it doesn't seem like clippy raises any red flags here…

There is a related lint: temporary_cstring_as_ptr, but it's too limited to catch this particular instance.
There's also an existing clippy tracking issue for extending that lint, but looks like it's been dormant for a while: rust-lang/rust-clippy#2045.

@mautier mautier deleted the audio/audio_device_name_open_use_after_free branch June 24, 2020 23:51
sypwex pushed a commit to sypwex/rust-sdl2 that referenced this pull request Jun 2, 2024
…ice_name_open_use_after_free

audio: fix device name use-after-free in AudioDevice::open
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.

2 participants