Skip to content

Unsoundness: Stream::close() does not consume the object but frees the underlying C object/DeviceInfo::from_c_info returns unbound lifetime #196

@t1mlange

Description

@t1mlange

Hi,

with following safe Rust code, it's possible to trigger a NPD:

use portaudio::*;

fn main() -> anyhow::Result<()> {
    let pa = PortAudio::new().unwrap();
    let def_output = pa.default_output_device()?;
    let output_info = pa.device_info(def_output)?;
    let latency = output_info.default_low_output_latency;
    let parameters = StreamParameters::new(
        def_output,
        2,
        true,
        latency,
    );
    let settings = InputStreamSettings::<f32>::new(
        parameters,
        44_100.0,
        1024 * 12,
    );

    let mut stream = pa.open_blocking_stream(settings)?;
    stream.start()?;
    println!("{:?}", stream.info());
    stream.close()?;
    println!("{:?}", stream.info());
    Ok(())
}

close() should either take ownership to prevent further access. However, I don't think it's exploitable, every method on Stream other than info() checks whether the stream is still alive before access.

Furthermore, it's possible to get an unbound lifetime for DeviceInfo through the From implementations, allowing a UAF on the name:

fn main() -> anyhow::Result<()> {
    let name;
    {
        let pa = PortAudio::new().unwrap();
        let def_output = pa.default_output_device()?;
        let output_info = pa.device_info(def_output)?;
        let output_info = DeviceInfo::from_c_info(PaDeviceInfo::from(output_info));
        name = output_info.name;    
    }
    println!("Device name: {}", name);
    Ok(())
}
==182589==ERROR: AddressSanitizer: heap-use-after-free on address 0x7bcad37ec730 at pc 0x56444d49f6b4 bp 0x7ffc05215cd0 sp 0x7ffc05215488
READ of size 4 at 0x7bcad37ec730 thread T0

I guess marking DeviceInfo::from_c_info() as unsafe should be sufficent (and making sure that all call sites do bind the lifetime).

Kind regards
Tim

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions