@@ -147,7 +147,7 @@ abstract class Configuration extends string {
147147 */
148148 predicate isBarrier ( DataFlow:: Node node ) {
149149 exists ( BarrierGuardNode guard |
150- isBarrierGuard ( guard ) and
150+ isBarrierGuardInternal ( guard ) and
151151 guard .internalBlocks ( node , "" )
152152 )
153153 }
@@ -181,7 +181,7 @@ abstract class Configuration extends string {
181181 */
182182 predicate isLabeledBarrier ( DataFlow:: Node node , FlowLabel lbl ) {
183183 exists ( BarrierGuardNode guard |
184- isBarrierGuard ( guard ) and
184+ isBarrierGuardInternal ( guard ) and
185185 guard .internalBlocks ( node , lbl )
186186 )
187187 or
@@ -198,6 +198,12 @@ abstract class Configuration extends string {
198198 */
199199 predicate isBarrierGuard ( BarrierGuardNode guard ) { none ( ) }
200200
201+ private predicate isBarrierGuardInternal ( BarrierGuardNode guard ) {
202+ isBarrierGuard ( guard )
203+ or
204+ guard .( AdditionalBarrierGuardNode ) .appliesTo ( this )
205+ }
206+
201207 /**
202208 * Holds if data may flow from `source` to `sink` for this configuration.
203209 */
@@ -304,7 +310,7 @@ abstract class BarrierGuardNode extends DataFlow::Node {
304310 forex ( SsaVariable input | input = ref .getAnInput ( ) |
305311 asExpr ( ) = ref .getGuard ( ) .getTest ( ) and
306312 outcome = ref .getGuard ( ) .( ConditionGuardNode ) .getOutcome ( ) and
307- internalBlocksExpr ( outcome , input .getAUse ( ) , label )
313+ barrierGuardBlocksExpr ( this , outcome , input .getAUse ( ) , label )
308314 )
309315 )
310316 or
@@ -313,33 +319,11 @@ abstract class BarrierGuardNode extends DataFlow::Node {
313319 nd = DataFlow:: valueNode ( p .getAnInstanceIn ( bb ) ) and
314320 asExpr ( ) = cond .getTest ( ) and
315321 outcome = cond .getOutcome ( ) and
316- internalBlocksAccessPath ( outcome , p , label ) and
322+ barrierGuardBlocksAccessPath ( this , outcome , p , label ) and
317323 cond .dominates ( bb )
318324 )
319325 }
320326
321- /**
322- * Holds if data flow node `nd` acts as a barrier for data flow.
323- *
324- * `label` is bound to the blocked label, or the empty string if all labels should be blocked.
325- */
326- private predicate internalBlocksExpr ( boolean outcome , Expr test , string label ) {
327- blocks ( outcome , test ) and label = ""
328- or
329- blocks ( outcome , test , label )
330- }
331-
332- /**
333- * Holds if data flow node `nd` acts as a barrier for data flow due to aliasing through
334- * an access path.
335- *
336- * `label` is bound to the blocked label, or the empty string if all labels should be blocked.
337- */
338- pragma [ noinline]
339- private predicate internalBlocksAccessPath ( boolean outcome , AccessPath ap , string label ) {
340- internalBlocksExpr ( outcome , ap .getAnInstance ( ) , label )
341- }
342-
343327 /**
344328 * Holds if this node blocks expression `e` provided it evaluates to `outcome`.
345329 *
@@ -353,6 +337,32 @@ abstract class BarrierGuardNode extends DataFlow::Node {
353337 predicate blocks ( boolean outcome , Expr e , FlowLabel label ) { none ( ) }
354338}
355339
340+ /**
341+ * Holds if data flow node `nd` acts as a barrier for data flow.
342+ *
343+ * `label` is bound to the blocked label, or the empty string if all labels should be blocked.
344+ */
345+ private predicate barrierGuardBlocksExpr ( BarrierGuardNode guard , boolean outcome , Expr test , string label ) {
346+ guard .blocks ( outcome , test ) and label = ""
347+ or
348+ guard .blocks ( outcome , test , label )
349+ or
350+ // Handle labelled barrier guard functions specially, to avoid negative recursion
351+ // through the non-abstract 3-argument version of blocks().
352+ guard .( AdditionalBarrierGuardCall ) .internalBlocksLabel ( outcome , test , label )
353+ }
354+
355+ /**
356+ * Holds if data flow node `nd` acts as a barrier for data flow due to aliasing through
357+ * an access path.
358+ *
359+ * `label` is bound to the blocked label, or the empty string if all labels should be blocked.
360+ */
361+ pragma [ noinline]
362+ private predicate barrierGuardBlocksAccessPath ( BarrierGuardNode guard , boolean outcome , AccessPath ap , string label ) {
363+ barrierGuardBlocksExpr ( guard , outcome , ap .getAnInstance ( ) , label )
364+ }
365+
356366/**
357367 * A guard node that only blocks specific labels.
358368 */
@@ -1186,3 +1196,110 @@ module PathGraph {
11861196 not pred = finalMidNode ( succ )
11871197 }
11881198}
1199+
1200+
1201+
1202+ /**
1203+ * Gets an operand of the given `&&` operator.
1204+ *
1205+ * We use this to construct the transitive closure over a relation
1206+ * that does not include all of `BinaryExpr.getAnOperand`.
1207+ */
1208+ private Expr getALogicalAndOperand ( LogAndExpr e ) {
1209+ result = e .getAnOperand ( )
1210+ }
1211+
1212+ /**
1213+ * Gets an operand of the given `||` operator.
1214+ *
1215+ * We use this to construct the transitive closure over a relation
1216+ * that does not include all of `BinaryExpr.getAnOperand`.
1217+ */
1218+ private Expr getALogicalOrOperand ( LogOrExpr e ) {
1219+ result = e .getAnOperand ( )
1220+ }
1221+
1222+ /**
1223+ * A `BarrierGuardNode` that controls which data flow
1224+ * configurations it is used in.
1225+ *
1226+ * Note: For performance reasons, all subclasses of this class should be part
1227+ * of the standard library. Override `Configuration::isBarrierGuard`
1228+ * for analysis-specific barrier guards.
1229+ */
1230+ abstract class AdditionalBarrierGuardNode extends BarrierGuardNode {
1231+ abstract predicate appliesTo ( Configuration cfg ) ;
1232+ }
1233+
1234+ /**
1235+ * A function that returns the result of a barrier guard.
1236+ */
1237+ private class BarrierGuardFunction extends Function {
1238+ DataFlow:: ParameterNode sanitizedParameter ;
1239+ BarrierGuardNode guard ;
1240+ boolean guardOutcome ;
1241+ string label ;
1242+
1243+ BarrierGuardFunction ( ) {
1244+ exists ( Expr e |
1245+ exists ( Expr returnExpr |
1246+ returnExpr = guard .asExpr ( )
1247+ or
1248+ // ad hoc support for conjunctions:
1249+ getALogicalAndOperand + ( returnExpr ) = guard .asExpr ( ) and guardOutcome = true
1250+ or
1251+ // ad hoc support for disjunctions:
1252+ getALogicalOrOperand + ( returnExpr ) = guard .asExpr ( ) and guardOutcome = false
1253+ |
1254+ exists ( SsaExplicitDefinition ssa |
1255+ ssa .getDef ( ) .getSource ( ) = returnExpr and
1256+ ssa .getVariable ( ) .getAUse ( ) = getAReturnedExpr ( )
1257+ )
1258+ or
1259+ returnExpr = getAReturnedExpr ( )
1260+ ) and
1261+ sanitizedParameter .flowsToExpr ( e ) and
1262+ barrierGuardBlocksExpr ( guard , guardOutcome , e , label )
1263+ ) and
1264+ getNumParameter ( ) = 1 and
1265+ sanitizedParameter .getParameter ( ) = getParameter ( 0 )
1266+ }
1267+
1268+ /**
1269+ * Holds if this function sanitizes argument `e` of call `call`, provided the call evaluates to `outcome`.
1270+ */
1271+ predicate isBarrierCall ( DataFlow:: CallNode call , Expr e , boolean outcome , string lbl ) {
1272+ exists ( DataFlow:: Node arg |
1273+ arg .asExpr ( ) = e and
1274+ arg = call .getArgument ( 0 ) and
1275+ call .getNumArgument ( ) = 1 and
1276+ argumentPassing ( call , arg , this , sanitizedParameter ) and
1277+ outcome = guardOutcome and
1278+ lbl = label
1279+ )
1280+ }
1281+
1282+ /**
1283+ * Holds if this function applies to the flow in `cfg`.
1284+ */
1285+ predicate appliesTo ( Configuration cfg ) { cfg .isBarrierGuard ( guard ) }
1286+ }
1287+
1288+ /**
1289+ * A call that sanitizes an argument.
1290+ */
1291+ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode , DataFlow:: CallNode {
1292+ BarrierGuardFunction f ;
1293+
1294+ AdditionalBarrierGuardCall ( ) { f .isBarrierCall ( this , _, _, _) }
1295+
1296+ override predicate blocks ( boolean outcome , Expr e ) {
1297+ f .isBarrierCall ( this , e , outcome , "" )
1298+ }
1299+
1300+ predicate internalBlocksLabel ( boolean outcome , Expr e , DataFlow:: FlowLabel label ) {
1301+ f .isBarrierCall ( this , e , outcome , label )
1302+ }
1303+
1304+ override predicate appliesTo ( Configuration cfg ) { f .appliesTo ( cfg ) }
1305+ }
0 commit comments