1 /* 2 * Copyright 2023 Code Intelligence GmbH 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.code_intelligence.jazzer.api; 18 19 import java.util.concurrent.atomic.AtomicReference; 20 import java.util.function.BiPredicate; 21 22 /** 23 * Provides static functions that configure the behavior of bug detectors provided by Jazzer. 24 */ 25 public final class BugDetectors { 26 private static final AtomicReference<BiPredicate<String, Integer>> currentPolicy = 27 getConnectionPermittedReference(); 28 29 /** 30 * Allows all network connections. 31 * 32 * <p>See {@link #allowNetworkConnections(BiPredicate)} for an alternative that provides 33 * fine-grained control over which network connections are expected. 34 * 35 * <p>By default, all attempted network connections are considered unexpected and result in a 36 * finding being reported. 37 * 38 * <p>By wrapping the call into a try-with-resources statement, network connection permissions 39 * can be configured to apply to individual parts of the fuzz test only: 40 * 41 * <pre>{@code 42 * Image image = parseImage(bytes); 43 * Response response; 44 * try (SilentCloseable unused = BugDetectors.allowNetworkConnections()) { 45 * response = uploadImage(image); 46 * } 47 * handleResponse(response); 48 * }</pre> 49 * 50 * @return a {@link SilentCloseable} that restores the previously set permissions when closed 51 */ allowNetworkConnections()52 public static SilentCloseable allowNetworkConnections() { 53 return allowNetworkConnections((host, port) -> true); 54 } 55 56 /** 57 * Allows all network connections for which the provided predicate returns {@code true}. 58 * 59 * <p>By default, all attempted network connections are considered unexpected and result in a 60 * finding being reported. 61 * 62 * <p>By wrapping the call into a try-with-resources statement, network connection permissions 63 * can be configured to apply to individual parts of the fuzz test only: 64 * 65 * <pre>{@code 66 * Image image = parseImage(bytes); 67 * Response response; 68 * try (SilentCloseable unused = BugDetectors.allowNetworkConnections( 69 * (host, port) -> host.equals("example.org"))) { 70 * response = uploadImage(image, "example.org"); 71 * } 72 * handleResponse(response); 73 * }</pre> 74 * 75 * @param connectionPermitted a predicate that evaluate to {@code true} if network connections to 76 * the provided combination of host and port are permitted 77 * @return a {@link SilentCloseable} that restores the previously set predicate when closed 78 */ allowNetworkConnections( BiPredicate<String, Integer> connectionPermitted)79 public static SilentCloseable allowNetworkConnections( 80 BiPredicate<String, Integer> connectionPermitted) { 81 if (connectionPermitted == null) { 82 throw new IllegalArgumentException("connectionPermitted must not be null"); 83 } 84 if (currentPolicy == null) { 85 throw new IllegalStateException("Failed to set network connection policy"); 86 } 87 BiPredicate<String, Integer> previousPolicy = currentPolicy.getAndSet(connectionPermitted); 88 return () -> { 89 if (!currentPolicy.compareAndSet(connectionPermitted, previousPolicy)) { 90 throw new IllegalStateException( 91 "Failed to reset network connection policy - using try-with-resources is highly recommended"); 92 } 93 }; 94 } 95 96 private static AtomicReference<BiPredicate<String, Integer>> getConnectionPermittedReference() { 97 try { 98 Class<?> ssrfSanitizer = 99 Class.forName("com.code_intelligence.jazzer.sanitizers.ServerSideRequestForgery"); 100 return (AtomicReference<BiPredicate<String, Integer>>) ssrfSanitizer 101 .getField("connectionPermitted") 102 .get(null); 103 } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { 104 System.err.println("WARNING: "); 105 e.printStackTrace(); 106 return null; 107 } 108 } 109 110 private BugDetectors() {} 111 } 112