Example: Synthetic method creation
This example demonstrates the creation of a synthetic method. In this synthetic method, we first taint a class field and then add a call to a method in the user's code and finally pass the result of this method call to a sink.
- Application scenario
- What is modelled in the synthetic method
- Step 1: Create an empty synthetic method
- Step 2: Model the tainting of a class field
- Step 3: Model the calling of the createUser() method
- Step 4: Model data return to the client
Application scenario
In this
example, createUser
is a REST API implemented in
the JAX-RS framework. A user can invoke this API using a URL such
as http://host:port/users/createUser
. The framework
runtime delegates this call to UserRestService.createUser()
since
the path matches. Additionally, the framework runtime initializes
the urlInfo
class variable from the client data before
calling createUser()
. Finally, the data returned
by createUser()
is sent back to the client by the
runtime.
What is modelled in the synthetic method
To capture the Application scenario using a synthetic method, we have these elements:
- The tainting of the
urlInfo
class variable ofUserRestService
. - The call to
UserRestService.createUser()
. - The return of data to the client.
This is the code for the createUser()
method:
import java.io.BufferedWriter;
@Path("users")
public class UserRestService {
@Context
UriInfo urlInfo;
@Path("/createUser")
public User createUser(){
MultivaluedMap<String, String> queryParams =
urlInfo.getQueryParameters();
String name = queryParams.getFirst("name");
User user = new User(name);
return user;
}
}
Step 1: Create an empty synthetic method
22 public class JAXRSHandler extends F4FHandler{
23 @Override
public void handleApp(F4FApp app, F4FActions actions) {
24 HighLevelSyntheticMethod synthMethod = HighLevelSyntheticMethod.make();
- The synthetic method object is initialized at line 24.
Step 2: Model the tainting of a class field
The
code snippet below demonstrates how specific class fields can be tainted.
In this example, we wish to taint the class fields that are annotated
with the @Context
annotation.
27 // create a local variable of the appropriate type
28 Local userRestServiceClazzInstance =
synthMethod.newLocal("com.ibm.appscan.UserRestService");
29
30 // get all the class fields
31 for(IField field: app.getIClass
("com.ibm.appscan.UserRestService").getDeclaredInstanceFields()){
32
33 //get all the annotations associated with the field
34 Collection<Annotation> fieldAnnotations = app.getFieldAnnotations(field);
35
36 //for each annotation of the field check if it is an @Context annotation
37 for (Annotation annotation : fieldAnnotations) {
38
39 if (annotation.getType().getName().toString().equals
("Ljavax/ws/rs/core/Context")) {
40
41 // call the F4F API to assign taint to the field
43 synthMethod.addInstanceVariableWrite(
userRestServiceClazzInstance /*Variable representing
class instance*/,
44 field /*field to taint */,
Taint.taint() /* taint */,
null);
45 }
46 }
47 }
The Framework for Frameworks API addInstanceVariableWrite
takes
four arguments:
- The first argument is the class reference whose field we want
to taint. In the example, the local variable
userRestServiceClazzInstance
refers to this argument. - The second argument is the class field we want to taint.
- The third argument is the new value that will be assigned to the
class variable field. In the example, we want to taint this variable
so that a
Taint.taint()
is passed. - The last argument is
FilePositionInfo
, which isnull
in this example.
Step 3: Model the calling of the createUser()
method
In this step, we simulate the call in our synthetic method.
50 // call createUser() and store the returned value to a local variable
51 Local returnObj = synthMethod.addCall(
52 "com.ibm.appscan.UserRestService.createUser():com.ibm.appscan.User"
/* signature of the method to be called */,
null, /* FilePositionInfo */
53 userRestServiceClazzInstance /* Object on which the method
will be called */);
The addCall
high-level
API takes three arguments:
- The first argument is the signature of the method that we want
to invoke. In this case, we want to invoke
User.createUser()
, hence its signature is used. - The second argument is
FilePositionInfo
. It is passed asnull
as it is not required for this example. - The last argument represents the list of parameters which are
required to invoke the
createUser()
method.
Since createUser()
takes no arguments, the
only argument passed to this call is the this
object,
a Local
variable (userRestServiceClazzInstance
)
of the type User
. The method createUser()
returns
a newly-created User
which is stored in a new Local
variable
called returnedObj
(as shown on line 51).
Step 4: Model data return to the client
In this final step, we create a sink to model the return of data back to the client.
58 // create a PrintWriter object
59 Local printWriterObj = synthMethod.newLocal("java.io.PrintWriter");
60
61 // we want to call the print API on the PrintWriter object.
// The print API takes a single argument of Object type returns void
62
63 // we create a param list of size 2. The first item in this list is always the
// 'this' object and rest are actual method arguments.
64 Param[] printWriterObjParam = new Param[2];
65 printWriterObjParam[0] = printWriterObj; // The "this" object
// the value returned by the call to the createUser method
66 printWriterObjParam[1] = returnObj;
67
68 // Now add a call to the print method
69 synthMethod.addCall("java.io.PrintWriter.print(java.lang.Object):void",
null, printWriterObjParam);
70 }
- At line 59, we create a
Local
object for thePrintWriter
class in the synthetic method. - From lines 64 to 66, we prepare the parameter list which is required
to invoke the
print
method on thePrintWriter
class instance (printWriterObj
):- The first parameter is the object reference (
printWriterObj
), itself. - The second parameter is the argument to the
print
method. We want to pass the return value which is stored in thereturnObj
Local variable.
- The first parameter is the object reference (
- At line 69, we add a call to the
PrintWriter.print
method to model the return of data back to the client.