Skip to content

Commit

Permalink
feat: modernize fuzzing
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Apr 7, 2024
1 parent 043d8f1 commit 26554eb
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 123 deletions.
39 changes: 0 additions & 39 deletions .github/workflows/fuzz.yml

This file was deleted.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@
"coverage:report:ci": "c8 report",
"bench": "echo \"Error: Benchmarks have been moved to '/benchmarks'\" && exit 1",
"serve:website": "echo \"Error: Documentation has been moved to '/docs'\" && exit 1",
"prepare": "husky install && node ./scripts/platform-shell.js",
"fuzz": "jsfuzz test/fuzzing/fuzz.js corpus"
"prepare": "husky install && node ./scripts/platform-shell.js"
},
"devDependencies": {
"@matteo.collina/tspl": "^0.1.1",
Expand All @@ -104,13 +103,13 @@
"c8": "^9.1.0",
"cross-env": "^7.0.3",
"dns-packet": "^5.4.0",
"fast-check": "^3.17.1",
"form-data": "^4.0.0",
"formdata-node": "^6.0.3",
"https-pem": "^3.0.0",
"husky": "^9.0.7",
"jest": "^29.0.2",
"jsdom": "^24.0.0",
"jsfuzz": "^1.0.15",
"node-forge": "^1.3.1",
"pre-commit": "^1.2.2",
"proxy": "^2.1.1",
Expand Down
6 changes: 2 additions & 4 deletions test/fuzzing/client/client-fuzz-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@ const acceptableCodes = [
'ERR_INVALID_ARG_TYPE'
]

// TODO: could make this a class with some inbuilt functionality that we can inherit
async function fuzz (netServer, results, buf) {
async function fuzz (address, results, buf) {
const body = buf
results.body = body
try {
const data = await request(`http://localhost:${netServer.address().port}`, { body })
const data = await request(address, { body })
data.body.destroy().on('error', () => {})
} catch (err) {
results.err = err
// Handle any undici errors
if (Object.values(errors).some(undiciError => err instanceof undiciError)) {
// Okay error
} else if (!acceptableCodes.includes(err.code)) {
console.log(`=== Headers: ${JSON.stringify(body)} ===`)
throw err
}
}
Expand Down
5 changes: 2 additions & 3 deletions test/fuzzing/client/client-fuzz-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ const acceptableCodes = [
'ERR_INVALID_ARG_TYPE'
]

async function fuzz (netServer, results, buf) {
async function fuzz (address, results, buf) {
const headers = { buf: buf.toString() }
results.body = headers
try {
const data = await request(`http://localhost:${netServer.address().port}`, { headers })
const data = await request(address, { headers })
data.body.destroy().on('error', () => {})
} catch (err) {
results.err = err
// Handle any undici errors
if (Object.values(errors).some(undiciError => err instanceof undiciError)) {
// Okay error
} else if (!acceptableCodes.includes(err.code)) {
console.log(`=== Headers: ${JSON.stringify(headers)} ===`)
throw err
}
}
Expand Down
6 changes: 2 additions & 4 deletions test/fuzzing/client/client-fuzz-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ const acceptableCodes = [
'ENOTFOUND',
'EAI_AGAIN',
'ECONNREFUSED'
// ----
]

async function fuzz (netServer, results, buf) {
async function fuzz (address, results, buf) {
const optionKeys = ['body', 'path', 'method', 'opaque', 'upgrade', buf]
const options = {}
for (const optionKey of optionKeys) {
Expand All @@ -21,15 +20,14 @@ async function fuzz (netServer, results, buf) {
}
results.options = options
try {
const data = await request(`http://localhost:${netServer.address().port}`, options)
const data = await request(address, options)
data.body.destroy().on('error', () => {})
} catch (err) {
results.err = err
// Handle any undici errors
if (Object.values(errors).some(undiciError => err instanceof undiciError)) {
// Okay error
} else if (!acceptableCodes.includes(err.code)) {
console.log(`=== Options: ${JSON.stringify(options)} ===`)
throw err
}
}
Expand Down
66 changes: 0 additions & 66 deletions test/fuzzing/fuzz.js

This file was deleted.

64 changes: 64 additions & 0 deletions test/fuzzing/fuzzing.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use strict'

const { once } = require('node:events')
const fc = require('fast-check')
const netServer = require('./server')
const { describe, before, after, test } = require('node:test')
const {
clientFuzzBody,
clientFuzzHeaders,
clientFuzzOptions
} = require('./client')

// Detect if running in CI (here we use GitHub Workflows)
// https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
const isCI = process.env.CI === 'true'

fc.configureGlobal({
interruptAfterTimeLimit: isCI ? 60_000 /* 1 minute */ : 10_000 /* 10 seconds */,
numRuns: Number.MAX_SAFE_INTEGER
})

describe('fuzzing', { timeout: 600_000 /* 10 minutes */ }, () => {
before(async () => {
netServer.listen(0)
await once(netServer, 'listening')
})

after(() => {
netServer.close()
})

test('body', async () => {
const address = `http://localhost:${netServer.address().port}`
await fc.assert(
fc.asyncProperty(fc.uint8Array(), async (body) => {
body = Buffer.from(body)
const results = {}
await clientFuzzBody(address, results, body)
})
)
})

test('headers', async () => {
const address = `http://localhost:${netServer.address().port}`
await fc.assert(
fc.asyncProperty(fc.uint8Array(), async (body) => {
body = Buffer.from(body)
const results = {}
await clientFuzzHeaders(address, results, body)
})
)
})

test('options', async () => {
const address = `http://localhost:${netServer.address().port}`
await fc.assert(
fc.asyncProperty(fc.uint8Array(), async (body) => {
body = Buffer.from(body)
const results = {}
await clientFuzzOptions(address, results, body)
})
)
})
})
17 changes: 13 additions & 4 deletions test/fuzzing/server/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
'use strict'

module.exports = {
splitData: require('./server-fuzz-split-data'),
appendData: require('./server-fuzz-append-data')
}
const net = require('node:net')
const serverFuzzFns = [
require('./server-fuzz-append-data'),
require('./server-fuzz-split-data')
]

const netServer = net.createServer(socket => {
socket.on('data', data => {
serverFuzzFns[(Math.random() * 2) | 0](socket, data)
})
})

module.exports = netServer

0 comments on commit 26554eb

Please sign in to comment.