[PostgreSQL] Add new protocol fuzzer (#4431)

* Add new protocol fuzzer

* Fixed fuzzer

* Removed tar
This commit is contained in:
Yunshu Ouyang 2020-09-17 06:42:31 +02:00 committed by GitHub
parent ac56d80070
commit e0f8bad47b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 190 additions and 4 deletions

View File

@ -25,4 +25,4 @@ WORKDIR postgresql
RUN mkdir bld
COPY fuzzer $SRC/fuzzer
COPY build.sh $SRC/
COPY build.sh add_fuzzers.diff $SRC/

View File

@ -0,0 +1,68 @@
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c9424f167c..aa2897ec63 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -101,6 +101,10 @@ int max_stack_depth = 100;
/* wait N seconds to allow attach from a debugger */
int PostAuthDelay = 0;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+bool fuzzer_first_run = true;
+#endif
+
/* ----------------
@@ -505,11 +509,14 @@ static int
ReadCommand(StringInfo inBuf)
{
int result;
-
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ result = SocketBackend(inBuf);
+#else
if (whereToSendOutput == DestRemote)
result = SocketBackend(inBuf);
else
result = InteractiveBackend(inBuf);
+#endif
return result;
}
@@ -3784,6 +3791,10 @@ PostgresMain(int argc, char *argv[],
volatile bool send_ready_for_query = true;
bool disable_idle_in_transaction_timeout = false;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ if(fuzzer_first_run)
+ {
+#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
/* Initialize startup process environment if necessary. */
if (!IsUnderPostmaster)
InitStandaloneProcess(argv[0]);
@@ -4151,6 +4162,11 @@ PostgresMain(int argc, char *argv[],
if (!ignore_till_sync)
send_ready_for_query = true; /* initially, or after error */
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ fuzzer_first_run=false;
+ }
+#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
+
/*
* Non-error queries loop here.
*/
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index d0b368530e..02a3e9066e 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -513,7 +513,9 @@ errfinish(const char *filename, int lineno, const char *funcname)
pq_endcopyout(true);
/* Emit the message to the right places */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
EmitErrorReport();
+#endif
/* Now free up subsidiary data attached to stack entry, and release it */
if (edata->message)

View File

@ -15,6 +15,7 @@
#
################################################################################
cp -r $SRC/fuzzer src/backend/
git apply ../add_fuzzers.diff
useradd fuzzuser
chown -R fuzzuser .

View File

@ -37,15 +37,17 @@ OBJS_FUZZERS = $(filter-out ../main/objfiles.txt, $(OBJS))
createdb: dbfuzz
fuzzer: simple_query_fuzzer \
json_parser_fuzzer
json_parser_fuzzer \
protocol_fuzzer
simple_query_fuzzer json_parser_fuzzer: %: %.o fuzzer_initialize.o $(OBJS_FUZZERS)
$(CXX) $(CFLAGS) $(call expand_subsys,$^) -o $@ $(LIB_FUZZING_ENGINE)
simple_query_fuzzer.o json_parser_fuzzer.o fuzzer_initialize.o: %.o: %.c
simple_query_fuzzer.o json_parser_fuzzer.o protocol_fuzzer.o fuzzer_initialize.o: %.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $^
protocol_fuzzer: %: %.o $(OBJS_FUZZERS)
$(CXX) $(CFLAGS) $(call expand_subsys,$^) -o $@ $(LIB_FUZZING_ENGINE) -Wl,--wrap=exit -Wl,--wrap=pq_getbyte
dbfuzz: dbfuzz.o | submake-libpgport temp-install
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@ \

View File

@ -0,0 +1,115 @@
// Copyright 2020 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
//
// http://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.
//
///////////////////////////////////////////////////////////////////////////////
#include "postgres.h"
#include "access/xlog.h"
#include "access/xact.h"
#include "common/ip.h"
#include "common/username.h"
#include "executor/spi.h"
#include "jit/jit.h"
#include "libpq/auth.h"
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parser.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/datetime.h"
#include "utils/memutils.h"
#include "utils/memdebug.h"
#include "utils/pidfile.h"
#include "utils/portal.h"
#include "utils/snapmgr.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <libgen.h>
const char *progname = "progname";
static sigjmp_buf postgre_exit;
static bool postgre_started;
static char *buffer;
static size_t buffersize;
static char *bufferpointer;
static char *av[6];
int LLVMFuzzerInitialize(int *argc, char ***argv) {
char *exe_path = (*argv)[0];
//dirname() can modify its argument
char *exe_path_copy = strdup(exe_path);
char *dir = dirname(exe_path_copy);
chdir(dir);
free(exe_path_copy);
av[0] = "tmp_install/usr/local/pgsql/bin/postgres";
av[1] = "--single";
av[2] = "-D/tmp/protocol_db/data";
av[3] = "-F";
av[4] = "-k\"/tmp\"";
av[5] = NULL;
system("rm -rf /tmp/protocol_db; mkdir /tmp/protocol_db; cp -r data /tmp/protocol_db");
system("cp -r tmp_install /tmp/");
MemoryContextInit();
if(!sigsetjmp(postgre_exit, 0)){
postgre_started = true;
PostgresMain(5, av, "dbfuzz", "fuzzuser");
}
pq_endmsgread();
return 0;
}
void __wrap_exit(int status){
if(postgre_started)
siglongjmp(postgre_exit, 1);
else
__real_exit(status);
}
int __wrap_pq_getbyte(void){
if(!buffersize) return EOF;
unsigned char cur = buffer[0];
bufferpointer++; buffersize--;
return cur;
}
/*
** Main entry point. The fuzzer invokes this function with each
** fuzzed input.
*/
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
buffersize = size;
buffer = (char *) calloc(size, sizeof(char));
bufferpointer = buffer;
memcpy(buffer, data, size);
if(!sigsetjmp(postgre_exit, 0)){
postgre_started = true;
PostgresMain(5, av, "dbfuzz", "fuzzuser");
}
pq_endmsgread();
postgre_started = false;
free(buffer);
return 0;
}