Java: Added sources and flow steps for RabbitMQ

This commit is contained in:
Artem Smotrakov
2022-03-19 17:44:33 +00:00
committed by Chris Smowton
parent fb39e0f577
commit 269143a19f
15 changed files with 198 additions and 0 deletions

View File

@@ -138,6 +138,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.MyBatis
private import semmle.code.java.frameworks.Hibernate
private import semmle.code.java.frameworks.jOOQ
private import semmle.code.java.frameworks.RabbitMQ
}
private predicate sourceModelCsv(string row) {

View File

@@ -21,6 +21,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.RabbitMQ
}
/**

View File

@@ -0,0 +1,58 @@
/**
* Provides classes and predicates related to RabbitMQ.
*/
import java
private import semmle.code.java.dataflow.ExternalFlow
/**
* Defines remote sources in RabbitMQ.
*/
private class RabbitMQSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
// soruces for RabbitMQ 4.x
"com.rabbitmq.client;Command;true;getContentHeader;();;ReturnValue;remote",
"com.rabbitmq.client;Command;true;getContentBody;();;ReturnValue;remote",
"com.rabbitmq.client;Consumer;true;handleDelivery;(String,Envelope,BasicProperties,byte[]);;Parameter[3];remote",
"com.rabbitmq.client;QueueingConsumer;true;nextDelivery;;;ReturnValue;remote",
"com.rabbitmq.client;RpcServer;true;handleCall;(Delivery,BasicProperties);;Parameter[0];remote",
"com.rabbitmq.client;RpcServer;true;handleCall;(BasicProperties,byte[],BasicProperties);;Parameter[1];remote",
"com.rabbitmq.client;RpcServer;true;handleCall;(byte[],BasicProperties);;Parameter[0];remote",
"com.rabbitmq.client;RpcServer;true;preprocessReplyProperties;(Delivery,Builder);;Parameter[0];remote",
"com.rabbitmq.client;RpcServer;true;postprocessReplyProperties;(Delivery,Builder);;Parameter[0];remote",
"com.rabbitmq.client;RpcServer;true;handleCast;(Delivery);;Parameter[0];remote",
"com.rabbitmq.client;RpcServer;true;handleCast;(BasicProperties,byte[]);;Parameter[1];remote",
"com.rabbitmq.client;RpcServer;true;handleCast;(byte[]);;Parameter[0];remote",
"com.rabbitmq.client;StringRpcServer;true;handleStringCall;;;Parameter[0];remote",
"com.rabbitmq.client;RpcClient;true;doCall;;;ReturnValue;remote",
"com.rabbitmq.client;RpcClient;true;primitiveCall;;;ReturnValue;remote",
"com.rabbitmq.client;RpcClient;true;responseCall;;;ReturnValue;remote",
"com.rabbitmq.client;RpcClient;true;stringCall;(String);;ReturnValue;remote",
"com.rabbitmq.client;RpcClient;true;mapCall;;;ReturnValue;remote",
"com.rabbitmq.client.impl;Frame;true;getInputStream;();;ReturnValue;remote",
"com.rabbitmq.client.impl;Frame;true;getPayload;();;ReturnValue;remote",
"com.rabbitmq.client.impl;FrameHandler;true;readFrame;();;ReturnValue;remote",
]
}
}
/**
* Defines flow steps in RabbitMQ.
*/
private class RabbitMQSummaryCsv extends SummaryModelCsv {
override predicate row(string row) {
row =
[
// flow steps for RabbitMQ 4.x
"com.rabbitmq.client;GetResponse;true;GetResponse;;;Argument[2];Argument[-1];taint",
"com.rabbitmq.client;GetResponse;true;getBody;();;Argument[-1];ReturnValue;taint",
"com.rabbitmq.client;RpcClient$Response;true;getBody;();;Argument[-1];ReturnValue;taint",
"com.rabbitmq.client;QueueingConsumer$Delivery;true;getBody;();;Argument[-1];ReturnValue;taint",
"com.rabbitmq.client.impl;Frame;false;fromBodyFragment;(int,byte[],int,int);;Argument[1];ReturnValue;taint",
"com.rabbitmq.client.impl;Frame;false;readFrom;(DataInputStream);;Argument[0];ReturnValue;taint",
"com.rabbitmq.client.impl;Frame;true;writeTo;(DataOutputStream);;Argument[-1];Argument[0];taint",
]
}
}

View File

@@ -0,0 +1,20 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:frameworks:rabbitmq" }
override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node node) {
exists(MethodAccess ma | ma.getMethod().hasName("sink") | node.asExpr() = ma.getAnArgument())
}
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() { none() }
override DataFlow::Configuration getTaintFlowConfig() { result = any(Conf c) }
}

View File

@@ -0,0 +1,19 @@
import java
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineExpectationsTest
class SourceTest extends InlineExpectationsTest {
SourceTest() { this = "SourceTest" }
override string getARelevantTag() { result = "source" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "source" and
exists(RemoteFlowSource source |
not source.asParameter().getCallable().getDeclaringType().hasName("DefaultConsumer") and
source.getLocation() = location and
element = source.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1,34 @@
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
public class Test {
public void defaultConsumerTest(Channel channel) {
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(
String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) { // $source
sink(body); // $hasTaintFlow
}
};
}
public void queueingConsumerTest(QueueingConsumer consumer) {
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery(); // $source
sink(delivery.getBody()); // $hasTaintFlow
delivery = consumer.nextDelivery(42); // $source
sink(delivery.getBody()); // $hasTaintFlow
}
}
private void sink(byte[] data) {
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/rabbitmq-4.12.0

View File

@@ -0,0 +1,8 @@
package com.rabbitmq.client;
public class AMQP {
public static class BasicProperties {
}
}

View File

@@ -0,0 +1,5 @@
package com.rabbitmq.client;
public interface Channel {
}

View File

@@ -0,0 +1,8 @@
package com.rabbitmq.client;
import java.io.IOException;;
public interface Consumer {
void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException;
}

View File

@@ -0,0 +1,15 @@
package com.rabbitmq.client;
import java.io.IOException;
public class DefaultConsumer implements Consumer {
public DefaultConsumer(Channel channel) {
}
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
}
}

View File

@@ -0,0 +1,5 @@
package com.rabbitmq.client;
public class Envelope {
}

View File

@@ -0,0 +1,23 @@
package com.rabbitmq.client;
public class QueueingConsumer extends DefaultConsumer {
public QueueingConsumer(Channel channel) {
super(channel);
}
public Delivery nextDelivery() {
return null;
}
public Delivery nextDelivery(long timeout) {
return null;
}
public static class Delivery {
public byte[] getBody() {
return null;
}
}
}