From 90dc42fb873d18c515056d1577cd1ec5c291c4e5 Mon Sep 17 00:00:00 2001 From: Roman Wagner Date: Sat, 28 Aug 2021 16:49:25 +0200 Subject: [PATCH] [zxing] Initial Integration (#6057) --- projects/zxing/Dockerfile | 29 +++ projects/zxing/MultiFormatDecodeFuzzer.java | 54 ++++++ projects/zxing/MultiFormatEncodeFuzzer.java | 187 ++++++++++++++++++++ projects/zxing/build.sh | 53 ++++++ projects/zxing/project.yaml | 11 ++ 5 files changed, 334 insertions(+) create mode 100644 projects/zxing/Dockerfile create mode 100644 projects/zxing/MultiFormatDecodeFuzzer.java create mode 100644 projects/zxing/MultiFormatEncodeFuzzer.java create mode 100644 projects/zxing/build.sh create mode 100644 projects/zxing/project.yaml diff --git a/projects/zxing/Dockerfile b/projects/zxing/Dockerfile new file mode 100644 index 000000000..7b25b92cb --- /dev/null +++ b/projects/zxing/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2021 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 + +RUN curl -L https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip -o maven.zip && \ + unzip maven.zip -d $SRC/maven && \ + rm -rf maven.zip + +ENV MVN $SRC/maven/apache-maven-3.6.3/bin/mvn + +RUN git clone --depth 1 https://github.com/zxing/zxing + +COPY build.sh $SRC/ +COPY MultiFormatDecodeFuzzer.java MultiFormatEncodeFuzzer.java $SRC/ +WORKDIR $SRC/zxing diff --git a/projects/zxing/MultiFormatDecodeFuzzer.java b/projects/zxing/MultiFormatDecodeFuzzer.java new file mode 100644 index 000000000..319ad9977 --- /dev/null +++ b/projects/zxing/MultiFormatDecodeFuzzer.java @@ -0,0 +1,54 @@ +// Copyright 2021 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. +// +//////////////////////////////////////////////////////////////////////////////// + +import com.google.zxing.BinaryBitmap; +import com.google.zxing.BufferedImageLuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; + +import javax.imageio.ImageIO; +import java.io.IOException; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; + +public final class MultiFormatDecodeFuzzer { + private static MultiFormatReader barcodeReader = new MultiFormatReader(); + + public static void fuzzerInitialize() { + } + + public static void fuzzerTestOneInput(byte[] input) { + BufferedImage image; + try { + image = ImageIO.read(new ByteArrayInputStream(input)); + } catch (IOException e) { + return; + } + if (image == null) + return; + + BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + Result result = barcodeReader.decode(bitmap); + result.getText(); + result.getResultMetadata(); + } catch (ReaderException ignored) { + } + } +} diff --git a/projects/zxing/MultiFormatEncodeFuzzer.java b/projects/zxing/MultiFormatEncodeFuzzer.java new file mode 100644 index 000000000..46a9e80e1 --- /dev/null +++ b/projects/zxing/MultiFormatEncodeFuzzer.java @@ -0,0 +1,187 @@ +// Copyright 2021 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. +// +//////////////////////////////////////////////////////////////////////////////// + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.aztec.encoder.AztecCode; +import com.google.zxing.aztec.AztecReader; +import com.google.zxing.datamatrix.DataMatrixReader; +import com.google.zxing.maxicode.MaxiCodeReader; +import com.google.zxing.oned.MultiFormatOneDReader; +import com.google.zxing.pdf417.PDF417Reader; +import com.google.zxing.qrcode.QRCodeReader; +import com.google.zxing.oned.CodaBarReader; +import com.google.zxing.oned.Code128Reader; +import com.google.zxing.oned.Code39Reader; +import com.google.zxing.oned.Code93Reader; +import com.google.zxing.oned.EAN13Reader; +import com.google.zxing.oned.EAN8Reader; +import com.google.zxing.oned.ITFReader; +import com.google.zxing.oned.UPCAReader; +import com.google.zxing.oned.UPCEReader; +import com.google.zxing.pdf417.PDF417Reader; +import com.google.zxing.qrcode.QRCodeReader; + +import java.util.EnumMap; +import java.util.Map; + +import javax.naming.NameNotFoundException; + +import com.google.zxing.Reader; +import com.google.zxing.Binarizer; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.WriterException; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.BitArray; +import com.google.zxing.NotFoundException; +import com.google.zxing.FormatException; +import com.google.zxing.ChecksumException; +import com.google.zxing.LuminanceSource; +import com.google.zxing.Result; +import com.google.zxing.pdf417.PDF417Writer; + +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.google.zxing.qrcode.decoder.Mode; +import com.google.zxing.qrcode.encoder.QRCode; + +import com.google.zxing.datamatrix.encoder.HighLevelEncoder; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; + +public final class MultiFormatEncodeFuzzer { + + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + int width = data.consumeInt(100, 200); + int height = data.consumeInt(100, 200); + BarcodeFormat format = data.pickValue(BarcodeFormat.values()); + String originalData = data.consumeRemainingAsAsciiString(); + + BitMatrix matrix; + try { + matrix = new MultiFormatWriter().encode(originalData, format, width, height); + } catch (WriterException | IllegalArgumentException e) { + return; + } + + BinaryBitmap bitmap = null; + Result result; + try { + bitmap = new BinaryBitmap(new TrivialBinarizer(matrix)); + result = getReader(format).decode(bitmap); + } catch (NotFoundException | ChecksumException | FormatException e) { + throw new IllegalStateException("Failed to recover\n" + originalData + "\nencoded with " + format + " in " + + width + "x" + height + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString(), e); + } + String decodedData = result.getText(); + if (!decodedData.equals(originalData)) { + throw new IllegalStateException( + "Failed to recover\n" + originalData + "\nencoded with " + format + " in " + width + "x" + height + + ", got:\n" + decodedData + "\n\n" + matrix.toString() + "\n\n" + bitmap.toString()); + } + } + + private static Reader getReader(BarcodeFormat format) { + switch (format) { + case EAN_8: + return new EAN8Reader(); + case UPC_E: + return new UPCEReader(); + case EAN_13: + return new EAN13Reader(); + case UPC_A: + return new UPCAReader(); + case QR_CODE: + return new QRCodeReader(); + case CODE_39: + return new Code39Reader(); + case CODE_93: + return new Code93Reader(); + case CODE_128: + return new Code128Reader(); + case ITF: + return new ITFReader(); + case PDF_417: + return new PDF417Reader(); + case CODABAR: + return new CodaBarReader(); + case DATA_MATRIX: + return new DataMatrixReader(); + case AZTEC: + return new AztecReader(); + default: + throw new IllegalArgumentException("No encoder available for format " + format); + } + } + + private static final class TrivialBinarizer extends Binarizer { + private final BitMatrix matrix; + + public TrivialBinarizer(BitMatrix matrix) { + super(new TrivialLuminanceSource(matrix)); + this.matrix = matrix; + } + + public BitArray getBlackRow(int y, BitArray row) throws NotFoundException { + return matrix.getRow(y, row); + } + + public BitMatrix getBlackMatrix() throws NotFoundException { + return matrix; + } + + public Binarizer createBinarizer(LuminanceSource source) { + return new TrivialBinarizer(matrix); + } + } + + private static final class TrivialLuminanceSource extends LuminanceSource { + private final BitMatrix matrix; + + public TrivialLuminanceSource(BitMatrix matrix) { + super(matrix.getWidth(), matrix.getHeight()); + this.matrix = matrix; + } + + public byte[] getRow(int y, byte[] row) { + if (row.length != matrix.getWidth()) { + row = new byte[matrix.getWidth()]; + } + BitArray bitRow = matrix.getRow(y, null); + for (int i = 0; i < matrix.getWidth(); i++) { + if (bitRow.get(i)) { + row[i] = 0; + } else { + row[i] = (byte) 255; + } + } + return row; + } + + public byte[] getMatrix() { + byte[] bytes = new byte[matrix.getWidth() * matrix.getHeight()]; + for (int x = 0; x < matrix.getWidth(); x++) { + for (int y = 0; y < matrix.getHeight(); y++) { + if (!matrix.get(x, y)) + bytes[x + y * matrix.getWidth()] = (byte) 255; + } + } + return bytes; + } + } +} diff --git a/projects/zxing/build.sh b/projects/zxing/build.sh new file mode 100644 index 000000000..8e139e544 --- /dev/null +++ b/projects/zxing/build.sh @@ -0,0 +1,53 @@ +#!/bin/bash -eu +# Copyright 2021 Google Inc. +# +# 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. +# +################################################################################ + +MAVEN_ARGS="-DskipTests -Djavac.src.version=15 -Djavac.target.version=15" +$MVN package org.apache.maven.plugins:maven-shade-plugin:3.2.4:shade $MAVEN_ARGS +CURRENT_VERSION=$($MVN org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate \ + -Dexpression=project.version -q -DforceStdout) +cp "core/target/core-$CURRENT_VERSION.jar" $OUT/zxing.jar + +mkdir -p $OUT/com/google/zxing +cp core/target/test-classes/com/google/zxing/BufferedImageLuminanceSource.class $OUT/com/google/zxing + +ALL_JARS="zxing.jar" + +# The classpath at build-time includes the project jars in $OUT as well as the +# Jazzer API. Additionally, include $OUT itself to pick up +# BufferedImageLuminanceSource. +BUILD_CLASSPATH=$(echo $ALL_JARS | xargs printf -- "$OUT/%s:"):$JAZZER_API_PATH:$OUT + +# 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 + +for fuzzer in $(find $SRC -name '*Fuzzer.java'); do + fuzzer_basename=$(basename -s .java $fuzzer) + javac -cp $BUILD_CLASSPATH $fuzzer + cp $SRC/$fuzzer_basename*.class $OUT/ + + # 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\" \ +\$@" > $OUT/$fuzzer_basename + chmod u+x $OUT/$fuzzer_basename +done diff --git a/projects/zxing/project.yaml b/projects/zxing/project.yaml new file mode 100644 index 000000000..ceab3c387 --- /dev/null +++ b/projects/zxing/project.yaml @@ -0,0 +1,11 @@ +homepage: "https://github.com/zxing/zxing" +language: jvm +primary_contact: "srowen@gmail.com" +auto_ccs: + - "wagner@code-intelligence.com" + - "meumertzheim@code-intelligence.com" +fuzzing_engines: + - libfuzzer +main_repo: "https://github.com/zxing/zxing.git" +sanitizers: + - address