diff --git a/projects/hsqldb/ConnectionOptionsFuzzer.java b/projects/hsqldb/ConnectionOptionsFuzzer.java new file mode 100644 index 000000000..c64d891fe --- /dev/null +++ b/projects/hsqldb/ConnectionOptionsFuzzer.java @@ -0,0 +1,31 @@ +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; + +public class ConnectionOptionsFuzzer extends TestServer { + + ConnectionOptionsFuzzer(boolean verbose) { + super(verbose); + } + + void testOneInput(String fuzzyString) { + try { + getConnection(fuzzyString); + } catch (SQLException ex) { + /* ignore */ + } catch (IllegalArgumentException ex) { + /* ??? */ + } + } + + public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) throws Exception { + try (TestServer fuzzer = new ConnectionOptionsFuzzer(false)) { + fuzzer.testOneInput(fuzzedDataProvider.consumeRemainingAsAsciiString()); + } + } +} \ No newline at end of file diff --git a/projects/hsqldb/Dockerfile b/projects/hsqldb/Dockerfile new file mode 100644 index 000000000..f6f0c04b1 --- /dev/null +++ b/projects/hsqldb/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2022 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. +# +################################################################################ + +FROM gcr.io/oss-fuzz-base/base-builder-jvm + +RUN curl -L https://dlcdn.apache.org//ant/binaries/apache-ant-1.10.12-bin.zip -o ant.zip && \ + unzip ant.zip -d $SRC/ant && \ + rm -rf ant.zip + +ENV ANT $SRC/ant/apache-ant-1.10.12/bin/ant + +RUN svn checkout https://svn.code.sf.net/p/hsqldb/svn/base/trunk hsqldb-svn + +COPY build.sh $SRC/ +COPY *.java $SRC/ +WORKDIR $SRC/hsqldb \ No newline at end of file diff --git a/projects/hsqldb/SqlPreparedStatementFuzzer.java b/projects/hsqldb/SqlPreparedStatementFuzzer.java new file mode 100644 index 000000000..36eb137f1 --- /dev/null +++ b/projects/hsqldb/SqlPreparedStatementFuzzer.java @@ -0,0 +1,31 @@ +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; + +public class SqlPreparedStatementFuzzer extends TestServer { + + SqlPreparedStatementFuzzer(boolean verbose) { + super(verbose); + } + + void testOneInput(String fuzzyString) { + try (Connection connection = getConnection()) { + PreparedStatement preparedStatement = connection.prepareStatement("UPDATE TestTable SET value=? WHERE key=1"); + preparedStatement.setString(1, fuzzyString); + preparedStatement.executeUpdate(); + } catch (SQLException ex) { + /* ignore */ + } + } + + public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) throws Exception { + try (TestServer fuzzer = new SqlStatementFuzzer(false)) { + fuzzer.testOneInput(fuzzedDataProvider.consumeRemainingAsAsciiString()); + } + } +} \ No newline at end of file diff --git a/projects/hsqldb/SqlStatementFuzzer.java b/projects/hsqldb/SqlStatementFuzzer.java new file mode 100644 index 000000000..e6e465785 --- /dev/null +++ b/projects/hsqldb/SqlStatementFuzzer.java @@ -0,0 +1,29 @@ +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; + +public class SqlStatementFuzzer extends TestServer { + + SqlStatementFuzzer(boolean verbose) { + super(verbose); + } + + void testOneInput(String fuzzyString) { + try { + getConnection().createStatement().execute(fuzzyString); + } catch (SQLException ex) { + /* ignore */ + } + } + + public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) throws Exception { + try (TestServer fuzzer = new SqlStatementFuzzer(false)) { + fuzzer.testOneInput(fuzzedDataProvider.consumeRemainingAsAsciiString()); + } + } +} \ No newline at end of file diff --git a/projects/hsqldb/TestServer.java b/projects/hsqldb/TestServer.java new file mode 100644 index 000000000..5c04a604c --- /dev/null +++ b/projects/hsqldb/TestServer.java @@ -0,0 +1,85 @@ +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh; +import org.hsqldb.server.Server; +import org.hsqldb.server.ServerConstants; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.PreparedStatement; + +public abstract class TestServer extends Server implements AutoCloseable { + + private PrintWriter m_stderr = null; + private PrintWriter m_stdout = null; + + TestServer(boolean verbose) { + super(); + setVerbose(verbose); + + setDatabaseName(0, getTestName()); + setDatabasePath(0, "mem:" + getTestName()); + + start(); + try { + createTestTable(); + } catch(SQLException ex) { + /* cannot happen? */ + } + } + + void createTestTable() throws SQLException { + try (Connection connection = getConnection()) { + Statement statement = connection.createStatement(); + statement.execute("DROP TABLE TestTable IF EXISTS"); + statement.execute("CREATE TABLE TestTable (key INTEGER, value VARCHAR(256))"); + statement.execute("INSERT INTO TestTable VALUES ((0, \"Hello\"),(1, \"World\"))"); + } + } + + public void close() throws Exception { + stop(); + } + + protected void setVerbose(boolean verbose) { + if (verbose) { + m_stderr = new PrintWriter(System.err); + m_stdout = new PrintWriter(System.out); + } else { + m_stderr = null; + m_stdout = null; + } + this.setErrWriter(m_stderr); + this.setLogWriter(m_stdout); + } + + public int stop() { + int retval = super.stop(); + + /* + * polling [...] + */ + while (getState() == ServerConstants.SERVER_STATE_CLOSING) { + Thread.yield(); + } + + return retval; + } + + Connection getConnection(String options) throws SQLException { + return DriverManager.getConnection("jdbc:hsqldb:mem:" + getTestName() + ";" + options, "sa", ""); + } + + Connection getConnection() throws SQLException { + return getConnection(""); + } + + String getTestName() { + return getClass().getSimpleName(); + } + + abstract void testOneInput(String fuzzyString); +} \ No newline at end of file diff --git a/projects/hsqldb/build.sh b/projects/hsqldb/build.sh new file mode 100644 index 000000000..873e97f14 --- /dev/null +++ b/projects/hsqldb/build.sh @@ -0,0 +1,57 @@ +#!/bin/bash -eu +# Copyright 2022 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. +# +################################################################################ + +pushd ${SRC}/hsqldb-svn/build +$ANT -Dbuild.debug=true hsqldb +cp ../lib/hsqldb.jar $OUT/ +popd + +ALL_JARS="hsqldb.jar" + +# The classpath at build-time includes the project jars in $OUT as well as the +# Jazzer API. +BUILD_CLASSPATH=$(echo $ALL_JARS | xargs printf -- "$OUT/%s:"):$JAZZER_API_PATH + +# All .jar and .class files lie in the same directory as the fuzzer at runtime. +RUNTIME_CLASSPATH=$(echo $ALL_JARS | xargs printf -- "\$this_dir/%s:"):\$this_dir + +# compile all java files and copy them to $OUT +javac -cp $SRC:$BUILD_CLASSPATH -g $SRC/*.java +cp $SRC/*.class $OUT/ + +# generate jazzer start script +for fuzzer in $(find $SRC -maxdepth 1 -name '*Fuzzer.java'); do + fuzzer_basename=$(basename -s .java $fuzzer) + #javac -cp $SRC:$BUILD_CLASSPATH $fuzzer + #cp $SRC/$fuzzer_basename.class $OUT/ + #for member_class in $(find $SRC -maxdepth 1 -name "$fuzzer_basename\$*.class"); do + # cp $member_class $OUT/ + #done + + # Create an execution wrapper that executes Jazzer with the correct arguments. + echo "#!/bin/sh +# LLVMFuzzerTestOneInput for fuzzer detection. +this_dir=\$(dirname \"\$0\") +LD_LIBRARY_PATH=\"$JVM_LD_LIBRARY_PATH\":\$this_dir \ +\$this_dir/jazzer_driver --agent_path=\$this_dir/jazzer_agent_deploy.jar \ +--cp=$RUNTIME_CLASSPATH \ +--target_class=$fuzzer_basename \ +--jvm_args=\"-Xmx2048m\" \ +--disabled_hooks=\"com.code_intelligence.jazzer.sanitizers.SqlInjection\" \ +\$@" > $OUT/$fuzzer_basename + chmod u+x $OUT/$fuzzer_basename +done \ No newline at end of file diff --git a/projects/hsqldb/project.yaml b/projects/hsqldb/project.yaml new file mode 100644 index 000000000..6d4887245 --- /dev/null +++ b/projects/hsqldb/project.yaml @@ -0,0 +1,15 @@ +homepage: "www.hsqldb.org" +language: jvm +main_repo: "https://svn.code.sf.net/p/hsqldb/svn/" +fuzzing_engines: + - libfuzzer +sanitizers: + - address +primary_contact: "fredt@users.sourceforge.net" +vendor_ccs: + - "wagner@code-intelligence.com" + - "yakdan@code-intelligence.com" + - "glendowne@code-intelligence.com" + - "patrice.salathe@code-intelligence.com" + - "hlin@code-intelligence.com" + - "schaich@code-intelligence.com" \ No newline at end of file