Skip to content

Commit

Permalink
Add njs as a target/profile (#434)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xbigshaq authored Jul 16, 2024
1 parent 1cbc0f4 commit 5432e70
Show file tree
Hide file tree
Showing 10 changed files with 539 additions and 0 deletions.
59 changes: 59 additions & 0 deletions Sources/FuzzilliCli/Profiles/NjsProfile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Fuzzilli

let njsProfile = Profile(
processArgs: { randomize in
["fuzz"]
},

processEnv: ["UBSAN_OPTIONS": "handle_segv=0"],

maxExecsBeforeRespawn: 1000,

timeout: 250,

codePrefix: """
""",

codeSuffix: """
""",

ecmaVersion: ECMAScriptVersion.es6,

startupTests: [
// Check that the fuzzilli integration is available.
("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed),

// Check that common crash types are detected.
("fuzzilli('FUZZILLI_CRASH', 0)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 1)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 2)", .shouldCrash),
],

additionalCodeGenerators: [],

additionalProgramTemplates: WeightedList<ProgramTemplate>([]),

disabledCodeGenerators: [],

disabledMutators: [],

additionalBuiltins: [:],

additionalObjectGroups: [],

optionalPostProcessor: nil
)
1 change: 1 addition & 0 deletions Sources/FuzzilliCli/Profiles/Profile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ let profiles = [
"xs": xsProfile,
"v8holefuzzing": v8HoleFuzzingProfile,
"serenity": serenityProfile,
"njs": njsProfile,
]
14 changes: 14 additions & 0 deletions Targets/njs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Target: NJS

To build njs for fuzzing:
* Step 1 - prepare env
* Run `setup.sh`, this will:
* Clone the NJS repo from https://github.com/nginx/njs/
* Apply the relevant patches & add a _fuzzilli_ JS module
* Step 2 - Build fuzzer
* Run `fuzzbuild.sh`, this will:
* Configure with `./configure --cc=clang --cc-opt="-g -fsanitize-coverage=trace-pc-guard"`
* Run `make njs_fuzzilli`

The REPRL shell/fuzzable build will be saved at `<njs-dir>/build/njs_fuzzilli`

1 change: 1 addition & 0 deletions Targets/njs/REVISION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d8fbff1b0b1099fac5f75112580d671007584b00
6 changes: 6 additions & 0 deletions Targets/njs/fuzzbuild.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
set -e

cd njs/
./configure --cc=clang --cc-opt="-g -fsanitize-coverage=trace-pc-guard"
make njs_fuzzilli
7 changes: 7 additions & 0 deletions Targets/njs/mod/gen-fuzzilli-shell.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

NEEDLE='main(int argc, char \*\*argv)'
MODIF='not_main(int argc, char \*\*argv)'
sed -i "s/$NEEDLE/$MODIF/" ./external/njs_fuzzilli_shell.c

sed -i '1s/^/int not_main(int argc, char **argv);\n/' ./external/njs_fuzzilli_shell.c
11 changes: 11 additions & 0 deletions Targets/njs/mod/njs_coverage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
void __sanitizer_cov_reset_edgeguards(void);
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
void __sanitizer_cov_trace_pc_guard(uint32_t *guard);

struct shmem_data {
uint32_t num_edges;
unsigned char edges[];
};

#define SHM_SIZE 0x100000
#define MAX_EDGES ((SHM_SIZE - 4) * 8)
156 changes: 156 additions & 0 deletions Targets/njs/mod/njs_fuzzilli.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <njs.h>
#include <njs_unix.h>
#include <njs_arr.h>
#include <njs_queue.h>
#include <njs_rbtree.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "njs_coverage.h"
#include <njs_fuzzilli_shell.c>


// defs
#define REPRL_CRFD 100
#define REPRL_CWFD 101
#define REPRL_DRFD 102
#define REPRL_DWFD 103

#define SHM_SIZE 0x100000
#define MAX_EDGES ((SHM_SIZE - 4) * 8)

#define CHECK(cond) if (!(cond)) { fprintf(stderr, "\"" #cond "\" failed\n"); _exit(-1); }

// Will be imported from `njs_fuzzilli_module.o` during linking phase
extern struct shmem_data* __shmem;
extern uint32_t *__edges_start, *__edges_stop;


njs_str_t* njs_fetch_fuzz_input(void);

njs_str_t* njs_fetch_fuzz_input(void) {
njs_str_t *script = NULL;
char *script_src, *ptr;
size_t script_size = 0, remaining = 0;
unsigned action;

script_size = 0;
CHECK(read(REPRL_CRFD, &action, 4) == 4);
if (action == 'cexe') {
CHECK(read(REPRL_CRFD, &script_size, 8) == 8);
} else {
fprintf(stderr, "Unknown action: %u\n", action);
_exit(-1);
}

script_src = malloc(script_size+1);
ptr = script_src;
remaining = script_size;

while (remaining > 0) {
ssize_t rv = read(REPRL_DRFD, ptr, remaining);
if (rv <= 0) {
fprintf(stderr, "Failed to load script\n");
_exit(-1);
}
remaining -= rv;
ptr += rv;
}

script = malloc(sizeof(njs_str_t));
script_src[script_size] = '\0';
script->start = (u_char*)script_src;
script->length = script_size;

return script;
}


static njs_int_t
njs_main_fuzzable(njs_opts_t *opts)
{
njs_int_t ret;
njs_engine_t *engine;

engine = njs_create_engine(opts);
if (engine == NULL) {
return NJS_ERROR;
}

ret = njs_console_init(opts, &njs_console);
if (njs_slow_path(ret != NJS_OK)) {
njs_stderror("njs_console_init() failed\n");
return NJS_ERROR;
}

ret = njs_process_script(engine, &njs_console, &opts->command);
engine->destroy(engine);
return ret;
}


int
main(int argc, char **argv)
{
njs_opts_t opts;
njs_memzero(&opts, sizeof(njs_opts_t));
int result=0, status=0;

if(argc < 2) {
printf("usage: ./%s <opt>\navailable opts: \n\t'filename.js' - path of js file to be executed\n\tfuzz - entering REPRL mode(fuzzilli)\n", argv[0]);
return NJS_ERROR;
}

if(!strcmp(argv[1], "fuzz")) {
char helo[] = "HELO";
if (write(REPRL_CWFD, helo, 4) != 4 || read(REPRL_CRFD, helo, 4) != 4) {
printf("Invalid HELO response from parent\n");
_exit(-1);
}

if (memcmp(helo, "HELO", 4) != 0) {
printf("Invalid response from parent\n");
_exit(-1);
}

while(1) {
njs_str_t* fuzzer_input = njs_fetch_fuzz_input();

opts.file = (char *) "fuzzer";
opts.command.start = fuzzer_input->start;
opts.command.length = fuzzer_input->length;
opts.suppress_stdout = 0;
result = njs_main_fuzzable(&opts);

free(fuzzer_input->start);
free(fuzzer_input);

status = (result & 0xff) << 8;
CHECK(write(REPRL_CWFD, &status, 4) == 4);
__sanitizer_cov_reset_edgeguards();
}
} else {
njs_int_t ret;
njs_engine_t *engine;

opts.file = argv[1];
engine = njs_create_engine(&opts);
if (engine == NULL) {
return NJS_ERROR;
}

ret = njs_console_init(&opts, &njs_console);
if (njs_slow_path(ret != NJS_OK)) {
njs_stderror("njs_console_init() failed\n");
return NJS_ERROR;
}
result = njs_process_file(&opts);
engine->destroy(engine);

}

return result;
}

Loading

0 comments on commit 5432e70

Please sign in to comment.