-
Notifications
You must be signed in to change notification settings - Fork 285
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
JsArrayBuffer::external
soundness hole
#896
Comments
JsArrayBuffer::external
is unsafeJsArrayBuffer::external
soundness hole
@Cassy343 Good find! It looks like both A more minimal example demonstrating the soundness hole: pub fn soundness_hole(mut cx: FunctionContext) -> JsResult<JsArrayBuffer> {
let mut data = vec![0u8, 1, 2, 3];
let buf = JsArrayBuffer::external(&mut cx, data.as_mut_slice());
Ok(buf)
// `data` is dropped here, but `buf` is holding a reference!
} A longer example that clearly shows the data dropping while a reference is still held: struct BytesMut(Vec<u8>);
impl Drop for BytesMut {
fn drop(&mut self) {
eprintln!("Dropping `BytesMut`!");
}
}
impl AsMut<[u8]> for BytesMut {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}
pub fn soundness_hole(mut cx: FunctionContext) -> JsResult<JsArrayBuffer> {
let mut data = BytesMut(vec![0, 1, 2, 3]);
let buf = JsArrayBuffer::external(&mut cx, data.as_mut());
drop(data);
Ok(buf)
} With the bound, this is properly a compile error:
I have not directly tested your example, but it should be identical since |
…d `JsBuffer::external` Fixes #896
There's another more subtle error (bug?) that shows up when you only add use neon::prelude::*;
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("empty_buf", move |mut cx| {
let buffer = JsArrayBuffer::external(
&mut cx,
&mut []
);
Ok(buffer)
})?;
Ok(())
} Result:
I'm not sure if the right choice here is to just clearly document this behavior (if it's expected), or bite the bullet and require an owned value (perhaps |
@Cassy343 That's interesting because it seems to be related to internal behavior of V8 that expects unique references. Nothing about this is unsafe from a Rust perspective. This is only possible with an empty array. Rust's ownership rules would prevent this as soon as there is data (wouldn't be able to get multiple I'm more comfortable filing that as a separate bug and taking time to identify the problem since it's not a potential security issue (like the current problem). |
Sounds good, I'll leave you to file that since I think you have a better idea of how to categorize/characterize the problem. |
It actually looks like it might be a Node issue: Node #32463. It used to work and no longer does. Interestingly, I've only been able to make it happen in the REPL. |
I did a little more testing and the issue you found with duplicate of the same (empty) pointer is fixed in Node 17 and Node 18. |
@Cassy343 Thanks so much for reporting this issue! This has been fixed and published in Neon |
Undefined behavior can be triggered with a misuse of
JsArrayBuffer::external
using safe code.Rust:
JavaScript:
Result:
The text was updated successfully, but these errors were encountered: