googleprojectzero / fuzzilli

A JavaScript Engine Fuzzer
Apache License 2.0
1.89k stars 306 forks source link

Problems related to tracking data dependencies during fuzzing #457

Open mobsceneZ opened 3 weeks ago

mobsceneZ commented 3 weeks ago

Hi @saelo, I am recently integrating some WebAssembly (abbreviated as Wasm) features into fuzzilli. Everything looks good to me when adjusting the static JS model. However, when I try to add some primitive code generators, the problem surfaces.

Consider the generation of a WebAssembly.Exception object, according to the specification, its construction requires two parameters:

A demonstrating example could be as follow, here i32 stands for JS numbers and i64 stands for JS BigInt:

const tag = new WebAssembly.Tag({ parameters: ["i32", "i64"] });
const exception1 = new WebAssembly.Exception(tag, [42, 100n]);        // ok
const exception2 = new WebAssembly.Exception(tag, [42, 100]);         // TypeError: Cannot convert 100 to a BigInt

Suppose we would like to construct a WebAssembly.Exception object via, let's say, CodeGenerator, we may write the following code:

CodeGenerator("WasmExceptionGenerator", inputs: .required(.jsWebAssemblyTagObject)) {
  // ... some code here ...
}

However, since variables inside Fuzzilli do not explicitly track the data stored inside them, we could not determine the shape of the passed-in input inside the generator. Thus, there is no way for us to construct an appropriate payload to the WebAssembly.Exception constructor, or we can only resort to the guard statement but that's generally not desired.

Theoretically, maybe we can use the DefUseAnalyzer to track the data sources of the input, but that could bring extra overhead to the fuzzing process. Currently I cannot come up with an elegant way to handle this problem so I open this issue to see if you can give any advices (since I am not 100% familiar with fuzzilli). Thanks in advance for any kind suggestions ;).

saelo commented 2 weeks ago

Hi and sorry for the slow reply! Yeah I agree, this is currently a limitation of the type system (we basically need some form of type nesting). For now I would suggest creating a CodeGenerator that always creates both the Tag and the Exception objects for it. Alternatively, you could define a few global tag "signatures" and always use those. Then at least the probability of getting the right one are reasonably high. Both of these are more workarounds, but we're also working on better Wasm integration at the moment (which includes features like nested types to solve these problems) and we'll open source that code hopefully soon...

mobsceneZ commented 1 week ago

Hi and sorry for the slow reply! Yeah I agree, this is currently a limitation of the type system (we basically need some form of type nesting). For now I would suggest creating a CodeGenerator that always creates both the Tag and the Exception objects for it. Alternatively, you could define a few global tag "signatures" and always use those. Then at least the probability of getting the right one are reasonably high. Both of these are more workarounds, but we're also working on better Wasm integration at the moment (which includes features like nested types to solve these problems) and we'll open source that code hopefully soon...

Thanks for your kind response! Yeah I am working on some workarounds for this problem as you suggested, btw, may I bother asking what does the type nesting mean in current context? A quick google search doesn't seem to give me insightful explanations 🤔.

saelo commented 1 week ago

With "nested type" I just mean something like that would allow you to write:

CodeGenerator("WasmExceptionGenerator", inputs: .required(.jsWebAssemblyTagObject)) { tagObject in
  let innerTypes = b.typeOf(tagObject).getInnerTypes()   // would give you [.integer, .bigint]
  ...
}

For example.

mobsceneZ commented 1 week ago

With "nested type" I just mean something like that would allow you to write:

CodeGenerator("WasmExceptionGenerator", inputs: .required(.jsWebAssemblyTagObject)) { tagObject in
  let innerTypes = b.typeOf(tagObject).getInnerTypes()   // would give you [.integer, .bigint]
  ...
}

For example.

Aha, I see! Thanks for the explanation and look forward to the later releases :)