From df8dcca9b511468dbbb655e6ae176cd33cfe4641 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 25 Oct 2017 15:41:29 -0700 Subject: [PATCH] Fix memory safety problem in `CGDataProvider::from_buffer()`. The wrapper for that function made no attempt to ensure that the buffer would stay alive, and as a result use-after-free could easily occur. The fix is to require that the buffer be stuffed in an `Arc` box and to teach Core Graphics how to release the `Arc` when it's done with it. --- Cargo.toml | 2 +- src/data_provider.rs | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ff303ed..afe1907 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "core-graphics" description = "Bindings to Core Graphics for OS X" homepage = "https://github.com/servo/core-graphics-rs" repository = "https://github.com/servo/core-graphics-rs" -version = "0.11.0" +version = "0.12.0" authors = ["The Servo Project Developers"] license = "MIT / Apache-2.0" diff --git a/src/data_provider.rs b/src/data_provider.rs index 7262934..9a10496 100644 --- a/src/data_provider.rs +++ b/src/data_provider.rs @@ -11,7 +11,8 @@ use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType}; use core_foundation::data::{CFData, CFDataRef}; use libc::{c_void, size_t, off_t}; -use std::ptr; +use std::mem; +use std::sync::Arc; use foreign_types::{ForeignType, ForeignTypeRef}; @@ -43,13 +44,21 @@ impl CGDataProvider { } } - pub fn from_buffer(buffer: &[u8]) -> Self { + /// Creates a data provider from the given reference-counted buffer. + /// + /// The `CGDataProvider` object takes ownership of the reference. Once the data provider + /// is destroyed, the reference count of the buffer is automatically decremented. + pub fn from_buffer(buffer: Arc>) -> Self { unsafe { - let result = CGDataProviderCreateWithData(ptr::null_mut(), - buffer.as_ptr() as *const c_void, - buffer.len() as size_t, - None); - CGDataProvider::from_ptr(result) + let ptr = (*buffer).as_ptr() as *const c_void; + let len = buffer.len() as size_t; + let info = mem::transmute::>, *mut c_void>(buffer); + let result = CGDataProviderCreateWithData(info, ptr, len, Some(release)); + return CGDataProvider::from_ptr(result); + } + + unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) { + drop(mem::transmute::<*mut c_void, Arc>>(info)) } } }