mirror of
https://github.com/lexmount/moli.git
synced 2026-10-30 16:07:24 +00:00
fix(webidl): isolate internal descriptor records from prototype pollution
This commit is contained in:
@@ -64,6 +64,10 @@ pub trait WebApiObjectDeclaration<'s> {
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain, data_properties, enumerable, no_dynamic_constructor)]
|
||||
pub struct DataPropertyDescriptorDeclaration<'scope> {
|
||||
// V8 converts this internal record with ToPropertyDescriptor, which also
|
||||
// reads inherited get/set fields. Author Object.prototype must not enter it.
|
||||
#[webapi(prototype, value = v8::null(scope))]
|
||||
prototype: (),
|
||||
value: v8::Local<'scope, v8::Value>,
|
||||
enumerable: bool,
|
||||
configurable: bool,
|
||||
@@ -73,6 +77,7 @@ pub struct DataPropertyDescriptorDeclaration<'scope> {
|
||||
impl<'scope> DataPropertyDescriptorDeclaration<'scope> {
|
||||
pub fn new(value: v8::Local<'scope, v8::Value>, writable: bool, enumerable: bool) -> Self {
|
||||
Self {
|
||||
prototype: (),
|
||||
value,
|
||||
enumerable,
|
||||
configurable: true,
|
||||
|
||||
@@ -68,11 +68,12 @@ where
|
||||
let prototype = prototype
|
||||
.to_v8_value(scope)
|
||||
.ok_or_else(|| BindError::new("failed to convert declared prototype"))?;
|
||||
let prototype = v8::Local::<v8::Object>::try_from(prototype)
|
||||
.map_err(|_| BindError::new("declared prototype must be an object"))?;
|
||||
let installed = object
|
||||
.set_prototype(scope, prototype.into())
|
||||
.unwrap_or(false);
|
||||
if !prototype.is_object() && !prototype.is_null() {
|
||||
return Err(BindError::new(
|
||||
"declared prototype must be an object or null",
|
||||
));
|
||||
}
|
||||
let installed = object.set_prototype(scope, prototype).unwrap_or(false);
|
||||
if !installed {
|
||||
return Err(BindError::new("failed to set declared prototype"));
|
||||
}
|
||||
|
||||
@@ -3094,3 +3094,55 @@ mod interfaces {
|
||||
pub(super) SampleTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn null_prototype_declarations_ignore_object_prototype_pollution() {
|
||||
#[derive(WebApiObject)]
|
||||
#[webapi(plain)]
|
||||
struct NullPrototype {
|
||||
#[webapi(prototype, value = v8::null(scope))]
|
||||
prototype: (),
|
||||
}
|
||||
|
||||
ensure_v8();
|
||||
let mut isolate = v8::Isolate::new(v8::CreateParams::default());
|
||||
let scope = pin!(v8::HandleScope::new(&mut isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Context::new(scope, Default::default());
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let object = NullPrototype::new().bind(scope).unwrap();
|
||||
assert!(object.get_prototype(scope).unwrap().is_null());
|
||||
let invalid = v8::Integer::new(scope, 1);
|
||||
assert!(moli_webapi_declare::set_declared_prototype(scope, object, &invalid).is_err());
|
||||
assert!(object.get_prototype(scope).unwrap().is_null());
|
||||
run_script(
|
||||
scope,
|
||||
"Object.prototype.get = () => { throw Error('inherited getter') };",
|
||||
);
|
||||
let value = v8::Integer::new(scope, 7);
|
||||
let descriptor =
|
||||
moli_webapi_declare::DataPropertyDescriptorDeclaration::new(value.into(), false, true)
|
||||
.bind(scope)
|
||||
.unwrap();
|
||||
assert!(descriptor.get_prototype(scope).unwrap().is_null());
|
||||
let global = context.global(scope);
|
||||
assert_eq!(
|
||||
global.create_data_property(
|
||||
scope,
|
||||
v8::String::new(scope, "descriptor").unwrap().into(),
|
||||
descriptor.into()
|
||||
),
|
||||
Some(true)
|
||||
);
|
||||
assert!(
|
||||
run_script(
|
||||
scope,
|
||||
r#"(() => {
|
||||
const target={};Object.defineProperty(target,'value',descriptor);
|
||||
const d=Object.getOwnPropertyDescriptor(target,'value');
|
||||
return target.value===7 && d.writable===false && d.enumerable && d.configurable;
|
||||
})()"#
|
||||
)
|
||||
.is_true()
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user