• 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.runtime;
16 
17 import com.code_intelligence.jazzer.utils.Utils;
18 import com.github.fmeum.rules_jni.RulesJni;
19 import java.lang.reflect.Executable;
20 import java.nio.charset.Charset;
21 
22 @SuppressWarnings("unused")
23 final public class TraceDataFlowNativeCallbacks {
24   static {
25     RulesJni.loadLibrary("jazzer_driver", "/com/code_intelligence/jazzer/driver");
26   }
27 
28   // Note that we are not encoding as modified UTF-8 here: The FuzzedDataProvider transparently
29   // converts CESU8 into modified UTF-8 by coding null bytes on two bytes. Since the fuzzer is more
30   // likely to insert literal null bytes, having both the fuzzer input and the reported string
31   // comparisons be CESU8 should perform even better than the current implementation using modified
32   // UTF-8.
33   private static final Charset FUZZED_DATA_CHARSET = Charset.forName("CESU8");
34 
traceMemcmp(byte[] b1, byte[] b2, int result, int pc)35   public static native void traceMemcmp(byte[] b1, byte[] b2, int result, int pc);
36 
traceStrcmp(String s1, String s2, int result, int pc)37   public static void traceStrcmp(String s1, String s2, int result, int pc) {
38     traceMemcmp(encodeForLibFuzzer(s1), encodeForLibFuzzer(s2), result, pc);
39   }
40 
traceStrstr(String s1, String s2, int pc)41   public static void traceStrstr(String s1, String s2, int pc) {
42     traceStrstr0(encodeForLibFuzzer(s2), pc);
43   }
44 
traceReflectiveCall(Executable callee, int pc)45   public static void traceReflectiveCall(Executable callee, int pc) {
46     String className = callee.getDeclaringClass().getCanonicalName();
47     String executableName = callee.getName();
48     String descriptor = Utils.getDescriptor(callee);
49     tracePcIndir(Utils.simpleFastHash(className, executableName, descriptor), pc);
50   }
51 
traceCmpLongWrapper(long arg1, long arg2, int pc)52   public static int traceCmpLongWrapper(long arg1, long arg2, int pc) {
53     traceCmpLong(arg1, arg2, pc);
54     // Long.compare serves as a substitute for the lcmp opcode, which can't be used directly
55     // as the stack layout required for the call can't be achieved without local variables.
56     return Long.compare(arg1, arg2);
57   }
58 
59   // The caller has to ensure that arg1 and arg2 have the same class.
traceGenericCmp(Object arg1, Object arg2, int pc)60   public static void traceGenericCmp(Object arg1, Object arg2, int pc) {
61     if (arg1 instanceof CharSequence) {
62       traceStrcmp(arg1.toString(), arg2.toString(), 1, pc);
63     } else if (arg1 instanceof Integer) {
64       traceCmpInt((int) arg1, (int) arg2, pc);
65     } else if (arg1 instanceof Long) {
66       traceCmpLong((long) arg1, (long) arg2, pc);
67     } else if (arg1 instanceof Short) {
68       traceCmpInt((short) arg1, (short) arg2, pc);
69     } else if (arg1 instanceof Byte) {
70       traceCmpInt((byte) arg1, (byte) arg2, pc);
71     } else if (arg1 instanceof Character) {
72       traceCmpInt((char) arg1, (char) arg2, pc);
73     } else if (arg1 instanceof Number) {
74       traceCmpLong(((Number) arg1).longValue(), ((Number) arg2).longValue(), pc);
75     } else if (arg1 instanceof byte[]) {
76       traceMemcmp((byte[]) arg1, (byte[]) arg2, 1, pc);
77     }
78   }
79 
80   /* trace-cmp */
traceCmpInt(int arg1, int arg2, int pc)81   public static native void traceCmpInt(int arg1, int arg2, int pc);
traceConstCmpInt(int arg1, int arg2, int pc)82   public static native void traceConstCmpInt(int arg1, int arg2, int pc);
traceCmpLong(long arg1, long arg2, int pc)83   public static native void traceCmpLong(long arg1, long arg2, int pc);
traceSwitch(long val, long[] cases, int pc)84   public static native void traceSwitch(long val, long[] cases, int pc);
85   /* trace-div */
traceDivInt(int val, int pc)86   public static native void traceDivInt(int val, int pc);
traceDivLong(long val, int pc)87   public static native void traceDivLong(long val, int pc);
88   /* trace-gep */
traceGep(long val, int pc)89   public static native void traceGep(long val, int pc);
90   /* indirect-calls */
tracePcIndir(int callee, int caller)91   public static native void tracePcIndir(int callee, int caller);
92 
handleLibraryLoad()93   public static native void handleLibraryLoad();
94 
encodeForLibFuzzer(String str)95   private static byte[] encodeForLibFuzzer(String str) {
96     // libFuzzer string hooks only ever consume the first 64 bytes, so we can definitely cut the
97     // string off after 64 characters.
98     return str.substring(0, Math.min(str.length(), 64)).getBytes(FUZZED_DATA_CHARSET);
99   }
100 
traceStrstr0(byte[] needle, int pc)101   private static native void traceStrstr0(byte[] needle, int pc);
102 }
103