diff --git a/projects/gitpython/Dockerfile b/projects/gitpython/Dockerfile index e997b98245df..6d1bcac505d7 100644 --- a/projects/gitpython/Dockerfile +++ b/projects/gitpython/Dockerfile @@ -13,6 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. FROM gcr.io/oss-fuzz-base/base-builder-python -RUN git clone https://github.com/gitpython-developers/gitpython gitpython +RUN git clone https://github.com/gitpython-developers/gitpython gitpython \ + && python3 -m pip install --upgrade pip; + +RUN mkdir -p $SRC/seed_data \ + && git clone --depth 1 https://github.com/DaveLak/oss-fuzz-inputs.git oss-fuzz-inputs \ + && rsync -avc oss-fuzz-inputs/gitpython/ $SRC/seed_data/ \ + && rm -rf oss-fuzz-inputs; + +RUN git clone --depth 1 https://github.com/google/fuzzing fuzzing \ + && cat fuzzing/dictionaries/utf8.dict \ + >> $SRC/seed_data/__base.dict \ + && rm -rf fuzzing; + COPY *.sh *py $SRC/ WORKDIR $SRC/gitpython diff --git a/projects/gitpython/build.sh b/projects/gitpython/build.sh index 0f26fbc3c229..cfb5069491ef 100644 --- a/projects/gitpython/build.sh +++ b/projects/gitpython/build.sh @@ -14,9 +14,32 @@ # limitations under the License. # ################################################################################ -pip3 install . +python3 -m pip install . + +# Directory to look in for dictionaries, options files, and seed corpa: +SEED_DATA_DIR="$SRC/seed_data" + +find $SEED_DATA_DIR \( -name '*_seed_corpus.zip' -o -name '*.options' -o -name '*.dict' \) \ + ! \( -name '__base.*' \) -exec printf 'Copying: %s\n' {} \; \ + -exec chmod a-x {} \; \ + -exec cp {} "$OUT" \; # Build fuzzers in $OUT. -for fuzzer in $(find $SRC -name 'fuzz_*.py'); do - compile_python_fuzzer $fuzzer +find "$SRC" -maxdepth 1 -name 'fuzz_*.py' -print0 | while IFS= read -r -d $'\0' fuzz_harness; do + compile_python_fuzzer "$fuzz_harness" + + common_base_dictionary_filename="$SEED_DATA_DIR/__base.dict" + if [[ -r "$common_base_dictionary_filename" ]]; then + # Strip the `.py` extension from the filename and replace it with `.dict`. + fuzz_harness_dictionary_filename="$(basename "$fuzz_harness" .py).dict" + output_file="$OUT/$fuzz_harness_dictionary_filename" + + printf 'Appending %s to %s\n' "$common_base_dictionary_filename" "$output_file" + # Ensure a newline is added at the end of the file before appending, + # but only if the file already exists and is not empty. + if [[ -s "$output_file" ]]; then + echo >> "$output_file" + fi + cat "$common_base_dictionary_filename" >> "$output_file" + fi done diff --git a/projects/gitpython/fuzz_config.py b/projects/gitpython/fuzz_config.py index 62b43ae347bb..9760eed799fd 100644 --- a/projects/gitpython/fuzz_config.py +++ b/projects/gitpython/fuzz_config.py @@ -12,31 +12,37 @@ # 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 atheris import sys import io -import atheris +from configparser import MissingSectionHeaderError, ParsingError -import configparser -from git import GitConfigParser +with atheris.instrument_imports(): + from git import GitConfigParser def TestOneInput(data): - fdp = atheris.FuzzedDataProvider(data) sio = io.BytesIO(data) sio.name = "/tmp/fuzzconfig.config" git_config = GitConfigParser(sio) try: git_config.read() - except configparser.MissingSectionHeaderError: - pass - except configparser.ParsingError: - pass - except UnicodeDecodeError: - pass + except (MissingSectionHeaderError, ParsingError, UnicodeDecodeError): + return -1 # Reject inputs raising expected exceptions + except (IndexError, ValueError) as e: + if isinstance(e, IndexError) and "string index out of range" in str(e): + # Known possibility that might be patched + # See: https://github.com/gitpython-developers/GitPython/issues/1887 + pass + elif isinstance(e, ValueError) and "embedded null byte" in str(e): + # The `os.path.expanduser` function, which does not accept strings + # containing null bytes might raise this. + return -1 + else: + raise e # Raise unanticipated exceptions as they might be bugs def main(): - atheris.instrument_all() atheris.Setup(sys.argv, TestOneInput) atheris.Fuzz() diff --git a/projects/gitpython/fuzz_tree.py b/projects/gitpython/fuzz_tree.py index 8f0fc1a39e04..e1c0fe537993 100644 --- a/projects/gitpython/fuzz_tree.py +++ b/projects/gitpython/fuzz_tree.py @@ -12,13 +12,15 @@ # 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 atheris import io import sys +import os import shutil -import atheris -from git.objects import Tree -from git import Repo +with atheris.instrument_imports(): + from git.objects import Tree + from git.repo import Repo def TestOneInput(data): @@ -45,11 +47,10 @@ def TestOneInput(data): try: fuzz_tree._deserialize(io.BytesIO(data)) except IndexError: - pass + return -1 def main(): - atheris.instrument_all() atheris.Setup(sys.argv, TestOneInput) atheris.Fuzz()