Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c66d264

Browse files
authored
Merge pull request #176 from msgpack/jsfuzz
Introduce Fuzzing with jsFuzz and fix issues found by fuzzing
2 parents 8b1e562 + ae09f48 commit c66d264

File tree

8 files changed

+83
-19
lines changed

8 files changed

+83
-19
lines changed

‎.github/workflows/fuzz.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/jsfuzz
2+
3+
name: Fuzz
4+
5+
on:
6+
push:
7+
branches:
8+
- main
9+
pull_request:
10+
11+
jobs:
12+
fuzzing:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v1
19+
with:
20+
node-version: "16"
21+
22+
- run: npm ci
23+
- run: npm run test:fuzz

‎.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ isolate-*.log
1111

1212
# flamebearer
1313
flamegraph.html
14+
15+
# jsfuzz
16+
corpus/

‎package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"test:cover:purejs": "npx nyc --no-clean npm run test:purejs",
2424
"test:cover:te": "npx nyc --no-clean npm run test:te",
2525
"test:deno": "deno test test/deno_test.ts",
26+
"test:fuzz": "npm exec -- jsfuzz@git+https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/jsfuzz.git --fuzzTime 60 --no-versifier test/decode.jsfuzz.js corpus",
2627
"cover:clean": "rimraf .nyc_output coverage/",
2728
"cover:report": "npx nyc report --reporter=text-summary --reporter=html --reporter=json",
2829
"test:browser": "karma start --single-run",

‎src/DecodeError.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
export class DecodeError extends Error {
3+
constructor(message: string) {
4+
super(message);
5+
6+
// fix the prototype chain in a cross-platform way
7+
const proto: typeof DecodeError.prototype = Object.create(DecodeError.prototype);
8+
Object.setPrototypeOf(this, proto);
9+
10+
Object.defineProperty(this, "name", {
11+
configurable: true,
12+
enumerable: false,
13+
value: DecodeError.name,
14+
});
15+
}
16+
}

‎src/Decoder.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getInt64, getUint64 } from "./utils/int";
44
import { utf8DecodeJs, TEXT_DECODER_THRESHOLD, utf8DecodeTD } from "./utils/utf8";
55
import { createDataView, ensureUint8Array } from "./utils/typedArrays";
66
import { CachedKeyDecoder, KeyDecoder } from "./CachedKeyDecoder";
7+
import { DecodeError } from "./DecodeError";
78

89
const enum State {
910
ARRAY,
@@ -60,22 +61,6 @@ const DEFAULT_MAX_LENGTH = 0xffff_ffff; // uint32_max
6061

6162
const sharedCachedKeyDecoder = new CachedKeyDecoder();
6263

63-
export class DecodeError extends Error {
64-
constructor(message: string) {
65-
super(message);
66-
67-
// fix the prototype chain in a cross-platform way
68-
const proto: typeof DecodeError.prototype = Object.create(DecodeError.prototype);
69-
Object.setPrototypeOf(this, proto);
70-
71-
Object.defineProperty(this, "name", {
72-
configurable: true,
73-
enumerable: false,
74-
value: DecodeError.name,
75-
});
76-
}
77-
}
78-
7964
export class Decoder<ContextType = undefined> {
8065
private totalPos = 0;
8166
private pos = 0;
@@ -133,6 +118,10 @@ export class Decoder<ContextType = undefined> {
133118
return new RangeError(`Extra ${view.byteLength - pos} of ${view.byteLength} byte(s) found at buffer[${posToShow}]`);
134119
}
135120

121+
/**
122+
* @throws {DecodeError}
123+
* @throws {RangeError}
124+
*/
136125
public decode(buffer: ArrayLike<number> | BufferSource): unknown {
137126
this.reinitializeState();
138127
this.setBuffer(buffer);

‎src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ export { DecodeOptions };
1313
import { decodeAsync, decodeArrayStream, decodeMultiStream, decodeStream } from "./decodeAsync";
1414
export { decodeAsync, decodeArrayStream, decodeMultiStream, decodeStream };
1515

16-
import { Decoder, DecodeError } from "./Decoder";
17-
export { Decoder, DecodeError };
16+
import { Decoder, DataViewIndexOutOfBoundsError } from "./Decoder";
17+
import { DecodeError } from "./DecodeError";
18+
export { Decoder, DecodeError, DataViewIndexOutOfBoundsError };
1819

1920
import { Encoder } from "./Encoder";
2021
export { Encoder };

‎src/timestamp.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
2+
import { DecodeError } from "./DecodeError";
23
import { getInt64, setInt64 } from "./utils/int";
34

45
export const EXT_TIMESTAMP = -1;
@@ -91,7 +92,7 @@ export function decodeTimestampToTimeSpec(data: Uint8Array): TimeSpec {
9192
return { sec, nsec };
9293
}
9394
default:
94-
throw new Error(`Unrecognized data size for timestamp: ${data.length}`);
95+
throw new DecodeError(`Unrecognized data size for timestamp (expected 4, 8, or 12): ${data.length}`);
9596
}
9697
}
9798

‎test/decode.jsfuzz.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* eslint-disable */
2+
const assert = require("assert");
3+
const { Decoder, encode, DecodeError } = require("../dist/index.js");
4+
5+
/**
6+
* @param {Buffer} bytes
7+
* @returns {void}
8+
*/
9+
module.exports.fuzz = function fuzz(bytes) {
10+
const decoder = new Decoder();
11+
try {
12+
decoder.decode(bytes);
13+
} catch (e) {
14+
if (e instanceof DecodeError) {
15+
// ok
16+
} else if (e instanceof RangeError) {
17+
// ok
18+
} else {
19+
throw e;
20+
}
21+
}
22+
23+
// make sure the decoder instance is not broken
24+
const object = {
25+
foo: 1,
26+
bar: 2,
27+
baz: ["one", "two", "three"],
28+
};
29+
assert.deepStrictEqual(decoder.decode(encode(object)), object);
30+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /