Reachability Analysis
The possibility of vulnerabilities increases as applications grow in size and complexity. The attack vectors increase with an increase in the usage of open-source software components in the application. With tight deadlines and competing priorities, it is often not feasible to remediate all vulnerabilities. A practical approach to achieving a near-zero risk scenario in limited amount of time, is remediating the open-source software vulnerabilities that lie in the execution paths of an application i.e. are reachable.
Reachability Analysis, lets you determine such reachable components, using the Callflow feature.
The Callflow feature, when used during application scans can detect vulnerable components that are reachable. Policy violations occurring due to these components will be labeled as "Reachable" in the application report. The remediation efforts can then be targeted towards these "Reachable" policy violations.
How does the Callflow Feature Work?
Callflow is designed to run on java (or any JVM language) binaries located in the scan target. When Callflow is enabled during application scans, the scan process analyzes all application binaries and the dependencies binaries in the scan target folder.
If the scan detects a vulnerable component and if the application code calls the specific method in the component that could potentially be exploitable, the policy violation is labeled as "Reachable."
If the scan detects a vulnerable component, but the application code does not execute any calls to the specific vulnerable method, the policy violation will be labeled as "Not Reachable."
Example
Consider an XML reader application that has a dependency on com.vulnerables.utils: vulnerable-deserializer:1.5. It has an endpoint that receives an XML file. The endpoint code reads the content of the XML file using the method XMLReader.readFile() and renders it on-screen. Based on our security data, the method readfile() has known vulnerabilities and public CVEs .
Callflow analyzes the .jar files created by the build tool and scans the method signatures to identify the vulnerable methods that are reachable. The policy violation for the component com.vulnerables.utils: vulnerable-deserializer:1.5 is labeled as "Reachable." This will be displayed in the policy evaluation report for the corresponding scan and on the Violations Dashboard.
The XML reader application also has a feature that allows users to write the XML input to a LaTeX document and export. One of the methods of the LaTeX library is vulnerable to remote command execution. Due to its known vulnerability, this method is never called and so is not in the execution path. Callflow analysis will not label the policy violation as "Reachable."
Using the Callflow Feature for Reachability Analysis
Reachability Analysis is currently supported on:
Sonatype Platform Plugin for Jenkins
Install the plugin in an existing instance of Jenkins running the project pipelines.
Currently does not support the
NamedStrategy
for method selection. See Strategies for Enabling Callflow below.
For Best Results with Reachability Analysis
Results for Reachability Analysis using the Callflow feature depend on the strategy used to select the types of methods to scan and selection of namespaces to narrow down the scan entry points.
Strategies for Enabling the Callflow Feature
1. Minimal configuration
The example below shows using the Callflow feature with minimal configuration.
callflow: [ enable: true ]
2. Method Selection
This is currently available only for Reachability Analysis performed on Sonatype Platform Plugin for Jenkins.
You can use one of the three available strategies for method selection for scans with Callflow enabled:
ACCESSIBLE_CONCRETE: Select public/protected non-abstract/synthetic methods from non-interface/annotation classes. This is the default entry point strategy.
PUBLIC_CONCRETE: Select public non-abstract/synthetic methods from non-interface/annotation classes
JAVA_MAIN: Select all methods matching public static void main(String[] args)
With the Jenkins plugin ready, you can enable the Callflow feature with the minimal configuration as below:
Example
The example below shows how to enable the Callflow feature with the ACCESSIBLE_CONCRETE strategy.
callflow: [ enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE' ] ]
3. Selection of Namespaces
Select the methods that should be considered as entry points (points in code where execution begins) for the analysis.
Namespaces are specified at the level of packages. All packages nested under a namespace are considered for entry point selection. If multiple namespaces are specified, all of them will be included.
Callflow analysis will start with the namespaces specified and subsequently analyze all others in the execution path.
Example
Consider the following project structure:
src |—main | |—java | | |—com | | | |—sonatype | | | | |—iq | | | | | |—domain | | | | | | |—DomainClassOne.java | | | | | |—application | | | | | |—repository | | | | |—wrappers | | | | | |—OktaLoginWrapper.java | | | | |—configs |—test | |—java | | |—com | | | |—sonatype | | | | |—iq | | | | | |—domain | | | | | | |—DomainClassOne.java | | | | | |—application | | | | | |—repository | | | | |—wrappers | | | | | |—OktaLoginWrapper.java | | | | |—configs
The Callflow feature is configured as follows:
callflow: [ enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE', namespaces: [ 'com.sonatype.iq' ] ] ]
In the example above, the namespaces property specifies the namespace 'com.sonatype.iq', which will be considered as the entry point for the analysis. This namespace has domain, application and repository packages under its scope. Methods belonging to DomainClassOne.java class (under the domain package in the 'com.sonatype.iq' namespace) will be analyzed before other methods in the package classes. Similarly, methods belonging to classes under other the application and repository packages will be analyzed at the start of analysis for the package.
Packages of type wrappers, with namespace 'com.sonatype.wrappers' and config packages with namespace 'com.sonatype.configs' will be omitted when an entry point for the analysis is being established. Similarly, methods belonging to OktaLoginWrapper class with namespace 'com.sonatype.wrappers.OktaLoginWrapper.java' will be omitted when establishing an entry point.
NOTES:
An entry point is any method signature that aligns with the selected Callflow strategy. For example, for JAVA_MAIN strategy, all entry point methods have
public static void main
as method signature.You can use regular expressions when specifying the namespace.
Example: For
org.foo.example
you can use regular expressions with '/' at the start and end of the string as,/^org\\.+.*\\.example\$/
Fine-tuning the Callflow Feature
The Callflow feature can be fine-tuned for improved performance and precision in detecting "Reachable" components.
Parameters available for fine-tuning:
1. Using the Parameter includes
Multi-module projects could have several .jar files when built. Many of these .jar files are dependencies of another .jar file, which could be the one containing the main application. By specifying the path to this specific .jar when running Callflow, you can avoid multiple evaluations of the same .jar files which would occur when:
.jar files are evaluated separately, and
.jar files are evaluated when invoked by the main application
The includes parameter specifies a target path for the artifacts to be analyzed. It limits the scope of the analysis, resulting in better precision and reducing the utilization of system resources.
Example
callflow: [ enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE' ], includes: [ '**/target/my-project-*.jar' ] ]
If includes is omitted, the target location for the analysis will be the same as specified in the iqScanPatterns of the nexusPolicyEvaluation in the Jenkins file. This may increase the scope of the target analysis, leading to reduced precision.
2. Using the Parameter java.options[ ]
Running Callflow on large-size applications could lead to insufficient memory. To allow for sufficient memory allocation in such cases, you can increase the heap size using the java.options[] properties.
Refer to Java® Platform, Standard Edition & Java Development Kit Version 21 API Specification
Example
callflow: [ enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE', namespaces: [ 'com.sonatype.iq' ] ], java: [ options:[ '-Xmx4G' ] ] ]
The example above, shows the allocated heap size of up to 4GB. As always, maximum heap size will depend on the physical memory available.
3. Using the Parameter timeout
Depending on the size and complexity of the scan targets, it may take longer than expected for Callflow to return outputs. Use the timeout parameter to limit the execution time and free up system resources for other tasks. Callflow execution will be aborted after the specified time has elapsed.
Example
callflow: [ timeout: '10 minutes', logLevel: 'DEBUG', enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE', namespaces: [ 'com.sonatype.iq' ] ] ]
The value for timeout can be provided as a string, that specifies the amount of time and the unit. For example, "60 seconds", " 3 minutes", "1 hour."
Error Handling for Callflow
By default, Jenkins will mark the pipeline as FAILURE if there are any error conditions in executing callflow analysis.
To avoid a pipeline FAILURE, set the value of the failOnError parameter to "false" (is true by default). Jenkins will mark the pipeline as UNSTABLE.
Example
callflow: [ failOnError: false timeout: '10 minutes', logLevel: 'DEBUG', enable: true, entrypointStrategy: [ $class: 'NamedStrategy', name: 'ACCESSIBLE_CONCRETE', namespaces: [ 'com.sonatype.iq' ] ] ]
Expected Outputs
Callflow yields different outputs for wide range of scenarios. The outputs depend on the type of artifacts analyzed, strategies used and fine tuning using the performance enhancing parameters described above.
Callflow output is logged in the IQ Policy Evaluation log and can be found in the stage where policy evaluation is called within your Jenkins pipeline.
Here are descriptions to a few sample outputs:
Sample output 1: Policy violations labeled as Reachable
On successful execution of Callflow, the number of "Reachable" components found will be logged as:
2024-07-25 15:08:32 GMT-05:00 [INFO] CallflowReachableMethodsCommand - Found 2 reachable methods
To view the actual method signatures of reachable methods, the logLevel should be set to DEBUG. However, this may lead to a lot of logging text and make the logs unreadable.
The Application Report will show the policy violations for components (belonging to the Maven ecosystem) that contain vulnerable method signatures.
Example
Click on the policy violation to open the violation details view.
Sample output 2: Policy violations labeled as "Not Reachable"
This occurs when Callflow does not find any "Reachable" methods. This means that there are no vulnerable components in the execution path of the analyzed application.
This scenario will appear in the log as:
2024-07-25 15:39:21 GMT-05:00 [INFO] CallflowReachableMethodsCommand - Found 0 reachable methods
Sample output 3: Callflow analysis skipped
This occurs when there are no vulnerable components found during the policy evaluation. Callflow analysis is skipped.
This is logged in the pipeline log as:
2024-07-25 15:38:03 GMT-05:00 [INFO] Skipping callflow analysis; missing vulnerable component method data
Warning
The absence of "Reachable" methods does not guarantee safety. The analysis may not have been able to detect these methods due to mis-configuration of the Callflow feature. We recommend checking these configurations thoroughly, at the start of the analysis.
Other Considerations While Running Callflow
This section describes some more considerations when performing Reachability Analysis using Callflow.
Running Callflow in multi-module projects
For a project that has multiple modules and produces multiple artifacts, Callflow should be configured with one of the strategies described above, for accurate results.
If a project produces two different artifacts, for example, one .jar file for a client service and one .jar file for a server, each of these .jar files should be evaluated separately. We recommend setting up a separate pipeline in Jenkins, one that produces the client .jar and one that produces the server .jar. This way you can use the includes parameter to specify the artifact you want to analyze on each pipeline.
If a multi-module project has modules that are meant to be used as a library for other projects, using JAVA_MAIN will not produce any "Reachable" methods. This is because none of the modules will have the methods with the signature public static void main. In such cases, it is best to use ACCESSIBLE_CONCRETE or PUBLIC_CONCRETE in the strategies section above.
Execution Times
Reachability Analysis using Callflow can be a time and memory intensive process, depending upon the size of the project that is being analyzed. The execution involves going through all entry points specified and creating a call graph and process the code to detect vulnerable methods in the execution path. This could be a huge overhead if your project has millions of lines of code, lots of dependencies and entry points.
To reduce the execution times, here are some recommendations:
If your project has a releaseable main branch, run Callflow on the main branch instead of all the feature branches on each new commit.
If you have changes in the project manifest, run Callflow in the feature branches. This is a trade off between build time and the extra analysis step due to Callflow.
Run Callflow at fixed times, for example, on nightly builds.
If you have multi-module projects, separate the projects before running Callflow.