Skip to content

Commit

Permalink
Fuzzer part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
tomusdrw committed Dec 11, 2024
1 parent 6eedb90 commit c4c18c2
Show file tree
Hide file tree
Showing 7 changed files with 2,132 additions and 10 deletions.
10 changes: 10 additions & 0 deletions assembly/arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ function decodeI32(data: Uint8Array): u32 {
return num;
}

export function encodeI32(input: i32): u8[] {
const data: u8[] = [];
let num = u32(input);
while (num > 0) {
data.push(u8(num));
num >>= 8;
}
return data;
}

function decodeU32(data: Uint8Array): u32 {
let num = u32(data[0]);
num |= u32(data[1]) << 8;
Expand Down
1 change: 1 addition & 0 deletions assembly/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { decodeProgram, decodeSpi, liftBytes } from "./program";

export * from "./api";
export { runVm, getAssembly } from "./api-generic";
export { wrapAsProgram } from "./program";

export enum InputKind {
Generic = 0,
Expand Down
58 changes: 57 additions & 1 deletion assembly/program.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Args, Arguments, DECODERS, REQUIRED_BYTES } from "./arguments";
import { Args, Arguments, DECODERS, REQUIRED_BYTES, encodeI32 } from "./arguments";
import { Decoder } from "./codec";
import { INSTRUCTIONS, MISSING_INSTRUCTION } from "./instructions";

Expand Down Expand Up @@ -36,6 +36,33 @@ export function lowerBytes(data: Uint8Array): u8[] {
return r;
}

/** Turn given bytecode into a valid program. Add JumpTable and Mask. */
export function wrapAsProgram(bytecode: Uint8Array): Uint8Array {
const jumpTableLength: u8 = 0;
const jumpTableItemLength: u8 = 0;
const codeLength = bytecode.length;
const mask = buildMask(bytecode);
const codeLengthBytes = encodeI32(codeLength);

const data = new Uint8Array(1 + 1 + codeLengthBytes.length + codeLength + mask.length);
data[0] = jumpTableLength;
data[1] = jumpTableItemLength;
let offset = 2;
for (let i = 0; i < codeLengthBytes.length; i++) {
data[offset] = codeLengthBytes[i];
offset++;
}
for (let i = 0; i < bytecode.length; i++) {
data[offset] = bytecode[i];
offset++;
}
for (let i = 0; i < mask.length; i++) {
data[offset] = mask[i];
offset++;
}
return data;
}

export function decodeProgram(program: Uint8Array): Program {
const decoder = new Decoder(program);

Expand All @@ -60,6 +87,35 @@ export function decodeProgram(program: Uint8Array): Program {
return new Program(rawCode, mask, jumpTable, basicBlocks);
}

function buildMask(bytecode: Uint8Array): u8[] {
const mask = new StaticArray<boolean>(bytecode.length);
for (let i = 0; i < bytecode.length; i++) {
const instruction = bytecode[i];
const iData = <i32>instruction < INSTRUCTIONS.length ? INSTRUCTIONS[instruction] : MISSING_INSTRUCTION;
// We don't know exactly how many bytes would be read...
const _args = decodeArguments(iData.kind, bytecode.subarray(i + 1));
// TODO [ToDr] We could possibly encode the arguments back to see how much bytes they would take?
const skipBytes = REQUIRED_BYTES[iData.kind];
mask[i] = true;
i += skipBytes;
}
// pack mask
const packed: u8[] = [];
for (let i = 0; i < mask.length; i += 8) {
let byte = 0;
// TODO [ToDr] Check, might need to go in the other order
for (let j = i; j < i + 8; j++) {
if (j < mask.length) {
byte |= mask[j] ? 1 : 0;
} else {
byte |= 1;
}
byte << 1;
}
}
return packed;
}

export class Mask {
// NOTE: might be longer than code (bit-alignment)
readonly bytesToSkip: StaticArray<u8>;
Expand Down
2 changes: 2 additions & 0 deletions bin/disassemble.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env node

import fs from 'node:fs';
import { InputKind, disassemble } from "../build/release.js";

Expand Down
17 changes: 17 additions & 0 deletions bin/fuzz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node

// import { FuzzedDataProvider } from "@jazzer.js/core";
import { Pvm } from "@typeberry/pvm-debugger-adapter";
import { wrapAsProgram } from "../build/release.js";

export function fuzz(data) {
const pvm = new Pvm();
const program = wrapAsProgram(new Uint8Array(data));

pvm.reset(
program,
0,
100n
);
pvm.run(100);
}
Loading

0 comments on commit c4c18c2

Please sign in to comment.