diff --git a/moli-renderer-v8/src/context_bootstrap/window_accessors.rs b/moli-renderer-v8/src/context_bootstrap/window_accessors.rs index 6ac98cdedc..5c650b521a 100644 --- a/moli-renderer-v8/src/context_bootstrap/window_accessors.rs +++ b/moli-renderer-v8/src/context_bootstrap/window_accessors.rs @@ -24,9 +24,10 @@ pub(super) use helpers::{ window_child_context_handle, window_has_discarded_child_browsing_context, }; pub(super) use interceptors::{ - window_indexed_property_deleter, window_indexed_property_descriptor, - window_indexed_property_enumerator, window_indexed_property_getter, - window_indexed_property_query, window_named_properties_indexed_property_getter, + window_indexed_property_definer, window_indexed_property_deleter, + window_indexed_property_descriptor, window_indexed_property_enumerator, + window_indexed_property_getter, window_indexed_property_query, window_indexed_property_setter, + window_named_properties_indexed_property_getter, window_named_properties_indexed_property_query, window_named_property_getter, window_named_property_query, }; diff --git a/moli-renderer-v8/src/context_bootstrap/window_accessors/interceptors.rs b/moli-renderer-v8/src/context_bootstrap/window_accessors/interceptors.rs index 3173693d96..b91301018b 100644 --- a/moli-renderer-v8/src/context_bootstrap/window_accessors/interceptors.rs +++ b/moli-renderer-v8/src/context_bootstrap/window_accessors/interceptors.rs @@ -64,6 +64,17 @@ pub(in crate::context_bootstrap) fn window_indexed_property_getter<'s>( v8::Intercepted::kYes } +pub(in crate::context_bootstrap) fn window_indexed_property_setter( + _scope: &mut v8::PinScope<'_, '_>, + _index: u32, + _value: v8::Local<'_, v8::Value>, + _args: v8::PropertyCallbackArguments<'_>, + mut rv: v8::ReturnValue<'_, v8::Boolean>, +) -> v8::Intercepted { + rv.set_bool(false); + v8::Intercepted::kYes +} + pub(in crate::context_bootstrap) fn window_indexed_property_query<'s>( scope: &mut v8::PinScope<'s, '_>, index: u32, @@ -77,6 +88,17 @@ pub(in crate::context_bootstrap) fn window_indexed_property_query<'s>( v8::Intercepted::kYes } +pub(in crate::context_bootstrap) fn window_indexed_property_definer( + _scope: &mut v8::PinScope<'_, '_>, + _index: u32, + _descriptor: &v8::PropertyDescriptor, + _args: v8::PropertyCallbackArguments<'_>, + mut rv: v8::ReturnValue<'_, v8::Boolean>, +) -> v8::Intercepted { + rv.set_bool(false); + v8::Intercepted::kYes +} + pub(in crate::context_bootstrap) fn window_indexed_property_deleter<'s>( scope: &mut v8::PinScope<'s, '_>, index: u32, diff --git a/moli-renderer-v8/src/context_bootstrap/window_template.rs b/moli-renderer-v8/src/context_bootstrap/window_template.rs index 1d676371ef..66faf5ad3f 100644 --- a/moli-renderer-v8/src/context_bootstrap/window_template.rs +++ b/moli-renderer-v8/src/context_bootstrap/window_template.rs @@ -372,9 +372,11 @@ pub(crate) fn install_window_own_template_bindings<'s>( window_template.set_indexed_property_handler( v8::IndexedPropertyHandlerConfiguration::new() .getter(window_indexed_property_getter) + .setter(window_indexed_property_setter) .query(window_indexed_property_query) .deleter(window_indexed_property_deleter) .enumerator(window_indexed_property_enumerator) + .definer(window_indexed_property_definer) .descriptor(window_indexed_property_descriptor), ); // Window is a [Global] WebIDL interface. Blink installs its members on the diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs index a876706fd1..b88abf3575 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs @@ -15241,6 +15241,72 @@ fn main_window_indexed_child_deletion_is_live_and_not_cached() { ); } +#[test] +fn main_window_indexed_set_and_define_reject_every_array_index() { + let mut vm = new_storage_test_vm("https://window-indexed-write.test/"); + + let result = vm + .eval( + r#" +(() => { + const frame = document.createElement('iframe'); + (document.body || document.documentElement || document).appendChild(frame); + const child = frame.contentWindow; + const strictSetThrows = index => { + 'use strict'; + try { + window[index] = 'strict'; + return false; + } catch (error) { + return error instanceof TypeError; + } + }; + const defineThrows = (index, descriptor) => { + try { + Object.defineProperty(window, index, descriptor); + return false; + } catch (error) { + return error instanceof TypeError; + } + }; + + window[0] = 'sloppy'; + window[1] = 'sloppy'; + window[4294967294] = 'sloppy'; + const result = { + existingChildPreserved: window[0] === child, + existingStrictSetThrows: strictSetThrows(0), + existingReflectSet: Reflect.set(window, 0, 'reflect'), + existingReflectDefine: Reflect.defineProperty(window, 0, { value: 'reflect' }), + existingDefineThrows: defineThrows(0, { get: () => 'getter' }), + missingRemainsAbsent: window[1] === undefined, + missingStrictSetThrows: strictSetThrows(1), + missingReflectSet: Reflect.set(window, 1, 'reflect'), + missingReflectDefine: Reflect.defineProperty(window, 1, { value: 'reflect' }), + missingDefineThrows: defineThrows(1, { value: 'defined' }), + maxIndexRemainsAbsent: window[4294967294] === undefined, + maxIndexStrictSetThrows: strictSetThrows(4294967294), + maxIndexReflectSet: Reflect.set(window, 4294967294, 'reflect'), + maxIndexReflectDefine: Reflect.defineProperty(window, 4294967294, { value: 'reflect' }) + }; + window[4294967295] = 1; + result.nonIndexSet = window[4294967295]; + result.nonIndexReflectSet = Reflect.set(window, 4294967295, 2); + result.nonIndexAfterReflectSet = window[4294967295]; + result.nonIndexReflectDefine = Reflect.defineProperty(window, 4294967295, { value: 3 }); + result.nonIndexAfterDefine = window[4294967295]; + return JSON.stringify(result); +})() +"#, + ) + .expect("Window indexed write and define probe should evaluate"); + + assert_eq!( + result, + r#"{"existingChildPreserved":true,"existingStrictSetThrows":true,"existingReflectSet":false,"existingReflectDefine":false,"existingDefineThrows":true,"missingRemainsAbsent":true,"missingStrictSetThrows":true,"missingReflectSet":false,"missingReflectDefine":false,"missingDefineThrows":true,"maxIndexRemainsAbsent":true,"maxIndexStrictSetThrows":true,"maxIndexReflectSet":false,"maxIndexReflectDefine":false,"nonIndexSet":1,"nonIndexReflectSet":true,"nonIndexAfterReflectSet":2,"nonIndexReflectDefine":true,"nonIndexAfterDefine":3}"# + ); +} + #[tokio::test] async fn main_window_indexed_child_descriptor_matches_window_semantics() { let mut vm = new_storage_test_vm("https://window-indexed-descriptor.test/");