Start here

Home
About Klocwork
What's new
Fixed issues
Release notes
Installation

Reference

C/C++ checkers
Java checkers
C# checkers
MISRA C 2004 checkers
MISRA C++ 2008 checkers
MISRA C 2012 checkers
MISRA C 2012 checkers with Amendment 1
Commands
Metrics
Troubleshooting
Reference

Product components

C/C++ Integration build analysis
Java Integration build analysis
Desktop analysis
Refactoring
Klocwork Static Code Analysis
Klocwork Code Review
Structure101
Tuning
Custom checkers

Coding environments

Visual Studio
Eclipse for C/C++
Eclipse for Java
IntelliJ IDEA
Other

Administration

Project configuration
Build configuration
Administration
Analysis performance
Server performance
Security/permissions
Licensing
Klocwork Static Code Analysis Web API
Klocwork Code Review Web API

Community

View help online
Visit RogueWave.com
Klocwork Support
Rogue Wave Videos

Legal

Legal information

Tutorial - Creating a Java Path checker

Tutorial - Creating a Java Path checker

Prerequisite: Ant must be installed.

For this tutorial, we will create a Security Vulnerability (SV) checker named JNDI.PRINT. For more information about the types of Java Path checkers you can create, see Types of Java Path checkers. The process for creating a Java path checker is the same regardless of whether you are creating an SV, RLK, or common checker.

The snippet containing the issue we want to detect is in Sample1.java:

import javax.naming.*;

public class Sample1 {

   public void test(final Context context) throws Exception {
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");
      System.out.println(enumeration );
   }
}

Run kwcreatechecker

From the directory in which you want your checker files to be created, run kwcreatechecker with the following options:

kwcreatechecker --language java --type sv --code JNDI.PRINT
Note: The use of special (and multibyte) characters is not supported with the --code option.

Result

A directory is created with the name you specified with --code . This directory contains the checker stub files. In the case of the example above, the directory is named JNDI.PRINT.

Add @Source and @Sink to the knowledge base

At minimum, you must define one source and one sink for the engine to detect the issue. An issue is reported only when data created in a source is used in a sink.

The .jkb file generated by kwcreatechecker contains examples of source, sink, check, and prop.

  1. Open JNDI.PRINT\kb\jndi.print.jkb.
  2. Add a source. Based on the sample provided above, the source for the issue is the call to a list method from the Context class which returns potentially dangerous data, which should not be printed:
    package javax.naming; 
    
    import java.util.Hashtable; 
    
    public interface Context { 
        @Source("return") public NamingEnumeration list(String name) throws NamingException; 
    }
    
  3. Add the sink. In this case, the sink is the call to the println method.
    package java.io;
    
    import java.util.Formatter; 
    import java.util.Locale; 
    
    public class PrintStream {    
        public void println(@Sink Object o); 
    }
    
  4. Save and close the file.

Provide a title and message for the checker

  1. Open JNDI.PRINT\checkers.xml in the editor of your choice.
  2. Replace "Your message goes here" with:
    JNDI data {0} leak
    
  3. Replace "Your title goes here" with:
    JNDI information leak
    
  4. Save the file.

Create context-sensitive help for your checker

  1. Open JNDI.PRINT\help.xml in the editor of your choice.
  2. Mandatory: Add the following issue help description:
    Sensitive JNDI information leak
    
  3. Optional: You may fill in the rest of the file with the information below, if desired.
  4. Save the file.

JNDI.PRINT help.xml

<?xml version="1.0"?>
<help language="java">
    
    <defect id="JNDI.PRINT">        
        <description>            
            Sensitive JNDI information leak            
        </description>
        <risks>            
            Revealing details about an JNDI storage is a security issue because it provides attackers with information they can use to further their attacks.
        </risks>
        <prevention>            
            Filter all the data coming from the JNDI in order to prevent sensitive information leaks.
        </prevention>
        
        <examples>            
            <example line="1">                
                <![CDATA[
                
import javax.naming.*;

public class Sample1 {

    public void test(final Context context) throws Exception {
    
        final NamingEnumeration<NameClassPair> enumeration = context.list("*");
        System.out.println(enumeration );
        
    }
    
}

            ]]>
            
                <description>                    
                    JNDI.PRINT is reported on line 7.                    
                </description>                
            </example>            
        </examples>        
    </defect>    
</help>

Run ant to pack the checker files

Go to your checker directory and run Ant in order to pack the checker files into a JAR file. For example:

cd \home\jsmith\testproject\JNDI.PRINT

ant

Results:

Buildfile: build.xml

jar:

[jar] Building jar: \home\jsmith\testproject\JNDI.PRINTJNDI.PRINT.jar

install: BUILD SUCCESSFUL Total time: 7 seconds

Test the checker

Put the checker JAR in the plugins folder

To test the checker, you must locally deploy the JAR file you created in the previous step.

If you do not see a plugins directory in the following location, you must create it manually. The location varies depending on your operating system:

  • Unix: ~<username>/.klocwork/plugins
  • Windows 7 and Vista: C:\users\<username>\.klocwork\plugins
  • Windows XP: C:\Documents and Settings\<username>\.klocwork\plugins

Place the JAR file in the plugins folder.

Run kwjava

Run kwjava to test your checker against one or more sample files. To reduce the size of the output, it's best practice to use simple source files when testing your checker.

kwjava --license-host kw-test --license-port 27000 Sample1.java --xml problem.xml

problem.xml output:

<problem>
    <file>Sample1.java</file>
    <method>test</method>
    <line>7</line>
    <column>17</column>
    <message>
        JNDI data Parameter enumeration of call to println(...) is printed out at enumeration
    </message>
    JNDI.PRINT
    
    <params>
        <param>Parameter enumeration of call to println(...)</param>
        <param>Value returned by list(...)</param>
        <param>enumeration</param>
        <param>enumeration</param>
    </params>
    <trace> 
        <traceBlock file="Sample1.java" class="Sample1" method="test" id="1">
            <traceLine line="6" text="Value returned by list(...)"/>
            <traceLine line="7" text="Parameter enumeration of call to println(...)"/>
        </traceBlock> 
    </trace>
</problem>

If your checker is not detecting the issues you expect, re-examine the knowledge base file to troubleshoot the problem.

If you cannot pinpoint the problem in the knowledge base file, you can enable your checker's log to get information about the code analyzed by the checker, as well as the sources and sinks that were applied. See Optional: Advanced troubleshootingOptional: Advanced troubleshooting.

Optional: Advanced troubleshooting

Run kwjava with the -l option. The log contains the information about the code analyzed by the checker, as well as the sources and sinks that were applied. You can use this output to debug and improve your checker and knowledge base.

kwjava --license-host kw-test --license-port 27000 Sample1.java -xml problem.xml -l <checker_dir>\logger.xml>

where<checker_dir> is the checker directory generated by kwcreatechecker

When you enable your checker's logger file, you see how data is collected and tracked by your checker.

Add @Prop to the knowledge base

Our new snippet reference is Sample2.java:

import javax.naming.*;

public class Sample2 {

   public void test(final Context context) throws Exception {    
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");    
      final Object o = enumeration.next();  
      System.out.println(o); 
   }
}

Extending the knowledge base with @Prop

In the above sample, tainted data is created in final NamingEnumeration<NameClassPair> enumeration = context.list("*");, but it is not used in the sink. What is used in the sink is an element of the tainted data. This element of the tainted data is extracted in final Object o = enumeration.next();.

In order to support such a situation we should extend the checker knowledge base with a prop entry, specifying that the next method returns the tainted data if the enumeration is tainted.

  1. Open JNDI.PRINT\kb\jndi.print.jkb.
  2. Add the prop:
package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
 
   @Prop(in="this", out="return") T next() throws NamingException;
}

Add @Check to the knowledge base

We will use Sample3.java to get the information we need to create a check entry:

import javax.naming.*;

public class Sample3 {

   public void test(final Context context) throws Exception {
      final NamingEnumeration<NameClassPair> enumeration = context.list("*");
      final Object o = enumeration.next();
      verify(o);
      System.out.println(o);
   }

   public void verify(final Object o) throws Exception {
      if (o.toString().indexOf("password") >= 0) {
         throw new Exception("Private data is accessed");
      }
   }
}

In the above snippet, the verify method is sufficient to check the data.

  1. Open JNDI.PRINT\kb\jndi.print.jkb.
  2. Add the check:
public class Sample3 { 
   public void verify(@Check final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
 
   @Prop(in="this", out="return") T next() throws NamingException;
}  

With this knowledge-base entry, JNDI.PRINT would not be reported against Sample3.

Go to : Test the checker. After re-testing the checker, we will add a check-true to the knowledge base.

Add @CheckTrue to the knowledge base

If the verify method from the check returns a boolean value, which is true (data is allowed to be printed out) and false otherwise, the data is not tainted in the positive branch if:

public class Sample3 {  
public boolean verify(@CheckTrue final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
  
   @Prop(in="this", out="return") T next() throws NamingException;
}

In that case an issue won't be reported for the following code:

   final NamingEnumeration<NameClassPair> enumeration = context.list("*");   
   final Object o = enumeration.next();  
   if (verify(o)) {     
      System.out.println(o);   
   }

But an issue will be reported for this code since the check was performed incorrectly:

   final NamingEnumeration<NameClassPair> enumeration = context.list("*");   
   final Object o = enumeration.next();
   if (!verify(o)) {   
      System.out.println(o);   
   }

Go to: Test the checker. After retesting the checker, we will add a check-false to the knowledge base.

Add @CheckFalse to the knowledge base

If verify should return false for the data allowed to be printed (reversed check) then the @CheckFalse annotation should be used.

public class Sample3 { 
public boolean verify(@CheckFalse final Object o) throws Exception;
}

package javax.naming;

import java.util.Hashtable;

public interface Context {

   @Source("return") public NamingEnumeration list(String name) throws NamingException;
}

public interface NamingEnumeration<T> {
  
   @Prop(in="this", out="return") T next() throws NamingException;
}

Next step: Test the checker. If after re-testing the checker, we are satisfied with the analysis results, the checker is ready for deployment. See Deploying custom checkers.