From 5468f737e1eb021f8a69fe3ba559c43aa22d1455 Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Tue, 19 Nov 2024 11:41:45 +0900 Subject: Polish a tad --- Makefile | 27 ++++++++++++++++++--------- collect.c | 23 ++++++++++++++--------- fix.m4 | 34 ++++++++++++++++++---------------- synth | 55 ------------------------------------------------------- synth.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 89 deletions(-) delete mode 100644 synth create mode 100644 synth.py diff --git a/Makefile b/Makefile index 4ee0a88..92cefaf 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,15 @@ +.POSIX: +.PHONY: all clean install uninstall + CXXFLAGS += -g -std=c++23 -Wextra -Werror -LDFLAGS += -lcommon -ldyninstAPI -linstructionAPI -lparseAPI # dyninst -PREFIX ?= /usr/local +LDLIBS += -lcommon -ldyninstAPI -linstructionAPI -lparseAPI # dyninst -BIN := fix scout synth -BIN_PREFIX := $(DESTDIR)$(PREFIX)/bin/taosc- -DATA := collect patch -DATA_DIR := $(DESTDIR)$(PREFIX)/share/taosc +PREFIX ?= /usr/local +BIN_PREFIX ::= $(DESTDIR)$(PREFIX)/bin/taosc- +DATA_DIR ::= $(DESTDIR)$(PREFIX)/share/taosc -.PHONY: all clean install +BIN ::= fix scout synth +DATA ::= collect patch all: $(BIN) $(DATA) @@ -15,7 +17,10 @@ clean: rm -f $(BIN) $(DATA) fix: fix.m4 - m4 -D DATA_DIR=${DATA_DIR} $< > $@ + m4 -D DATA_DIR=$(DATA_DIR) $< > $@ + +synth: synth.py + link $< $@ collect: collect.c e9compile $< @@ -23,10 +28,14 @@ collect: collect.c patch: patch.c e9compile $< -install: $(addprefix $(BIN_PREFIX),$(BIN)) $(addprefix $(DATA_DIR)/,$(DATA)) +install: $(BIN:%=$(BIN_PREFIX)%) $(DATA:%=$(DATA_DIR)/%) $(BIN_PREFIX)%: % install -Dm 755 $< $@ $(DATA_DIR)/%: % install -Dm 644 $< $@ + +uninstall: + rm -f $(BIN:%=$(BIN_PREFIX)%) $(DATA:%=$(DATA_DIR)/%) + rmdir $(DATA_DIR) diff --git a/collect.c b/collect.c index 875213a..2ae9c2e 100644 --- a/collect.c +++ b/collect.c @@ -21,13 +21,17 @@ #include "stdlib.c" -char *path; +FILE *fout = NULL; void init(int argc, const char *const *argv, const char **envp) { environ = envp; - path = getenv("TAOSC_COLLECT"); /* TODO: fopen */ - setvbuf(stderr, NULL, _IOFBF, 0); + const char *const path = getenv("TAOSC_OUTPUT"); + if (path != NULL) + fout = fopen(path, "w"); + if (fout == NULL) + fout = stderr; + setvbuf(fout, NULL, _IOFBF, 0); } @@ -36,12 +40,13 @@ void log(const struct STATE *state) static mutex_t mutex = MUTEX_INITIALIZER; if (mutex_lock(&mutex) < 0) return; - clearerr(stderr); - fprintf(stderr, "[begin]\n"); + clearerr(fout); + fprintf(fout, "[begin]\n"); const int64_t *const env = (const int64_t *) state; - for (unsigned char i = 1; i < sizeof(state) / sizeof(int64_t); ++i) - fprintf(stderr, "%hhu %lld\n", i, env[i]); - fprintf(stderr, "[end]\n"); - fflush(stderr); + for (unsigned char i = 1; i < sizeof(*state) / sizeof(*env); ++i) + fprintf(fout, "%hhu %lld\n", i, env[i]); + fprintf(fout, "[end]\n"); + fflush(fout); + fclose(fout); /* FIXME: reopen */ mutex_unlock(&mutex); } diff --git a/fix.m4 b/fix.m4 index cbf3725..4647d00 100644 --- a/fix.m4 +++ b/fix.m4 @@ -1,6 +1,6 @@ #!/bin/sh # Patcher -# Copyright (C) 2024 Nguy?n Gia Phong +# Copyright (C) 2024 Nguyễn Gia Phong # # This file is part of taosc. # @@ -17,30 +17,32 @@ # You should have received a copy of the GNU Affero General Public License # along with taosc. If not, see . -set -e +set -ex if test $# -ne 3 then - echo Usage: taosc-fix binary instruction-address working-directory + echo Usage: taosc-fix binary address workdir exit 1 fi binary="$(realpath $1)" address="$2" wd="$(realpath $3)" +bin="$wd/$(basename $binary)" +afl-dyninst -x "$binary" "$bin.fuzzee" pushd DATA_DIR > /dev/null trap 'popd > /dev/null' EXIT -collect="$wd/$(basename $binary).collect" -e9tool -M addr=$address -P 'log(state)@collect' -o "$collect.orig" "$binary" -afl-dyninst -i "$collect.orig" -o "$collect" -patched="$wd/$(basename $binary).patched" -e9tool -M addr=$address -P 'if dest(state)@patch goto' -o "$patched" "$binary" +e9tool -M addr=$address -P 'log(state)@collect'\ + -o "$bin.collect" "$binary" +e9tool -M addr=$address -P 'if dest(state)@patch goto'\ + -o "$bin.patched" "$binary" +# TODO: augment number of executions +afl-dyninst-env afl-fuzz -i "$wd/fuzz/exploits" -o "$wd/fuzz/crashes"\ + -CE 10000 -- "$bin.fuzzee" -d @@ +find "$wd/fuzz/crashes/default/crashes" -name id:* | + parallel TAOSC_OUTPUT="$wd/vars/neg/"'$(basename {})' "$bin.collect" -d {} +time taosc-synth "$wd/vars" > "$wd/predicates" taosc-scout "$binary" "$address" > "$wd/destinations" -#for dest in $(taosc-slice "$binary" "$address") -#do -# for dest in $(taosc-slice "$binary" "$address") -# do -# TAOSC_PREDICATE=". - -from contextlib import redirect_stderr -from os import devnull -from os.path import basename -from pathlib import Path -from sys import argv, stdout - -from pacfix import learn -from pacfix.invariant import INVARIANT_MAP, InvariantType -from pacfix.utils import get_live_vars, get_valuations, parse_valuation - - -def encode(inv, file): - if inv.inv_type == InvariantType.VAR: - file.write(f"v{inv.data}") - elif inv.inv_type == InvariantType.CONST: - file.write(f"{'n' if inv.data < 0 else 'p'}{abs(inv.data)}") - else: - file.write(INVARIANT_MAP[inv.inv_type]) - encode(inv.left, file) - encode(inv.right, file) - - -if len(argv) != 3: - print(f'usage: taosc-synth input-dir delta') - exit(1) -input_dir = Path(argv[1]) -delta = float(argv[2]) - -with open(input_dir / 'vars') as f: live_vars = get_live_vars(f) -vals_neg, vals_pos = parse_valuation(get_valuations(input_dir / "neg"), - get_valuations(input_dir / "pos")) -with open(devnull, 'w') as f, redirect_stderr(f): - result = learn(live_vars, vals_neg, vals_pos, delta) -for i in result.inv_mgr.invs: - encode(i, stdout) - print() diff --git a/synth.py b/synth.py new file mode 100644 index 0000000..c35fb84 --- /dev/null +++ b/synth.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# Patch's predicate synthesizer +# Copyright (C) 2024 Nguyễn Gia Phong +# +# This file is part of taosc. +# +# Taosc is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Taosc is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with taosc. If not, see . + +from argparse import ArgumentParser +from cProfile import run +from functools import partial +from pathlib import Path + +from pacfix import learn +from pacfix.invariant import INVARIANT_MAP, InvariantType +from pacfix.utils import get_live_vars, get_valuations, parse_valuation + +write = partial(print, end='') + + +def write_invariant(inv): + if inv.inv_type == InvariantType.VAR: + write('v') + write(inv.data) + elif inv.inv_type == InvariantType.CONST: + write('n' if inv.data < 0 else 'p') + write(abs(inv.data)) + else: + write(INVARIANT_MAP[inv.inv_type]) + write_invariant(inv.left) + write_invariant(inv.right) + + +arg_parser = ArgumentParser(prog='taosc-synth') +arg_parser.add_argument('input', help='input directory', type=Path) +arg_parser.add_argument('delta', help='PAC delta', type=float, + nargs='?', default=0.01) +args = arg_parser.parse_args() + +with open(args.input / 'list') as f: live_vars = get_live_vars(f) +vals_neg, vals_pos = parse_valuation(get_valuations(args.input / 'neg'), + get_valuations(args.input / 'pos')) +result = learn(live_vars, vals_neg, vals_pos, args.delta) +for i in result.inv_mgr.invs: + write_invariant(i) + print() -- cgit 1.4.1