Skip to content

Commit 3fde2af

Browse files
committed
Add hierarchy of EventBus classes
1 parent 4e32adc commit 3fde2af

File tree

3 files changed

+180
-22
lines changed

3 files changed

+180
-22
lines changed

javascript/frameworks/ui5/ext/ui5.model.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extensions:
33
pack: codeql/javascript-all
44
extensible: "typeModel"
55
data:
6+
- ["SapUICoreInstance", "global", "Member[sap].Member[ui].Member[getCore].ReturnValue"]
67
- ["Control", "Control", "Instance"]
78
- ["Control", "sap/ui/core/Control", ""]
89
- ["Control", "global", "Member[sap].Member[ui].Member[core].Member[Control]"]
@@ -72,10 +73,18 @@ extensions:
7273
- ["UI5ClientStorage", "sap/ui/core/util/File", ""]
7374
- ["UI5ClientStorage", "global", "Member[sap].Member[ui].Member[core].Member[util].Member[File]"]
7475
# Publishing and Subscribing to Events
75-
- ["UI5EventBusPublish", "sap/ui/core/EventBus", "Member[getInstance].ReturnValue.Member[publish]"]
76+
- ["UI5EventBusInstance", "sap/ui/core/EventBus", "Member[getInstance].ReturnValue"]
77+
- ["UI5EventBusPublish", "UI5EventBusInstance", "Member[publish]"]
7678
- ["UI5EventBusPublishedEventData", "UI5EventBusPublish", "Argument[2]"]
77-
- ["UI5EventBusSubscribe", "sap/ui/core/EventBus", "Member[getInstance].ReturnValue.Member[subscribe]"]
79+
- ["UI5EventBusSubscribe", "UI5EventBusInstance", "Member[subscribe]"]
7880
- ["UI5EventSubscriptionHandlerDataParameter", "UI5EventBusSubscribe", "Argument[2].Parameter[2]"]
81+
- ["SapUICoreEventBusInstance", "SapUICoreInstance", "Member[getEventBus].ReturnValue"]
82+
- ["SapUICoreEventBusPublish", "SapUICoreEventBusInstance", "Member[publish]"]
83+
- ["SapUICoreEventBusPublishedEventData", "SapUICoreEventBusPublish", "Argument[2]"]
84+
- ["SapUICoreEventBusSubscribe", "SapUICoreEventBusInstance", "Member[subscribe]"]
85+
- ["SapUICoreEventSubscriptionHandlerDataParameter", "SapUICoreEventBusSubscribe", "Argument[2].Parameter[2]"]
86+
# Extend Calls
87+
# -
7988

8089
- addsTo:
8190
pack: codeql/javascript-all

javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/UI5.qll

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ class WebApp extends HTML::HtmlFile {
139139
* by a call to `sap.ui.getCore()`.
140140
*/
141141
class SapUiCore extends MethodCallNode {
142+
/*
143+
* NOTE: Ideally, we'd like to use `ModelOutput::getATypeNode("SapUICore").asSource()` to
144+
* take advantage of the inter-procedural flexibility of MaD, but doing so causes
145+
* non-monotomic recursion.
146+
*
147+
* So, we opt to use `SourceNode.getAPropertyRead/1` and `SourceNode.getAMethodCall/1`
148+
* instead and get away with local flow tracking they provide.
149+
*/
150+
142151
SapUiCore() { this = globalVarRef("sap").getAPropertyRead("ui").getAMethodCall("getCore") }
143152
}
144153

@@ -1428,3 +1437,159 @@ class PropertyMetadata extends ObjectLiteralNode {
14281437
inSameWebApp(this.getFile(), result.getFile())
14291438
}
14301439
}
1440+
1441+
module EventBus {
1442+
abstract class EventBusPublishCall extends CallNode {
1443+
abstract EventBusSubscribeCall getMatchingSubscribeCall();
1444+
1445+
abstract DataFlow::Node getPublishedData();
1446+
1447+
string getChannelName() { result = this.getArgument(0).getALocalSource().getStringValue() }
1448+
1449+
string getMessageType() { result = this.getArgument(1).getALocalSource().getStringValue() }
1450+
}
1451+
1452+
abstract class EventBusSubscribeCall extends CallNode {
1453+
abstract EventBusPublishCall getMatchingPublishCall();
1454+
1455+
abstract DataFlow::Node getSubscriptionData();
1456+
1457+
string getChannelName() { result = this.getArgument(0).getALocalSource().getStringValue() }
1458+
1459+
string getMessageType() { result = this.getArgument(1).getALocalSource().getStringValue() }
1460+
}
1461+
1462+
class GlobalEventBusPublishCall extends EventBusPublishCall {
1463+
API::Node publishMethod;
1464+
1465+
GlobalEventBusPublishCall() {
1466+
publishMethod = ModelOutput::getATypeNode("UI5EventBusPublish") and
1467+
this = publishMethod.getACall()
1468+
}
1469+
1470+
override GlobalEventBusSubscribeCall getMatchingSubscribeCall() {
1471+
result.getChannelName() = this.getChannelName() and
1472+
result.getMessageType() = this.getMessageType()
1473+
}
1474+
1475+
override DataFlow::Node getPublishedData() {
1476+
exists(API::Node publishedData |
1477+
publishedData = ModelOutput::getATypeNode("UI5EventBusPublishedEventData")
1478+
|
1479+
publishMethod.getASuccessor*() = publishedData and
1480+
result = publishedData.getInducingNode()
1481+
)
1482+
}
1483+
}
1484+
1485+
class SapUICoreEventBusPublishCall extends EventBusPublishCall {
1486+
API::Node publishMethod;
1487+
1488+
SapUICoreEventBusPublishCall() {
1489+
publishMethod = ModelOutput::getATypeNode("SapUICoreEventBusPublish") and
1490+
this = publishMethod.getACall()
1491+
}
1492+
1493+
override SapUICoreEventBusSubscribeCall getMatchingSubscribeCall() {
1494+
result.getChannelName() = this.getChannelName() and
1495+
result.getMessageType() = this.getMessageType()
1496+
}
1497+
1498+
override DataFlow::Node getPublishedData() {
1499+
exists(API::Node publishedData |
1500+
publishedData = ModelOutput::getATypeNode("SapUICoreEventBusPublishedEventData")
1501+
|
1502+
publishMethod.getASuccessor*() = publishedData and
1503+
result = publishedData.getInducingNode()
1504+
)
1505+
}
1506+
}
1507+
1508+
class ComponentEventBusPublishCall extends EventBusPublishCall {
1509+
CustomController controller;
1510+
Component component;
1511+
1512+
ComponentEventBusPublishCall() {
1513+
component = controller.getOwnerComponent() and
1514+
this = controller.getOwnerComponentRef().getAMemberCall("publish")
1515+
}
1516+
1517+
override ComponentEventBusSubscribeCall getMatchingSubscribeCall() {
1518+
result.getChannelName() = this.getChannelName() and
1519+
result.getMessageType() = this.getMessageType() and
1520+
result.getComponent() = this.getComponent()
1521+
}
1522+
1523+
override DataFlow::Node getPublishedData() { result = this.getArgument(2) }
1524+
1525+
Component getComponent() { result = component }
1526+
}
1527+
1528+
class GlobalEventBusSubscribeCall extends EventBusSubscribeCall {
1529+
API::Node subscribeMethod;
1530+
1531+
GlobalEventBusSubscribeCall() {
1532+
subscribeMethod = ModelOutput::getATypeNode("UI5EventBusSubscribe") and
1533+
this = subscribeMethod.getACall()
1534+
}
1535+
1536+
override GlobalEventBusPublishCall getMatchingPublishCall() {
1537+
result.getChannelName() = this.getChannelName() and
1538+
result.getMessageType() = this.getMessageType()
1539+
}
1540+
1541+
override DataFlow::Node getSubscriptionData() {
1542+
exists(API::Node subscribeMethodCallbackDataParameter |
1543+
subscribeMethodCallbackDataParameter =
1544+
ModelOutput::getATypeNode("UI5EventSubscriptionHandlerDataParameter")
1545+
|
1546+
subscribeMethod.getASuccessor*() = subscribeMethodCallbackDataParameter and
1547+
result = subscribeMethodCallbackDataParameter.getInducingNode()
1548+
)
1549+
}
1550+
}
1551+
1552+
class SapUICoreEventBusSubscribeCall extends EventBusSubscribeCall {
1553+
API::Node subscribeMethod;
1554+
1555+
SapUICoreEventBusSubscribeCall() {
1556+
subscribeMethod = ModelOutput::getATypeNode("SapUICoreInstance") and
1557+
this = subscribeMethod.getACall()
1558+
}
1559+
1560+
override SapUICoreEventBusPublishCall getMatchingPublishCall() {
1561+
result.getChannelName() = this.getChannelName() and
1562+
result.getMessageType() = this.getMessageType()
1563+
}
1564+
1565+
override DataFlow::Node getSubscriptionData() {
1566+
exists(API::Node subscribeMethodCallbackDataParameter |
1567+
subscribeMethodCallbackDataParameter =
1568+
ModelOutput::getATypeNode("SapUICoreEventSubscriptionHandlerDataParameter")
1569+
|
1570+
subscribeMethod.getASuccessor*() = subscribeMethodCallbackDataParameter and
1571+
result = subscribeMethodCallbackDataParameter.getInducingNode()
1572+
)
1573+
}
1574+
}
1575+
1576+
class ComponentEventBusSubscribeCall extends EventBusSubscribeCall {
1577+
CustomController controller;
1578+
Component component;
1579+
1580+
ComponentEventBusSubscribeCall() {
1581+
component = controller.getOwnerComponent() and
1582+
this = controller.getOwnerComponentRef().getAMemberCall("subscribe")
1583+
}
1584+
1585+
override ComponentEventBusPublishCall getMatchingPublishCall() {
1586+
result.getChannelName() = this.getChannelName() and
1587+
result.getMessageType() = this.getMessageType() and
1588+
result.getComponent() = this.getComponent()
1589+
}
1590+
1591+
override DataFlow::Node getSubscriptionData() { result = this.getABoundCallbackParameter(2, 2) }
1592+
1593+
Component getComponent() { result = component }
1594+
}
1595+
}

javascript/frameworks/ui5/lib/advanced_security/javascript/frameworks/ui5/dataflow/FlowSteps.qll

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -370,28 +370,12 @@ class LogArgumentToListener extends DataFlow::SharedFlowStep {
370370
class PublishedEventToEventSubscribedEventData extends DataFlow::SharedFlowStep {
371371
override predicate step(DataFlow::Node start, DataFlow::Node end) {
372372
exists(
373-
API::Node publishMethod, API::Node publishedData, API::Node subscribeMethod,
374-
API::Node subscribeMethodCallbackDataParameter
373+
EventBus::EventBusPublishCall publishCall, EventBus::EventBusSubscribeCall subscribeCall
375374
|
376-
publishMethod = ModelOutput::getATypeNode("UI5EventBusPublish") and
377-
publishedData = ModelOutput::getATypeNode("UI5EventBusPublishedEventData") and
378-
subscribeMethod = ModelOutput::getATypeNode("UI5EventBusSubscribe") and
379-
subscribeMethodCallbackDataParameter =
380-
ModelOutput::getATypeNode("UI5EventSubscriptionHandlerDataParameter")
375+
publishCall.getMatchingSubscribeCall() = subscribeCall
381376
|
382-
/* Ensure that `publishedData` belongs to `publishMethod`. */
383-
publishMethod.getASuccessor*() = publishedData and
384-
/* Ensure that `subscribeMethodCallbackDataParameter` belongs to `subscribeMethod`. */
385-
subscribeMethod.getASuccessor*() = subscribeMethodCallbackDataParameter and
386-
/* Ensure that the published and subscribed channels are the same. */
387-
publishMethod.getACall().getArgument(0).getALocalSource().getStringValue() =
388-
subscribeMethod.getACall().getArgument(0).getALocalSource().getStringValue() and
389-
/* Ensure that the published and subscribed message types are the same. */
390-
publishMethod.getACall().getArgument(1).getALocalSource().getStringValue() =
391-
subscribeMethod.getACall().getArgument(1).getALocalSource().getStringValue() and
392-
/* Wire into the start and end of this step. */
393-
start = publishedData.getInducingNode() and
394-
end = subscribeMethodCallbackDataParameter.getInducingNode()
377+
start = publishCall.getPublishedData() and
378+
end = subscribeCall.getSubscriptionData()
395379
)
396380
}
397381
}

0 commit comments

Comments
 (0)