534534 * "the IRQL before the corresponding save global call."
535535 */
536536 int getIrqlLevel ( ) {
537- result = any ( getPotentialExitIrqlAtCfnRaw ( this .getMostRecentRaise ( ) .getAPredecessor ( ) ) )
537+ result = any ( getPotentialExitIrqlAtCfnInternal ( this .getMostRecentRaise ( ) .getAPredecessor ( ) ) )
538538 }
539539
540540 int getIrqlLevelExplicit ( ) {
614614 */
615615 int getIrqlLevel ( ) {
616616 result =
617- any ( getPotentialExitIrqlAtCfnRaw ( this .getMostRecentRaiseInterprocedural ( ) .getAPredecessor ( ) ) )
617+ any ( getPotentialExitIrqlAtCfnInternal ( this .getMostRecentRaiseInterprocedural ( ) .getAPredecessor ( ) ) )
618618 }
619619
620620 int getIrqlLevelExplicit ( ) {
665665 * "the IRQL before the corresponding save global call."
666666 */
667667 int getIrqlLevel ( ) {
668- result = any ( getPotentialExitIrqlAtCfnRaw ( this .getMostRecentRaise ( ) .getAPredecessor ( ) ) )
668+ result = any ( getPotentialExitIrqlAtCfnInternal ( this .getMostRecentRaise ( ) .getAPredecessor ( ) ) )
669669 }
670670
671671 int getIrqlLevelExplicit ( ) {
723723 )
724724 or
725725 not exists ( Expr child | child = e1 .getAChild ( ) or child = e2 .getAChild ( ) )
726- }
726+ }
727727
728728 /** Utility function to get all exit points of a function. */
729729 pragma [ nomagic]
745745 */
746746 pragma [ nomagic]
747747 private int functionExitIrql ( Function f ) {
748- result = getPotentialExitIrqlAtCfnRaw ( getAnExitPointOfFunction ( f ) )
748+ result = getPotentialExitIrqlAtCfnInternal ( getAnExitPointOfFunction ( f ) )
749749 }
750750
751751 /**
790790 * Not implemented: _IRQL_limited_to_
791791 */
792792 int getPotentialExitIrqlAtCfn ( ControlFlowNode cfn ) {
793- result = getPotentialExitIrqlAtCfnRaw ( cfn )
793+ result = getPotentialExitIrqlAtCfnInternal ( cfn )
794794 or
795- not exists ( getPotentialExitIrqlAtCfnRaw ( cfn ) ) and
795+ not exists ( getPotentialExitIrqlAtCfnInternal ( cfn ) ) and
796796 result = astLevelExitIrqlFallback ( cfn )
797797 }
798798
803803 * `getPotentialExitIrqlAtCfn` instead, which additionally consults
804804 * `astLevelExitIrqlFallback` when this cascade yields no value.
805805 */
806- private int getPotentialExitIrqlAtCfnRaw ( ControlFlowNode cfn ) {
806+ private int getPotentialExitIrqlAtCfnInternal ( ControlFlowNode cfn ) {
807807 if cfn instanceof KeRaiseIrqlCall
808808 then result = cfn .( KeRaiseIrqlCall ) .getIrqlLevel ( )
809809 else
824824 if
825825 cfn instanceof FunctionCall and
826826 cfn .( FunctionCall ) .getTarget ( ) instanceof IrqlRequiresSameAnnotatedFunction
827- then result = getPotentialExitIrqlAtCfnRaw ( cfn .getAPredecessor ( ) )
827+ then result = getPotentialExitIrqlAtCfnInternal ( cfn .getAPredecessor ( ) )
828828 else
829829 if cfn instanceof FunctionCall
830830 then result = functionExitIrql ( cfn .( FunctionCall ) .getTarget ( ) )
831831 else
832832 if exists ( ControlFlowNode cfn2 | cfn2 = cfn .getAPredecessor ( ) )
833- then result = getPotentialExitIrqlAtCfnRaw ( cfn .getAPredecessor ( ) )
833+ then result = getPotentialExitIrqlAtCfnInternal ( cfn .getAPredecessor ( ) )
834834 else
835835 if exists ( callerPredecessor ( cfn .getControlFlowScope ( ) ) )
836836 then
837837 result =
838- getPotentialExitIrqlAtCfnRaw ( callerPredecessor ( cfn .getControlFlowScope ( ) ) )
838+ getPotentialExitIrqlAtCfnInternal ( callerPredecessor ( cfn .getControlFlowScope ( ) ) )
839839 else
840840 if
841841 cfn .getControlFlowScope ( ) instanceof IrqlRestrictsFunction and
878878 closer .getLocation ( ) .getStartLine ( ) < cfnStmt .getLocation ( ) .getStartLine ( ) and
879879 closer .getLocation ( ) .getStartLine ( ) > prev .getLocation ( ) .getStartLine ( )
880880 ) and
881- result = getPotentialExitIrqlAtCfnRaw ( prev )
881+ result = getPotentialExitIrqlAtCfnInternal ( prev )
882882 )
883883 }
884884
10601060 )
10611061 )
10621062 )
1063- }
1063+ }
1064+ /**
1065+ * Holds if `fc` is a call that may change the IRQL. This includes the
1066+ * IRQL primitives (KeRaiseIrql, KeLowerIrql, KfRaiseIrql, KfLowerIrql,
1067+ * etc., recognized via the `Ke*Irql*Call` and `*GlobalIrqlCall`
1068+ * classes), functions annotated with `_IRQL_raises_` or
1069+ * `_IRQL_saves_global_` / `_IRQL_restores_global_`, and functions
1070+ * whose body itself transitively contains an IRQL-changing call (i.e.,
1071+ * unannotated wrapper helpers).
1072+ *
1073+ * The transitive closure over the call graph is necessary to avoid
1074+ * false negatives where a driver wraps the IRQL primitives in a helper
1075+ * function without the appropriate SAL annotations.
1076+ *
1077+ * Lifted from `IrqlFloatStateMismatch.ql` so other queries (e.g.
1078+ * `IrqlInconsistentWithRequired`) can use the same soundness check.
1079+ */
1080+ predicate isIrqlChangingCall ( FunctionCall fc ) {
1081+ fc instanceof KeRaiseIrqlCall
1082+ or
1083+ fc instanceof KeLowerIrqlCall
1084+ or
1085+ fc instanceof RestoresGlobalIrqlCall
1086+ or
1087+ fc instanceof SavesGlobalIrqlCall
1088+ or
1089+ isIrqlChangingFunction ( fc .getTarget ( ) )
1090+ }
1091+
1092+ /**
1093+ * Holds if `f` directly or transitively contains an IRQL-changing call.
1094+ * See `isIrqlChangingCall`.
1095+ */
1096+ predicate isIrqlChangingFunction ( Function f ) {
1097+ f instanceof IrqlChangesFunction
1098+ or
1099+ exists ( FunctionCall inner |
1100+ inner .getEnclosingFunction ( ) = f and
1101+ isIrqlChangingCall ( inner )
1102+ )
1103+ }
0 commit comments