• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.replay;
16 
17 import com.code_intelligence.jazzer.api.FuzzedDataProvider;
18 import com.code_intelligence.jazzer.driver.FuzzedDataProviderImpl;
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.nio.file.Files;
23 import java.nio.file.Paths;
24 import java.util.Arrays;
25 
26 public class Replayer {
27   public static final int STATUS_FINDING = 77;
28   public static final int STATUS_OTHER_ERROR = 1;
29 
main(String[] args)30   public static void main(String[] args) {
31     if (args.length < 2) {
32       System.err.println("Usage: <fuzz target class> <input file path> <fuzzerInitialize args>...");
33       System.exit(STATUS_OTHER_ERROR);
34     }
35     ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
36 
37     Class<?> fuzzTargetClass;
38     try {
39       fuzzTargetClass = Class.forName(args[0]);
40     } catch (ClassNotFoundException e) {
41       e.printStackTrace();
42       System.exit(STATUS_OTHER_ERROR);
43       // Without this return the compiler sees fuzzTargetClass as possibly uninitialized.
44       return;
45     }
46 
47     String inputFilePath = args[1];
48     byte[] input = loadInput(inputFilePath);
49 
50     String[] fuzzTargetArgs = Arrays.copyOfRange(args, 2, args.length);
51     executeFuzzerInitialize(fuzzTargetClass, fuzzTargetArgs);
52     executeFuzzTarget(fuzzTargetClass, input);
53   }
54 
loadInput(String inputFilePath)55   private static byte[] loadInput(String inputFilePath) {
56     try {
57       return Files.readAllBytes(Paths.get(inputFilePath));
58     } catch (IOException e) {
59       e.printStackTrace();
60       System.exit(STATUS_OTHER_ERROR);
61       // Without this return the compiler sees loadInput as possibly not returning a value.
62       return null;
63     }
64   }
65 
executeFuzzerInitialize(Class<?> fuzzTarget, String[] args)66   private static void executeFuzzerInitialize(Class<?> fuzzTarget, String[] args) {
67     // public static void fuzzerInitialize()
68     try {
69       Method fuzzerInitialize = fuzzTarget.getMethod("fuzzerInitialize");
70       fuzzerInitialize.invoke(null);
71       return;
72     } catch (Exception e) {
73       handleInvokeException(e, fuzzTarget);
74     }
75     // public static void fuzzerInitialize(String[] args)
76     try {
77       Method fuzzerInitialize = fuzzTarget.getMethod("fuzzerInitialize", String[].class);
78       fuzzerInitialize.invoke(null, (Object) args);
79     } catch (Exception e) {
80       handleInvokeException(e, fuzzTarget);
81     }
82   }
83 
executeFuzzTarget(Class<?> fuzzTarget, byte[] input)84   public static void executeFuzzTarget(Class<?> fuzzTarget, byte[] input) {
85     // public static void fuzzerTestOneInput(byte[] input)
86     try {
87       Method fuzzerTestOneInput = fuzzTarget.getMethod("fuzzerTestOneInput", byte[].class);
88       fuzzerTestOneInput.invoke(null, (Object) input);
89       return;
90     } catch (Exception e) {
91       handleInvokeException(e, fuzzTarget);
92     }
93     // public static void fuzzerTestOneInput(FuzzedDataProvider data)
94     try {
95       Method fuzzerTestOneInput =
96           fuzzTarget.getMethod("fuzzerTestOneInput", FuzzedDataProvider.class);
97       try (FuzzedDataProviderImpl fuzzedDataProvider = FuzzedDataProviderImpl.withJavaData(input)) {
98         fuzzerTestOneInput.invoke(null, fuzzedDataProvider);
99       }
100       return;
101     } catch (Exception e) {
102       handleInvokeException(e, fuzzTarget);
103     }
104     System.err.printf("%s must define exactly one of the following two functions:%n"
105             + "    public static void fuzzerTestOneInput(byte[] ...)%n"
106             + "    public static void fuzzerTestOneInput(FuzzedDataProvider ...)%n"
107             + "Note: Fuzz targets returning boolean are no longer supported; exceptions should%n"
108             + "be thrown instead of returning true.%n",
109         fuzzTarget.getName());
110     System.exit(STATUS_OTHER_ERROR);
111   }
112 
handleInvokeException(Exception e, Class<?> fuzzTarget)113   private static void handleInvokeException(Exception e, Class<?> fuzzTarget) {
114     if (e instanceof NoSuchMethodException)
115       return;
116     if (e instanceof InvocationTargetException) {
117       filterOutOwnStackTraceElements(e.getCause(), fuzzTarget);
118       e.getCause().printStackTrace();
119       System.exit(STATUS_FINDING);
120     } else {
121       e.printStackTrace();
122       System.exit(STATUS_OTHER_ERROR);
123     }
124   }
125 
filterOutOwnStackTraceElements(Throwable t, Class<?> fuzzTarget)126   private static void filterOutOwnStackTraceElements(Throwable t, Class<?> fuzzTarget) {
127     if (t.getCause() != null)
128       filterOutOwnStackTraceElements(t.getCause(), fuzzTarget);
129     if (t.getStackTrace() == null || t.getStackTrace().length == 0)
130       return;
131     StackTraceElement lowestFrame = t.getStackTrace()[t.getStackTrace().length - 1];
132     if (!lowestFrame.getClassName().equals(Replayer.class.getName())
133         || !lowestFrame.getMethodName().equals("main"))
134       return;
135     for (int i = t.getStackTrace().length - 1; i >= 0; i--) {
136       StackTraceElement frame = t.getStackTrace()[i];
137       if (frame.getClassName().equals(fuzzTarget.getName())
138           && frame.getMethodName().equals("fuzzerTestOneInput")) {
139         t.setStackTrace(Arrays.copyOfRange(t.getStackTrace(), 0, i + 1));
140         break;
141       }
142     }
143   }
144 }
145