From 7c518925d8f6e957bf94cc2385bd197f32e614ee Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Mon, 20 Mar 2023 17:46:24 -0700 Subject: [PATCH 01/54] Initial work at IRQL-checking --- .../general/queries/IrqlTooLow/IrqlTooLow.ql | 54 ++++++++++++++++++ src/drivers/libraries/Irql.qll | 57 +++++++++++++------ 2 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql new file mode 100644 index 00000000..f39a5671 --- /dev/null +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-not-used + * @name IRQL not restored + * @description Any parameter annotated \_IRQL\_restores\_ must be read and used to restore the IRQL value. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Insecure Coding Practice + * @repro.text This function has a parameter annotated \_IRQL\_restores\_, but does not have a code path where this parameter is read and used to restore the IRQL. + * @owner.email sdat@microsoft.com + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @query-version v1 + */ + +import cpp +import drivers.libraries.Irql + +/* + * from IrqlAnnotatedFunction iaf, FunctionCall fc + * where fc.getParentScope*() = iaf and + * fc.getTarget() instanceof IrqlAnnotatedFunction and + * fc.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() != iaf.getIrqlLevel() + * select iaf, fc + */ + +class RecursiveIrqlRestrainedCall extends FunctionCall { + RecursiveIrqlRestrainedCall() { + this.getTarget() instanceof IrqlAnnotatedFunction + or + exists(FunctionCall fc2 | + fc2.getEnclosingFunction() = this.getTarget() and + fc2 instanceof RecursiveIrqlRestrainedCall + ) + } + + int getIrqlLevel() { result = this.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() } + + string getFuncIrqlName() { result = this.getTarget().(IrqlAnnotatedFunction).getFuncIrqlName() } +} + +// TODO: Check for IRQL changes within the function (tricky) +from IrqlAnnotatedFunction iaf, RecursiveIrqlRestrainedCall rirf +where + rirf.getEnclosingFunction() = iaf and + iaf instanceof IrqlRequiresAnnotatedFunction and + rirf.getTarget() instanceof IrqlRequiresAnnotatedFunction and + iaf.getIrqlLevel() != rirf.getIrqlLevel() +select iaf, rirf, rirf.getTarget() diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index f809bad5..47bf02bb 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -10,7 +10,7 @@ class IrqlTypeDefinition extends SALAnnotation { //IRQL Annotation Types IrqlTypeDefinition() { //Needs to include other function and parameter annotations too - this.getMacroName().matches(["_IRQL_requires_"]) and + this.getMacroName().matches(["_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_"]) and irqlAnnotationName = this.getMacroName() and exists(MacroInvocation mi | mi.getParentInvocation() = this and @@ -23,6 +23,18 @@ class IrqlTypeDefinition extends SALAnnotation { string getIrqlMacroName() { result = irqlAnnotationName } } +class IrqlMaxAnnotation extends IrqlTypeDefinition { + IrqlMaxAnnotation() { this.getMacroName().matches("_IRQL_requires_max_") } +} + +class IrqlMinAnnotation extends IrqlTypeDefinition { + IrqlMinAnnotation() { this.getMacroName().matches("_IRQL_requires_min_") } +} + +class IrqlRequiresAnnotation extends IrqlTypeDefinition { + IrqlRequiresAnnotation() { this.getMacroName().matches("_IRQL_requires_") } +} + /** * Represents a SAL annotation indicating that the parameter in * question is used as part of adjusting the IRQL. @@ -44,9 +56,7 @@ class IrqlParameterAnnotation extends SALAnnotation { * question contains an IRQL value that the system will be set to. */ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { - IrqlRestoreAnnotation() { - this.getMacroName().matches(["_IRQL_restores_"]) - } + IrqlRestoreAnnotation() { this.getMacroName().matches(["_IRQL_restores_"]) } } /** @@ -54,9 +64,7 @@ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { * question will have the current IRQL saved to it. */ class IrqlSaveAnnotation extends IrqlParameterAnnotation { - IrqlSaveAnnotation() { - this.getMacroName().matches(["_IRQL_saves_"]) - } + IrqlSaveAnnotation() { this.getMacroName().matches(["_IRQL_saves_"]) } } /** Represents a parameter that is annotated with "\_IRQL\_restores\_". */ @@ -69,23 +77,20 @@ class IrqlSaveParameter extends Parameter { IrqlSaveParameter() { exists(IrqlSaveAnnotation isa | isa.getDeclaration() = this) } } -//Represents Irql annotationed functions. +/** Represents a function that is annotated with "\_IRQL_requires_\", etc. */ class IrqlAnnotatedFunction extends Function { - string funcIrqlLevel; - string funcIrqlAnnotationName; + IrqlTypeDefinition irqlAnnotation; IrqlAnnotatedFunction() { - exists(IrqlTypeDefinition itd, FunctionDeclarationEntry fde | + exists(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() and - itd.getDeclarationEntry() = fde and - funcIrqlLevel = itd.getIrqlLevelFull() and - funcIrqlAnnotationName = itd.getIrqlMacroName() + irqlAnnotation.getDeclarationEntry() = fde ) } - private string getLevel() { result = funcIrqlLevel } + private string getLevel() { result = irqlAnnotation.getIrqlLevelFull() } - string getFuncIrqlName() { result = funcIrqlAnnotationName } + string getFuncIrqlName() { result = irqlAnnotation.getIrqlMacroName() } /** * Needs to include other levels too. From MSDN doc: Very few functions have both an upper bound other than DISPATCH_LEVEL and a lower bound other than PASSIVE_LEVEL. @@ -98,10 +103,28 @@ class IrqlAnnotatedFunction extends Function { else if getLevel().matches("%APC_LEVEL%") then result = 1 - else result = 2 + else + if getLevel().matches("%DISPATCH_LEVEL%") + then result = 2 + else + if getLevel().matches("%HIGH_LEVEL%") + then result = 15 + else result = 3 } } +class IrqlRequiresAnnotatedFunction extends IrqlAnnotatedFunction { + IrqlRequiresAnnotatedFunction() { irqlAnnotation instanceof IrqlRequiresAnnotation } +} + +class IrqlMaxAnnotatedFunction extends IrqlAnnotatedFunction { + IrqlMaxAnnotatedFunction() { irqlAnnotation instanceof IrqlMaxAnnotation } +} + +class IrqlMinAnnotatedFunction extends IrqlAnnotatedFunction { + IrqlMinAnnotatedFunction() { irqlAnnotation instanceof IrqlMinAnnotation } +} + //Evaluates to true if a FunctionCall at some points calls Irql annotated Function in its call hierarchy predicate containsIrqlCall(FunctionCall fc) { exists(Function fc2 | From 40d0a8c592271a24bc22aeeec93deb0515c9130f Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:44:38 -0700 Subject: [PATCH 02/54] Significant extra IRQL work. --- .../general/queries/IrqlTooLow/IrqlTooLow.ql | 140 +++++++++++++++--- src/drivers/libraries/Irql.qll | 44 +++++- 2 files changed, 158 insertions(+), 26 deletions(-) diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql index f39a5671..f0451834 100644 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql @@ -21,34 +21,128 @@ import cpp import drivers.libraries.Irql -/* - * from IrqlAnnotatedFunction iaf, FunctionCall fc - * where fc.getParentScope*() = iaf and - * fc.getTarget() instanceof IrqlAnnotatedFunction and - * fc.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() != iaf.getIrqlLevel() - * select iaf, fc +/** Represents a call to a function that has IRQL annotations restricting the range of IRQLs it can run at. */ +class IrqlRestrainedCall extends FunctionCall { + IrqlRestrainedCall() { this.getTarget() instanceof IrqlAnnotatedFunction } + + int getIrqlLevel() { result = this.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() } + + string getFuncIrqlAnnotation() { + result = this.getTarget().(IrqlAnnotatedFunction).getFuncIrqlAnnotation() + } +} + +/** + * Attempt to find the range of valid IRQL values when exiting a given function. + * TODO: Make a version of this focused on calls that we can recursively call to track the IRQL. + * BUG: Returning 15 unexpectedly in places. */ +int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { + if irqlFunc instanceof IrqlRaisesAnnotatedFunction + then result = irqlFunc.getIrqlLevel() + else + if + irqlFunc instanceof IrqlRequiresAnnotatedFunction and + irqlFunc instanceof IrqlRequiresSameAnnotatedFunction + then result = irqlFunc.getIrqlLevel() + else + if irqlFunc instanceof IrqlMaxAnnotatedFunction + then result = any([0 .. irqlFunc.getIrqlLevel()]) + else + if irqlFunc instanceof IrqlMinAnnotatedFunction + then result = any([irqlFunc.getIrqlLevel() .. 15]) + else + // Below is never reached, and is invalid if it is + result = -1 +} -class RecursiveIrqlRestrainedCall extends FunctionCall { - RecursiveIrqlRestrainedCall() { - this.getTarget() instanceof IrqlAnnotatedFunction - or - exists(FunctionCall fc2 | - fc2.getEnclosingFunction() = this.getTarget() and - fc2 instanceof RecursiveIrqlRestrainedCall +/** Given a IrqlRestrainedCall, gets the most recent prior call in the block. */ +IrqlRestrainedCall getPrecedingCallInSameBasicBlock(IrqlRestrainedCall irc) { + result = + irc.getBasicBlock() + .getNode(max(int precPos | + exists(IrqlRestrainedCall prec, int callPos | + irc.getBasicBlock().getNode(precPos) = prec and + irc.getBasicBlock().getNode(callPos) = irc and + precPos < callPos + ) + )) +} + +/** Get the most recent basic block(s) before a given block that also adjust the IRQL. */ +BasicBlock getPrecedingBasicBlocksWithIrqlCalls(BasicBlock inBlock) { + result = + any(BasicBlock bb | + bb.getANode() instanceof IrqlRestrainedCall and + bb.getASuccessor+() = inBlock and + not exists(BasicBlock otherBlock | + bb.getASuccessor+() = otherBlock and + otherBlock.getASuccessor+() = otherBlock and + otherBlock.getANode() instanceof IrqlRestrainedCall + ) ) - } +} - int getIrqlLevel() { result = this.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() } +/** Given a basic block, return the last irql-restrained call in that block. */ +IrqlRestrainedCall lastIrqlCallInBlock(BasicBlock inBlock) { + result = inBlock.getNode(max(int i | inBlock.getNode(i) instanceof IrqlRestrainedCall)) +} - string getFuncIrqlName() { result = this.getTarget().(IrqlAnnotatedFunction).getFuncIrqlName() } +/** Given a irql-restrained call, return the most recent set of irql restrictions prior to it. */ +int getAMostRecentIrql(IrqlRestrainedCall irc) { + if + exists(IrqlRestrainedCall previousCall, int precPos, int callPos | + irc.getBasicBlock().contains(previousCall) and + irc != previousCall and + irc.getBasicBlock().getNode(precPos) = previousCall and + irc.getBasicBlock().getNode(callPos) = irc + ) + then result = getPotentialIrql(getPrecedingCallInSameBasicBlock(irc).getTarget()) + else + // look for most recent basic block(s) with Irql calls + if + exists(BasicBlock previousIrqlBlock, IrqlRestrainedCall previousCall | + irc.getBasicBlock().getAPredecessor+() = previousIrqlBlock and + previousCall.getBasicBlock() = previousIrqlBlock + ) + then + // Can we use the same algorithm as the intra-block search? + // Foreach preceding block that has an IrqlCall, use its values iff not exists + // some other block s.t. there is a path from the preceding block to the other block to our block. + result = + ( + any(IrqlRestrainedCall previousCall | + previousCall = + lastIrqlCallInBlock(getPrecedingBasicBlocksWithIrqlCalls(irc.getBasicBlock())) + ) + ).getIrqlLevel() + else + // Else look at function signature overall + if irc.getEnclosingFunction() instanceof IrqlAnnotatedFunction + then result = getPotentialIrql(irc.getEnclosingFunction()) + else + // Else invalid + result = -1 } -// TODO: Check for IRQL changes within the function (tricky) -from IrqlAnnotatedFunction iaf, RecursiveIrqlRestrainedCall rirf +// TODO: Track IRQL recursively +/* + * from IrqlRestrainedCall irc, int previousLevel + * where + * irc.getTarget() instanceof IrqlMinAnnotatedFunction and + * previousLevel != -1 and + * previousLevel = max(int i | i = getAMostRecentIrql(irc)) and + * irc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel() > previousLevel + * select irc, "IRQL is potentially too low at call $@ - min " + irc.getIrqlLevel() + ", found " + previousLevel, irc, irc.toString() + */ + +// TODO: Track IRQL recursively +from IrqlRestrainedCall irc, int previousLevel where - rirf.getEnclosingFunction() = iaf and - iaf instanceof IrqlRequiresAnnotatedFunction and - rirf.getTarget() instanceof IrqlRequiresAnnotatedFunction and - iaf.getIrqlLevel() != rirf.getIrqlLevel() -select iaf, rirf, rirf.getTarget() + irc.getTarget() instanceof IrqlMaxAnnotatedFunction and + previousLevel != -1 and + previousLevel = min(int i | i = getAMostRecentIrql(irc)) and + irc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < previousLevel +select irc, + "IRQL is potentially too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, + irc, irc.toString() diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 47bf02bb..7142deb5 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -7,10 +7,11 @@ class IrqlTypeDefinition extends SALAnnotation { string irqlLevel; string irqlAnnotationName; - //IRQL Annotation Types + /** Represents standard IRQL annotations which refer to explicit IRQL levels. */ IrqlTypeDefinition() { //Needs to include other function and parameter annotations too - this.getMacroName().matches(["_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_"]) and + this.getMacroName() + .matches(["_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_"]) and irqlAnnotationName = this.getMacroName() and exists(MacroInvocation mi | mi.getParentInvocation() = this and @@ -23,10 +24,28 @@ class IrqlTypeDefinition extends SALAnnotation { string getIrqlMacroName() { result = irqlAnnotationName } } +class IrqlSameAnnotation extends SALAnnotation { + string irqlAnnotationName; + + /** Represents standard IRQL annotations which refer to explicit IRQL levels. */ + IrqlSameAnnotation() { + //Needs to include other function and parameter annotations too + this.getMacroName() + .matches(["_IRQL_requires_same_"]) and + irqlAnnotationName = this.getMacroName() + } + + string getIrqlMacroName() { result = irqlAnnotationName } +} + class IrqlMaxAnnotation extends IrqlTypeDefinition { IrqlMaxAnnotation() { this.getMacroName().matches("_IRQL_requires_max_") } } +class IrqlRaisesAnnotation extends IrqlTypeDefinition { + IrqlRaisesAnnotation() { this.getMacroName().matches("_IRQL_raises_") } +} + class IrqlMinAnnotation extends IrqlTypeDefinition { IrqlMinAnnotation() { this.getMacroName().matches("_IRQL_requires_min_") } } @@ -90,7 +109,7 @@ class IrqlAnnotatedFunction extends Function { private string getLevel() { result = irqlAnnotation.getIrqlLevelFull() } - string getFuncIrqlName() { result = irqlAnnotation.getIrqlMacroName() } + string getFuncIrqlAnnotation() { result = irqlAnnotation.getIrqlMacroName() } /** * Needs to include other levels too. From MSDN doc: Very few functions have both an upper bound other than DISPATCH_LEVEL and a lower bound other than PASSIVE_LEVEL. @@ -113,6 +132,21 @@ class IrqlAnnotatedFunction extends Function { } } +/** Represents a function that changes the IRQL. */ +abstract class IrqlChangesFunction extends IrqlAnnotatedFunction { } + +/** Represents a function that is explicitly annotated to not change the IRQL. */ +class IrqlRequiresSameAnnotatedFunction extends Function { + IrqlSameAnnotation irqlAnnotation; + + IrqlRequiresSameAnnotatedFunction() { + exists(FunctionDeclarationEntry fde | + fde = this.getADeclarationEntry() and + irqlAnnotation.getDeclarationEntry() = fde + ) + } +} + class IrqlRequiresAnnotatedFunction extends IrqlAnnotatedFunction { IrqlRequiresAnnotatedFunction() { irqlAnnotation instanceof IrqlRequiresAnnotation } } @@ -125,6 +159,10 @@ class IrqlMinAnnotatedFunction extends IrqlAnnotatedFunction { IrqlMinAnnotatedFunction() { irqlAnnotation instanceof IrqlMinAnnotation } } +class IrqlRaisesAnnotatedFunction extends IrqlAnnotatedFunction, IrqlChangesFunction { + IrqlRaisesAnnotatedFunction() { irqlAnnotation instanceof IrqlRaisesAnnotation } +} + //Evaluates to true if a FunctionCall at some points calls Irql annotated Function in its call hierarchy predicate containsIrqlCall(FunctionCall fc) { exists(Function fc2 | From 8f96a778f557df533dbae908a306be9520768694 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Fri, 25 Aug 2023 16:08:58 -0700 Subject: [PATCH 03/54] In-progress work --- .../general/queries/IrqlTooLow/IrqlTooLow.ql | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql index f0451834..348f0698 100644 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql @@ -33,8 +33,9 @@ class IrqlRestrainedCall extends FunctionCall { } /** - * Attempt to find the range of valid IRQL values when exiting a given function. + * Attempt to find the range of valid IRQL values when **exiting** a given function. * TODO: Make a version of this focused on calls that we can recursively call to track the IRQL. + * TODO: Cases where annotated min and max * BUG: Returning 15 unexpectedly in places. */ int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { @@ -46,14 +47,24 @@ int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { irqlFunc instanceof IrqlRequiresSameAnnotatedFunction then result = irqlFunc.getIrqlLevel() else - if irqlFunc instanceof IrqlMaxAnnotatedFunction - then result = any([0 .. irqlFunc.getIrqlLevel()]) + if + irqlFunc instanceof IrqlMaxAnnotatedFunction and + irqlFunc instanceof IrqlMinAnnotatedFunction + then + result = + any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. irqlFunc + .(IrqlMaxAnnotatedFunction) + .getIrqlLevel()] + ) else - if irqlFunc instanceof IrqlMinAnnotatedFunction - then result = any([irqlFunc.getIrqlLevel() .. 15]) + if irqlFunc instanceof IrqlMaxAnnotatedFunction + then result = any([0 .. irqlFunc.getIrqlLevel()]) else - // Below is never reached, and is invalid if it is - result = -1 + if irqlFunc instanceof IrqlMinAnnotatedFunction + then result = any([irqlFunc.getIrqlLevel() .. 15]) + else + // Below is never reached, and is invalid if it is + result = -1 } /** Given a IrqlRestrainedCall, gets the most recent prior call in the block. */ @@ -144,5 +155,5 @@ where previousLevel = min(int i | i = getAMostRecentIrql(irc)) and irc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < previousLevel select irc, - "IRQL is potentially too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, + "IRQL is too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, irc, irc.toString() From 7479c24156c074a83edba378d678030cb1be2543 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:58:07 -0700 Subject: [PATCH 04/54] More puttering around with IRQL --- .../general/queries/IrqlTooLow/IrqlTooLow.ql | 26 +++- src/drivers/libraries/Irql.qll | 113 +++++++++++++++++- 2 files changed, 128 insertions(+), 11 deletions(-) diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql index 348f0698..e6b41b5c 100644 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql @@ -49,7 +49,8 @@ int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { else if irqlFunc instanceof IrqlMaxAnnotatedFunction and - irqlFunc instanceof IrqlMinAnnotatedFunction + irqlFunc instanceof IrqlMinAnnotatedFunction and + irqlFunc instanceof IrqlRequiresSameAnnotatedFunction then result = any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. irqlFunc @@ -57,16 +58,30 @@ int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { .getIrqlLevel()] ) else - if irqlFunc instanceof IrqlMaxAnnotatedFunction + if + irqlFunc instanceof IrqlMaxAnnotatedFunction and + irqlFunc instanceof IrqlRequiresSameAnnotatedFunction then result = any([0 .. irqlFunc.getIrqlLevel()]) else - if irqlFunc instanceof IrqlMinAnnotatedFunction + if + irqlFunc instanceof IrqlMinAnnotatedFunction and + irqlFunc instanceof IrqlRequiresSameAnnotatedFunction then result = any([irqlFunc.getIrqlLevel() .. 15]) else - // Below is never reached, and is invalid if it is + // Below indicates we cannot determine the correct IRQL result = -1 } +cached +int getIrqlAtThisStatement(Expr e) { + if e instanceof KeRaiseIrqlCall + then result = e.(KeRaiseIrqlCall).getIrqlLevel() + else + if not exists(ControlFlowNode cfn | cfn = e.getAPredecessor()) + then result = 0 + else result = any(getIrqlAtThisStatement(e.getAPredecessor())) +} + /** Given a IrqlRestrainedCall, gets the most recent prior call in the block. */ IrqlRestrainedCall getPrecedingCallInSameBasicBlock(IrqlRestrainedCall irc) { result = @@ -154,6 +169,5 @@ where previousLevel != -1 and previousLevel = min(int i | i = getAMostRecentIrql(irc)) and irc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < previousLevel -select irc, - "IRQL is too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, +select irc, "IRQL is too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, irc, irc.toString() diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 7142deb5..86190d83 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -30,8 +30,7 @@ class IrqlSameAnnotation extends SALAnnotation { /** Represents standard IRQL annotations which refer to explicit IRQL levels. */ IrqlSameAnnotation() { //Needs to include other function and parameter annotations too - this.getMacroName() - .matches(["_IRQL_requires_same_"]) and + this.getMacroName().matches(["_IRQL_requires_same_"]) and irqlAnnotationName = this.getMacroName() } @@ -112,7 +111,7 @@ class IrqlAnnotatedFunction extends Function { string getFuncIrqlAnnotation() { result = irqlAnnotation.getIrqlMacroName() } /** - * Needs to include other levels too. From MSDN doc: Very few functions have both an upper bound other than DISPATCH_LEVEL and a lower bound other than PASSIVE_LEVEL. + * Get the level represented by this IRQL function. From MSDN doc: Very few functions have both an upper bound other than DISPATCH_LEVEL and a lower bound other than PASSIVE_LEVEL. * * The other IRQL levels are Processor-specific */ @@ -128,7 +127,7 @@ class IrqlAnnotatedFunction extends Function { else if getLevel().matches("%HIGH_LEVEL%") then result = 15 - else result = 3 + else result = 2 } } @@ -159,7 +158,7 @@ class IrqlMinAnnotatedFunction extends IrqlAnnotatedFunction { IrqlMinAnnotatedFunction() { irqlAnnotation instanceof IrqlMinAnnotation } } -class IrqlRaisesAnnotatedFunction extends IrqlAnnotatedFunction, IrqlChangesFunction { +class IrqlRaisesAnnotatedFunction extends IrqlAnnotatedFunction, IrqlChangesFunction { IrqlRaisesAnnotatedFunction() { irqlAnnotation instanceof IrqlRaisesAnnotation } } @@ -183,3 +182,107 @@ IrqlAnnotatedFunction getActualIrqlFunc(FunctionCall fc) { class CallsToIrqlAnnotatedFunction extends FunctionCall { CallsToIrqlAnnotatedFunction() { containsIrqlCall(this) } } + +class KeRaiseIrqlCall extends FunctionCall { + KeRaiseIrqlCall() { this.getTarget().getName().matches(any(["KeRaiseIrql", "KfRaiseIrql"])) } + + int getIrqlLevel() { + result = this.getArgument(0).(Literal).getValue().toInt() + } +} + +class IrqlLiteral extends Literal { + IrqlLiteral() { + this.getValueText() + .matches(any([ + "PASSIVE_LEVEL", "LOW_LEVEL", "APC_LEVEL", "DISPATCH_LEVEL", "CMCI_LEVEL", + "CLOCK_LEVEL", "IPI_LEVEL", "DRS_LEVEL", "POWER_LEVEL", "HIGH_LEVEL" + ] + )) or + this.getValueText().toInt() = any([0 .. 31]) + } + + string getRealValue() { result = this.getValue() } +} +// TODO: Add support for KeRaiseIrql/KeLowerIrql and variants +/* + * _IRQL_requires_max_(HIGH_LEVEL) + * _IRQL_raises_(NewIrql) + * _IRQL_saves_ + * NTKERNELAPI + * KIRQL + * KfRaiseIrql ( + * _In_ KIRQL NewIrql + * ); + */ + +// The problem here is that it's a dynamic value based on the NewIrql being passed in. Do we have a way to marry an annotation +// and a parameter? We can match on name, and then store the index in question... and then in logic we would need to check +// the argument passed in at parameter [x]. The value of x itself would depend on data-flow analysis, blech. Maybe that's +// too much for a V1. Still, if x is a literal, or a constant that can we coerce into an int, things get easier. +// Let me review the actual check(s) that CA performs and see what parity looks like. +// Comments from experimenting a bit: +// CA yells at you if you directly call KeRaiseIrql, etc. without an annotation. +// CA does _not_ yell at you if you call a function that directly calls KeRaiseIrql, etc. without an annotation. +// CA _does_ yell at you if you raise the IRQL in a conditional before calling a function which doesn't allow itself to be raised that high. +// +/* + * The following code gets the following warning: + * + * _IRQL_raises_(irqlToSet) + * NTSTATUS + * Defect_SetIRQL2(KIRQL* outIrql, KIRQL irqlToSet) + * { + * KeRaiseIrql(irqlToSet, outIrql); + * return STATUS_SUCCESS; + * } + * + * const KIRQL myIrqlLiteral = DISPATCH_LEVEL; + * + * NTSTATUS + * Defect_IRQL2(int doIrql)//, KIRQL irqlToSet) + * { + * KIRQL outIrql; + * if (doIrql) { + * Defect_SetIRQL2(&outIrql, myIrqlLiteral); + * } + * Defect_MaxIRQL(); + * return STATUS_SUCCESS; + * } + * + * Severity Code Description Project File Line Suppression State + * Warning C28167 The function 'Defect_IRQL2' changes the IRQL and does not restore the IRQL before it exits. It should be annotated to reflect the change or the IRQL should be restored. IRQL was last set at line 1576. defect_toastmon C:\Users\natede\source\repos\Windows-driver-samples\tools\dv\samples\DV-FailDriver-WDM\defect_toastmon.c 1572 + * + * In other words, it does not track constants. + * + * However, if I pass DISPATCH_LEVEL in directly, that *does* flag the "Irql too high" error: + * + * Severity Code Description Project File Line Suppression State + * Warning C28121 The function 'Defect_MaxIRQL' is not permitted to be called at the current IRQ level. The current level is too high: IRQL was last set to 2 at line 1576. The level might have been inferred from the function signature. defect_toastmon C:\Users\natede\source\repos\Windows-driver-samples\tools\dv\samples\DV-FailDriver-WDM\defect_toastmon.c 1578 + * + * So. We _do_ need to support literals. + * Also, CA yells at me if I use _IRQL_raises_(outIrql), so it is tracking which parameter becomes the IRQL... dang. + * + * Maybe a better way to handle all this is to do analyses at call-time? + */ + +/* + * More noodling. How do I track the IRQL at a given statement? + * + * I guess we could evaluate it at every statement, with a default of 0. Like a recursive function with logic of + * + * if this statement cannot change irql: + * irql = any(irql of previous statements) + * + * if this statement CAN change irql, either by being a function call to a function that raises IRQL or one that lowers, then we need to do proper analysis. + * if KeRaise: irql = (whatever the passed in value is) + * if KeLower: irql = any(data flow for the passed in variable) + * if calling a function annotated to raise: irql = (whatever the annotation is) + * if calling a function guaranteed to not change irql: irql = irql + * + * if first statement in a function: irql = any([whatever the irql value at the call site(s) is]) + * can also use annotations...? + * + * Wait, hold on. I'm getting my wires crossed. What I'm describing is "actual" irql flow. What CA does is look for contradictions in annotations, right? + */ + From 9d96c8977c113a7f7fe09f8e75cba20940501634 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:24:46 -0700 Subject: [PATCH 05/54] Update to CodeQL 2.14.4 Update cpp-all to 0.9.2, cpp-queries to 0.7.4 --- src/codeql-pack.lock.yml | 16 +++++++++++----- src/qlpack.lock.yml | 10 ---------- src/qlpack.yml | 6 +++--- 3 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 src/qlpack.lock.yml diff --git a/src/codeql-pack.lock.yml b/src/codeql-pack.lock.yml index 4fc89962..2c012295 100644 --- a/src/codeql-pack.lock.yml +++ b/src/codeql-pack.lock.yml @@ -2,11 +2,17 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.4.6 - codeql/ssa: - version: 0.0.7 + version: 0.9.2 codeql/cpp-queries: - version: 0.4.6 + version: 0.7.4 + codeql/dataflow: + version: 0.0.3 + codeql/ssa: + version: 0.1.4 codeql/suite-helpers: - version: 0.3.6 + version: 0.6.4 + codeql/tutorial: + version: 0.1.4 + codeql/util: + version: 0.1.4 compiled: false diff --git a/src/qlpack.lock.yml b/src/qlpack.lock.yml deleted file mode 100644 index 5efc9529..00000000 --- a/src/qlpack.lock.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -dependencies: - codeql/cpp-queries: - version: 0.2.0 - codeql/suite-helpers: - version: 0.1.0 - codeql/cpp-all: - version: 0.3.5 -compiled: false -lockVersion: 1.0.0 diff --git a/src/qlpack.yml b/src/qlpack.yml index 15fcb2f0..1d1a053c 100644 --- a/src/qlpack.yml +++ b/src/qlpack.yml @@ -2,10 +2,10 @@ # Licensed under the MIT license. name: microsoft/windows-drivers -version: 0.1.0 +version: 0.2.0 dependencies: - codeql/cpp-queries: ^0.4.5 - codeql/cpp-all: ^0.4.5 + codeql/cpp-queries: 0.7.4 + codeql/cpp-all: 0.9.2 suites: suites extractor: cpp licenses: MIT From 1cbca7ee86e4020bd0d1a16cfc255a83fdba74cc Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:39:20 -0700 Subject: [PATCH 06/54] Commit more IRQL code. Needs cleanup. --- .../general/queries/IrqlTooLow/IrqlTooHigh.ql | 33 ++ .../general/queries/IrqlTooLow/IrqlTooLow2.ql | 46 ++ src/drivers/libraries/Irql.qll | 420 +++++++++++++++--- src/drivers/libraries/SAL.qll | 5 + src/drivers/wdm/libraries/WdmDrivers.qll | 7 + 5 files changed, 461 insertions(+), 50 deletions(-) create mode 100644 src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql create mode 100644 src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql new file mode 100644 index 00000000..74f1bbb7 --- /dev/null +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-too-high + * @name IRQL too low + * @description A function annotated with IRQL requirements was called at an IRQL too high for the requirements. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Insecure Coding Practice + * @repro.text A function annotated with IRQL requirements was called at an IRQL too high for the requirements. + * @owner.email sdat@microsoft.com + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @query-version v1 + */ + +import cpp +import drivers.libraries.Irql + +// Take it from the top... +from FunctionCall fc +where + fc.getTarget() instanceof IrqlMaxAnnotatedFunction and + fc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < + min(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) +select fc, + "IRQL potentially too low high this call ($@). Maximum irql level of this call: $@, Irql level at preceding node: $@", + fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel(), + fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql new file mode 100644 index 00000000..5e7e19be --- /dev/null +++ b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-too-low + * @name IRQL too low + * @description A function annotated with IRQL requirements was called at an IRQL too low for the requirements. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Insecure Coding Practice + * @repro.text A function annotated with IRQL requirements was called at an IRQL too low for the requirements. + * @owner.email sdat@microsoft.com + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @query-version v1 + */ + +import cpp +import drivers.libraries.Irql +import semmle.code.cpp.controlflow.Guards + +//TODO: What do we do with cases like FILTER_LOCK, where there is a guard around using a call? + +// Take it from the top... +from FunctionCall fc, IrqlMinAnnotatedFunction imaf +where + fc.getTarget() = imaf and + imaf.getIrqlLevel() > max(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) + and not exists(GuardCondition c | c.controls(fc.getBasicBlock(), false)) +select fc, + "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", + fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel(), + fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) +/* + * fc.getTarget() instanceof IrqlMinAnnotatedFunction and + * fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel() > + * max(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) + * select fc, + * "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", + * fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel(), + * fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) + */ + diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 86190d83..4daef9e3 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -2,32 +2,104 @@ // Licensed under the MIT license. import cpp import drivers.libraries.SAL +import drivers.wdm.libraries.WdmDrivers -class IrqlTypeDefinition extends SALAnnotation { +/** + * A macro in wdm.h that represents an IRQL level, + * such as PASSIVE_LEVEL, DISPATCH_LEVEL, etc. + */ +class IrqlMacro extends Macro { + int irqlLevelAsInt; + + IrqlMacro() { + this.getName().matches("%_LEVEL") and + this.getFile().getBaseName().matches("wdm.h") and + this.getBody().toInt() = irqlLevelAsInt and + irqlLevelAsInt >= 0 and + irqlLevelAsInt <= 31 + } + + /** Returns the integer value of this IRQL level. */ + int getIrqlLevel() { result = irqlLevelAsInt } + + /** + * Returns the highest IRQL in wdm.h across this database. + * May cause incorrect results if database contains both 32-bit + * and 64-bit builds. + */ + int getGlobalMaxIrqlLevel() { + result = + any(int i | + exists(IrqlMacro im | + i = im.getIrqlLevel() and + not exists(IrqlMacro im2 | im2 != im and im2.getIrqlLevel() > im.getIrqlLevel()) + ) + ) + } +} + +/** Represents an _IRQL_saves_global_(parameter, kind) annotation. */ +class IrqlSavesGlobalAnnotation extends SALAnnotation { + MacroInvocation irqlMacroInvocation; + + IrqlSavesGlobalAnnotation() { + // Needs to include other function and parameter annotations too + this.getMacroName().matches(["_IRQL_saves_global_"]) and + irqlMacroInvocation.getParentInvocation() = this + } +} + +/** Represents an _IRQL_restores_global_(parameter, kind) annotation. */ +class IrqlRestoresGlobalAnnotation extends SALAnnotation { + MacroInvocation irqlMacroInvocation; + + IrqlRestoresGlobalAnnotation() { + // Needs to include other function and parameter annotations too + this.getMacroName().matches(["_IRQL_restores_global_"]) and + irqlMacroInvocation.getParentInvocation() = this + } +} + +/** Represents standard IRQL annotations which refer to explicit IRQL levels. */ +class IrqlAnnotation extends SALAnnotation { string irqlLevel; string irqlAnnotationName; + MacroInvocation irqlMacroInvocation; - /** Represents standard IRQL annotations which refer to explicit IRQL levels. */ - IrqlTypeDefinition() { - //Needs to include other function and parameter annotations too + IrqlAnnotation() { + // Needs to include other function and parameter annotations too this.getMacroName() .matches(["_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_"]) and irqlAnnotationName = this.getMacroName() and - exists(MacroInvocation mi | - mi.getParentInvocation() = this and - irqlLevel = mi.getMacro().getHead() - ) + irqlMacroInvocation.getParentInvocation() = this and + irqlLevel = irqlMacroInvocation.getMacro().getHead() } + /** Returns the raw text of the IRQL value used in this annotation. */ string getIrqlLevelFull() { result = irqlLevel } + /** Returns the text of this annotation (i.e. _IRQL_requires_, etc.) */ string getIrqlMacroName() { result = irqlAnnotationName } + + /** Evaluate the IRQL specified in this annotation, if possible. */ + int getIrqlLevel() { + if exists(IrqlMacro im | im.getHead().matches(this.getIrqlLevelFull())) + then + result = + any(int i | + exists(IrqlMacro im | + im.getIrqlLevel() = i and + im.getHead().matches(this.getIrqlLevelFull()) + ) + ) + else result = -1 + } } +/** Represents an "_IRQL_requires_same" annotation. */ class IrqlSameAnnotation extends SALAnnotation { string irqlAnnotationName; - /** Represents standard IRQL annotations which refer to explicit IRQL levels. */ IrqlSameAnnotation() { //Needs to include other function and parameter annotations too this.getMacroName().matches(["_IRQL_requires_same_"]) and @@ -37,19 +109,19 @@ class IrqlSameAnnotation extends SALAnnotation { string getIrqlMacroName() { result = irqlAnnotationName } } -class IrqlMaxAnnotation extends IrqlTypeDefinition { +class IrqlMaxAnnotation extends IrqlAnnotation { IrqlMaxAnnotation() { this.getMacroName().matches("_IRQL_requires_max_") } } -class IrqlRaisesAnnotation extends IrqlTypeDefinition { +class IrqlRaisesAnnotation extends IrqlAnnotation { IrqlRaisesAnnotation() { this.getMacroName().matches("_IRQL_raises_") } } -class IrqlMinAnnotation extends IrqlTypeDefinition { +class IrqlMinAnnotation extends IrqlAnnotation { IrqlMinAnnotation() { this.getMacroName().matches("_IRQL_requires_min_") } } -class IrqlRequiresAnnotation extends IrqlTypeDefinition { +class IrqlRequiresAnnotation extends IrqlAnnotation { IrqlRequiresAnnotation() { this.getMacroName().matches("_IRQL_requires_") } } @@ -95,44 +167,43 @@ class IrqlSaveParameter extends Parameter { IrqlSaveParameter() { exists(IrqlSaveAnnotation isa | isa.getDeclaration() = this) } } -/** Represents a function that is annotated with "\_IRQL_requires_\", etc. */ -class IrqlAnnotatedFunction extends Function { - IrqlTypeDefinition irqlAnnotation; +/** A typedef that has IRQL annotations applied to it. */ +class IrqlAnnotatedTypedef extends TypedefType { + IrqlAnnotation irqlAnnotation; + + IrqlAnnotatedTypedef() { irqlAnnotation.getTypedefDeclarations() = this } + + IrqlAnnotation getIrqlAnnotation() { result = irqlAnnotation } +} + +/** + * Represents a function that is annotated in such a way that + * either its entry or exit IRQL is restricted, either by having a min/max value, + * a required value, or by raising the IRQL to a known value. + */ +cached +class IrqlRestrictsFunction extends Function { + IrqlAnnotation irqlAnnotation; - IrqlAnnotatedFunction() { + cached + IrqlRestrictsFunction() { exists(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() and irqlAnnotation.getDeclarationEntry() = fde ) + or + exists(FunctionDeclarationEntry fde | + fde.getFunction() = this and + fde.getTypedefType().(IrqlAnnotatedTypedef).getIrqlAnnotation() = irqlAnnotation + ) } - private string getLevel() { result = irqlAnnotation.getIrqlLevelFull() } - + cached string getFuncIrqlAnnotation() { result = irqlAnnotation.getIrqlMacroName() } - - /** - * Get the level represented by this IRQL function. From MSDN doc: Very few functions have both an upper bound other than DISPATCH_LEVEL and a lower bound other than PASSIVE_LEVEL. - * - * The other IRQL levels are Processor-specific - */ - int getIrqlLevel() { - if getLevel().matches("%PASSIVE_LEVEL%") - then result = 0 - else - if getLevel().matches("%APC_LEVEL%") - then result = 1 - else - if getLevel().matches("%DISPATCH_LEVEL%") - then result = 2 - else - if getLevel().matches("%HIGH_LEVEL%") - then result = 15 - else result = 2 - } } /** Represents a function that changes the IRQL. */ -abstract class IrqlChangesFunction extends IrqlAnnotatedFunction { } +abstract class IrqlChangesFunction extends Function { } /** Represents a function that is explicitly annotated to not change the IRQL. */ class IrqlRequiresSameAnnotatedFunction extends Function { @@ -146,35 +217,83 @@ class IrqlRequiresSameAnnotatedFunction extends Function { } } -class IrqlRequiresAnnotatedFunction extends IrqlAnnotatedFunction { +class IrqlRequiresAnnotatedFunction extends IrqlRestrictsFunction { IrqlRequiresAnnotatedFunction() { irqlAnnotation instanceof IrqlRequiresAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlRequiresAnnotation).getIrqlLevel() } } -class IrqlMaxAnnotatedFunction extends IrqlAnnotatedFunction { +class IrqlMaxAnnotatedFunction extends IrqlRestrictsFunction { IrqlMaxAnnotatedFunction() { irqlAnnotation instanceof IrqlMaxAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlMaxAnnotation).getIrqlLevel() } } -class IrqlMinAnnotatedFunction extends IrqlAnnotatedFunction { +class IrqlMinAnnotatedFunction extends IrqlRestrictsFunction { IrqlMinAnnotatedFunction() { irqlAnnotation instanceof IrqlMinAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlMinAnnotation).getIrqlLevel() } } -class IrqlRaisesAnnotatedFunction extends IrqlAnnotatedFunction, IrqlChangesFunction { +class IrqlRaisesAnnotatedFunction extends IrqlRestrictsFunction, IrqlChangesFunction { IrqlRaisesAnnotatedFunction() { irqlAnnotation instanceof IrqlRaisesAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlRaisesAnnotation).getIrqlLevel() } +} + +/** A function annotated to save the IRQL at the specified location upon entry. */ +class IrqlSavesGlobalAnnotatedFunction extends IrqlChangesFunction { + IrqlSavesGlobalAnnotation irqlAnnotation; + string irqlKind; + int irqlParamIndex; + + IrqlSavesGlobalAnnotatedFunction() { + exists(FunctionDeclarationEntry fde | + fde = this.getADeclarationEntry() and + irqlAnnotation.getDeclarationEntry() = fde + ) and + irqlKind = irqlAnnotation.getExpandedArgument(0) and + this.getParameter(irqlParamIndex).getName().matches(irqlAnnotation.getExpandedArgument(1)) + } + + string getIrqlKind() { result = irqlKind } + + int getIrqlParameterSlot() { result = irqlParamIndex } +} + +/** A function annotated to restore the IRQL from the specified location upon exit. */ +class IrqlRestoresGlobalAnnotatedFunction extends IrqlChangesFunction { + IrqlRestoresGlobalAnnotation irqlAnnotation; + string irqlKind; + int irqlParamIndex; + + IrqlRestoresGlobalAnnotatedFunction() { + exists(FunctionDeclarationEntry fde | + fde = this.getADeclarationEntry() and + irqlAnnotation.getDeclarationEntry() = fde + ) and + irqlKind = irqlAnnotation.getExpandedArgument(0) and + this.getParameter(irqlParamIndex).getName().matches(irqlAnnotation.getExpandedArgument(1)) + } + + string getIrqlKind() { result = irqlKind } + + int getIrqlParameterSlot() { result = irqlParamIndex } } //Evaluates to true if a FunctionCall at some points calls Irql annotated Function in its call hierarchy predicate containsIrqlCall(FunctionCall fc) { exists(Function fc2 | fc.getTarget().calls*(fc2) and - fc2 instanceof IrqlAnnotatedFunction + fc2 instanceof IrqlRestrictsFunction ) } -//Returns functions in the ControlFlow path that are instance of IrqlAnnotatedFunction -IrqlAnnotatedFunction getActualIrqlFunc(FunctionCall fc) { +//Returns functions in the ControlFlow path that are instance of IrqlRestrictsFunction +IrqlRestrictsFunction getActualIrqlFunc(FunctionCall fc) { exists(Function fc2 | fc.getTarget().calls*(fc2) and - fc2 instanceof IrqlAnnotatedFunction and + fc2 instanceof IrqlRestrictsFunction and result = fc2 ) } @@ -183,11 +302,212 @@ class CallsToIrqlAnnotatedFunction extends FunctionCall { CallsToIrqlAnnotatedFunction() { containsIrqlCall(this) } } +/** A call to a KeRaiseIRQL API that directly raises the IRQL. */ class KeRaiseIrqlCall extends FunctionCall { - KeRaiseIrqlCall() { this.getTarget().getName().matches(any(["KeRaiseIrql", "KfRaiseIrql"])) } + KeRaiseIrqlCall() { + this.getTarget() + .getName() + .matches(any([ + "KeRaiseIrql", "KfRaiseIrql", "KeRaiseIrqlToDPCLevel", "KfRaiseIrqlToDPCLevel" + ] + )) + } int getIrqlLevel() { - result = this.getArgument(0).(Literal).getValue().toInt() + if this.getTarget().getName().matches(any(["KeRaiseIrqlToDPCLevel", "KfRaiseIrqlToDPCLevel"])) + then result = 2 + else result = this.getArgument(0).(Literal).getValue().toInt() + } +} + +/** A call to a function that restores the IRQL from a specified state. */ +class SavesGlobalIrqlCall extends FunctionCall { + SavesGlobalIrqlCall() { this.getTarget() instanceof IrqlSavesGlobalAnnotatedFunction } +} + +/** A call to a function that restores the IRQL from a specified state. */ +class RestoresGlobalIrqlCall extends FunctionCall { + RestoresGlobalIrqlCall() { this.getTarget() instanceof IrqlRestoresGlobalAnnotatedFunction } + + /** + * A heuristic evaluation of the IRQL that the system is lowering to. This is defined as + * "the IRQL before the corresponding save global call." + */ + int getIrqlLevel() { + result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + } + + /** Returns the matching call to a function that saved the IRQL to a global state. */ + SavesGlobalIrqlCall getMostRecentRaise() { + result = + any(SavesGlobalIrqlCall sgic | + this.getAPredecessor*() = sgic and + matchingSaveCall(sgic) and + not exists(SavesGlobalIrqlCall sgic2 | + sgic2 != sgic and sgic2.getAPredecessor*() = sgic and matchingSaveCall(sgic2) + ) + ) + } + + /** Holds if a given call to an _IRQL_Saves_Global_ annotated function is using the same IRQL location as this. */ + predicate matchingSaveCall(SavesGlobalIrqlCall sgic) { + // Attempting to match all expr children leads to an explosion in runtime, so for now just compare + // first child of each argument. This covers the common &variable case. + exists(int i, int j | + i = this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlParameterSlot() and + j = sgic.getTarget().(IrqlSavesGlobalAnnotatedFunction).getIrqlParameterSlot() and + this.getArgument(i).toString().matches(sgic.getArgument(j).toString()) and + ( + exists(Expr child | + child = this.getArgument(i).getAChild() and + this.getArgument(i) + .getChild(0) + .toString() + .matches(sgic.getArgument(j).getChild(0).toString()) + ) + or + not exists(Expr child | child = this.getArgument(i).getAChild()) + ) + ) and + this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlKind() = + sgic.getTarget().(IrqlSavesGlobalAnnotatedFunction).getIrqlKind() + } +} + +/** + * Attempt to provide the IRQL **once this control flow node exits**, based on annotations and direct calls to raising/lowering functions. + * This predicate functions as follows: + * - If calling a "Raise IRQL" function, then it returns the value of the argument passed in (the target IRQL). + * - If calling a "Lower IRQL" function, then it returns the value of the argument passed in (the target IRQL). + * - If calling a function annotated to restore the IRQL from a previously saved spot, then the result is the IRQL before that save call. + * - If calling a function annotated to raise the IRQL, then it returns the annotated value (the target IRQL). + * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN. + * - If this node immediately precedes a call to a call annotated _Irql_Requires_, then the result is the annotated value for that call. + * - If there is a prior CFN in the CFG, the result is the result for that prior CFN. + * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function. + * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. + * - If there is nothing else, then IRQL is 0. + * TODO: _IRQL_limited_to_(DISPATCH_LEVEL); + * BUG: At Windows-driver-samples\network\ndis\filter\device.c:263, FILTER_ACQUIRE_LOCK does a static check of "if second variable + * at this macro is false, then use raisetodpc instead of atdpc." How can we track these guards? Maybe we can import guard conditions and + * use a limited analysis? + */ +cached +int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { + if cfn instanceof KeRaiseIrqlCall + then result = cfn.(KeRaiseIrqlCall).getIrqlLevel() + else + if cfn instanceof KeLowerIrqlCall + then result = cfn.(KeLowerIrqlCall).getIrqlLevel() + else + if cfn instanceof RestoresGlobalIrqlCall + then result = cfn.(RestoresGlobalIrqlCall).getIrqlLevel() + else + if + cfn instanceof FunctionCall and + cfn.(FunctionCall).getTarget() instanceof IrqlRaisesAnnotatedFunction + then result = cfn.(FunctionCall).getTarget().(IrqlRaisesAnnotatedFunction).getIrqlLevel() + else + if + cfn instanceof FunctionCall and + cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction + then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + else + if + exists(ControlFlowNode cfn2 | + cfn2 = cfn.getASuccessor() and + cfn2.(FunctionCall).getTarget() instanceof IrqlRequiresAnnotatedFunction + ) + then + result = + any(cfn.getASuccessor() + .(FunctionCall) + .getTarget() + .(IrqlRequiresAnnotatedFunction) + .getIrqlLevel() + ) + else + if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor()) + then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + else + if + exists(FunctionCall fc, ControlFlowNode cfn2 | + fc.getTarget() = cfn.getControlFlowScope() and + cfn2.getASuccessor() = fc + ) + then + result = + any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 | + cfn2.getASuccessor().(FunctionCall).getTarget() = + cfn.getControlFlowScope() + )) + ) + else + if + cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and + getAllowableIrqlLevel(cfn.getControlFlowScope()) != -1 + then result = getAllowableIrqlLevel(cfn.getControlFlowScope()) + else result = 0 + // TODO: How to handle cases where the function is annotated _IRQL_MIN_, etc? + // May need to split into two libraries: "Actual" IRQL tracking and "annotation-based" IRQL tracking. + // Or maybe we keep the actual tracking for queries. +} + +/** + * Attempt to find the range of valid IRQL values when **entering** a given function. + */ +cached +int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { + if + irqlFunc instanceof IrqlRequiresAnnotatedFunction and + irqlFunc instanceof IrqlRequiresSameAnnotatedFunction + then result = irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() + else + if + irqlFunc instanceof IrqlMaxAnnotatedFunction and + irqlFunc instanceof IrqlMinAnnotatedFunction + then + result = + any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. irqlFunc + .(IrqlMaxAnnotatedFunction) + .getIrqlLevel()] + ) + else + if irqlFunc instanceof IrqlMaxAnnotatedFunction + then result = any([0 .. irqlFunc.(IrqlMaxAnnotatedFunction).getIrqlLevel()]) + else + if irqlFunc instanceof IrqlMinAnnotatedFunction + then result = any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. 15]) + else + if irqlFunc instanceof IrqlRequiresAnnotatedFunction + then result = irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() + else + // Below indicates we cannot determine the correct IRQL + result = -1 +} + +/** A direct call to a function that lowers the IRQL. */ +class KeLowerIrqlCall extends FunctionCall { + KeLowerIrqlCall() { this.getTarget().getName().matches(any(["KeLowerIrql", "KfLowerIrql"])) } + + /** + * A heuristic evaluation of the IRQL that the system is lowering to. This is defined as + * "the IRQL before the most recent KeRaiseIrql call". + */ + int getIrqlLevel() { + result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + } + + int getIrqlLevelAccurate() { + result = -1 //TODO + } + + KeRaiseIrqlCall getMostRecentRaise() { + result = + any(KeRaiseIrqlCall sgic | + this.getAPredecessor*() = sgic and + not exists(KeRaiseIrqlCall kric2 | kric2 != sgic and kric2.getAPredecessor*() = sgic) + ) } } diff --git a/src/drivers/libraries/SAL.qll b/src/drivers/libraries/SAL.qll index 64442c78..8c0d704c 100644 --- a/src/drivers/libraries/SAL.qll +++ b/src/drivers/libraries/SAL.qll @@ -49,6 +49,11 @@ class SALAnnotation extends MacroInvocation { not result instanceof Type // exclude typedefs } + Declaration getTypedefDeclarations() { + annotatesAt(this, result.getADeclarationEntry(), _, _) and + result instanceof Type // include + } + /** Gets the `DeclarationEntry` annotated by `this`. */ DeclarationEntry getDeclarationEntry() { annotatesAt(this, result, _, _) and diff --git a/src/drivers/wdm/libraries/WdmDrivers.qll b/src/drivers/wdm/libraries/WdmDrivers.qll index 173bb19c..3dbd57f6 100644 --- a/src/drivers/wdm/libraries/WdmDrivers.qll +++ b/src/drivers/wdm/libraries/WdmDrivers.qll @@ -48,6 +48,8 @@ class WdmCallbackRoutineTypedef extends TypedefType { or this.getName().matches("DRIVER_INITIALIZE") or + this.getName().matches("DRIVER_CANCEL") + or this.getName().matches("IO_COMPLETION_ROUTINE") or this.getName().matches("KSERVICE_ROUTINE") @@ -93,6 +95,11 @@ class WdmDriverEntry extends WdmCallbackRoutine { WdmDriverEntry() { callbackType.getName().matches("DRIVER_INITIALIZE") } } +/** A WDM DriverCancel callback routine. */ +class WdmDriverCancel extends WdmCallbackRoutine { + WdmDriverCancel() { callbackType.getName().matches("DRIVER_CANCEL")} +} + /** * WDM dispatch routine class. * We hold a routine to be a dispatch routine if there is From 564d095a856d34a82d25fe14755646b9db824593 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:26:53 -0700 Subject: [PATCH 07/54] Some cleanup and minor fixes to entry IRQL evaluation. --- src/drivers/libraries/Irql.qll | 209 ++++++++++----------------------- 1 file changed, 63 insertions(+), 146 deletions(-) diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 4daef9e3..e9a7e9e4 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -109,24 +109,28 @@ class IrqlSameAnnotation extends SALAnnotation { string getIrqlMacroName() { result = irqlAnnotationName } } +/** An "_IRQL_requires_max" annotation. */ class IrqlMaxAnnotation extends IrqlAnnotation { IrqlMaxAnnotation() { this.getMacroName().matches("_IRQL_requires_max_") } } +/** An "_IRQL_raises_" annotation. */ class IrqlRaisesAnnotation extends IrqlAnnotation { IrqlRaisesAnnotation() { this.getMacroName().matches("_IRQL_raises_") } } +/** An "IRQL_requires_min" annotation. */ class IrqlMinAnnotation extends IrqlAnnotation { IrqlMinAnnotation() { this.getMacroName().matches("_IRQL_requires_min_") } } +/** An "_IRQL_requires_" annotation. */ class IrqlRequiresAnnotation extends IrqlAnnotation { IrqlRequiresAnnotation() { this.getMacroName().matches("_IRQL_requires_") } } /** - * Represents a SAL annotation indicating that the parameter in + * A SAL annotation indicating that the parameter in * question is used as part of adjusting the IRQL. */ class IrqlParameterAnnotation extends SALAnnotation { @@ -142,7 +146,7 @@ class IrqlParameterAnnotation extends SALAnnotation { } /** - * Represents a SAL annotation indicating that the parameter in + * A SAL annotation indicating that the parameter in * question contains an IRQL value that the system will be set to. */ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { @@ -150,19 +154,19 @@ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { } /** - * Represents a SAL annotation indicating that the parameter in + * A SAL annotation indicating that the parameter in * question will have the current IRQL saved to it. */ class IrqlSaveAnnotation extends IrqlParameterAnnotation { IrqlSaveAnnotation() { this.getMacroName().matches(["_IRQL_saves_"]) } } -/** Represents a parameter that is annotated with "\_IRQL\_restores\_". */ +/** A parameter that is annotated with "\_IRQL\_restores\_". */ class IrqlRestoreParameter extends Parameter { IrqlRestoreParameter() { exists(IrqlRestoreAnnotation ira | ira.getDeclaration() = this) } } -/** Represents a parameter that is annotated with "\_IRQL\_saves\_". */ +/** A parameter that is annotated with "\_IRQL\_saves\_". */ class IrqlSaveParameter extends Parameter { IrqlSaveParameter() { exists(IrqlSaveAnnotation isa | isa.getDeclaration() = this) } } @@ -177,7 +181,7 @@ class IrqlAnnotatedTypedef extends TypedefType { } /** - * Represents a function that is annotated in such a way that + * A function that is annotated in such a way that * either its entry or exit IRQL is restricted, either by having a min/max value, * a required value, or by raising the IRQL to a known value. */ @@ -202,10 +206,10 @@ class IrqlRestrictsFunction extends Function { string getFuncIrqlAnnotation() { result = irqlAnnotation.getIrqlMacroName() } } -/** Represents a function that changes the IRQL. */ +/** A function that changes the IRQL. */ abstract class IrqlChangesFunction extends Function { } -/** Represents a function that is explicitly annotated to not change the IRQL. */ +/** A function that is explicitly annotated to not change the IRQL. */ class IrqlRequiresSameAnnotatedFunction extends Function { IrqlSameAnnotation irqlAnnotation; @@ -217,24 +221,28 @@ class IrqlRequiresSameAnnotatedFunction extends Function { } } +/** A function that is annotated to run at a specific IRQL. */ class IrqlRequiresAnnotatedFunction extends IrqlRestrictsFunction { IrqlRequiresAnnotatedFunction() { irqlAnnotation instanceof IrqlRequiresAnnotation } int getIrqlLevel() { result = irqlAnnotation.(IrqlRequiresAnnotation).getIrqlLevel() } } +/** A function that is annotated to enter at or below a given IRQL. */ class IrqlMaxAnnotatedFunction extends IrqlRestrictsFunction { IrqlMaxAnnotatedFunction() { irqlAnnotation instanceof IrqlMaxAnnotation } int getIrqlLevel() { result = irqlAnnotation.(IrqlMaxAnnotation).getIrqlLevel() } } +/** A function that is annotated to enter at or above a given IRQL. */ class IrqlMinAnnotatedFunction extends IrqlRestrictsFunction { IrqlMinAnnotatedFunction() { irqlAnnotation instanceof IrqlMinAnnotation } int getIrqlLevel() { result = irqlAnnotation.(IrqlMinAnnotation).getIrqlLevel() } } +/** A function that is annotated to raise the IRQL to a given value. */ class IrqlRaisesAnnotatedFunction extends IrqlRestrictsFunction, IrqlChangesFunction { IrqlRaisesAnnotatedFunction() { irqlAnnotation instanceof IrqlRaisesAnnotation } @@ -320,6 +328,32 @@ class KeRaiseIrqlCall extends FunctionCall { } } +/** A direct call to a function that lowers the IRQL. */ +class KeLowerIrqlCall extends FunctionCall { + KeLowerIrqlCall() { this.getTarget().getName().matches(any(["KeLowerIrql", "KfLowerIrql"])) } + + /** + * A heuristic evaluation of the IRQL that the system is lowering to. This is defined as + * "the IRQL before the most recent KeRaiseIrql call". + */ + int getIrqlLevel() { + result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + } + + /** + * Get the most recent call before this call that explicitly raised the IRQL. + * + * TODO: Should be updated to account for functions that are annotated _IRQL_raises_. + */ + KeRaiseIrqlCall getMostRecentRaise() { + result = + any(KeRaiseIrqlCall sgic | + this.getAPredecessor*() = sgic and + not exists(KeRaiseIrqlCall kric2 | kric2 != sgic and kric2.getAPredecessor*() = sgic) + ) + } +} + /** A call to a function that restores the IRQL from a specified state. */ class SavesGlobalIrqlCall extends FunctionCall { SavesGlobalIrqlCall() { this.getTarget() instanceof IrqlSavesGlobalAnnotatedFunction } @@ -349,10 +383,15 @@ class RestoresGlobalIrqlCall extends FunctionCall { ) } - /** Holds if a given call to an _IRQL_Saves_Global_ annotated function is using the same IRQL location as this. */ - predicate matchingSaveCall(SavesGlobalIrqlCall sgic) { + /** + * Holds if a given call to an _IRQL_saves_global_ annotated function is using the same IRQL location as this. + * + * We use a lazy evaluation here of checking that the literal text passed in as an argument to this call + * matches the text that was passed in to the saving call. + */ + private predicate matchingSaveCall(SavesGlobalIrqlCall sgic) { // Attempting to match all expr children leads to an explosion in runtime, so for now just compare - // first child of each argument. This covers the common &variable case. + // the expr itself and the first child of each argument. This covers the common &variable case. exists(int i, int j | i = this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlParameterSlot() and j = sgic.getTarget().(IrqlSavesGlobalAnnotatedFunction).getIrqlParameterSlot() and @@ -366,7 +405,9 @@ class RestoresGlobalIrqlCall extends FunctionCall { .matches(sgic.getArgument(j).getChild(0).toString()) ) or - not exists(Expr child | child = this.getArgument(i).getAChild()) + not exists(Expr child | + child = this.getArgument(i).getAChild() or child = sgic.getArgument(j).getAChild() + ) ) ) and this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlKind() = @@ -388,9 +429,7 @@ class RestoresGlobalIrqlCall extends FunctionCall { * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. * - If there is nothing else, then IRQL is 0. * TODO: _IRQL_limited_to_(DISPATCH_LEVEL); - * BUG: At Windows-driver-samples\network\ndis\filter\device.c:263, FILTER_ACQUIRE_LOCK does a static check of "if second variable - * at this macro is false, then use raisetodpc instead of atdpc." How can we track these guards? Maybe we can import guard conditions and - * use a limited analysis? + * TODO: Functions not explicitly annotated at the function level, but which have _IRQL_saves_ or _IRQL_restores_ parameter annotations. */ cached int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { @@ -454,13 +493,11 @@ int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { } /** - * Attempt to find the range of valid IRQL values when **entering** a given function. + * Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function. */ cached int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { - if - irqlFunc instanceof IrqlRequiresAnnotatedFunction and - irqlFunc instanceof IrqlRequiresSameAnnotatedFunction + if irqlFunc instanceof IrqlRequiresAnnotatedFunction then result = irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() else if @@ -477,132 +514,12 @@ int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { then result = any([0 .. irqlFunc.(IrqlMaxAnnotatedFunction).getIrqlLevel()]) else if irqlFunc instanceof IrqlMinAnnotatedFunction - then result = any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. 15]) + then + result = + any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. any(IrqlMacro im) + .getGlobalMaxIrqlLevel()] + ) else - if irqlFunc instanceof IrqlRequiresAnnotatedFunction - then result = irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() - else - // Below indicates we cannot determine the correct IRQL - result = -1 + // No known restriction + result = any([0 .. any(IrqlMacro im).getGlobalMaxIrqlLevel()]) } - -/** A direct call to a function that lowers the IRQL. */ -class KeLowerIrqlCall extends FunctionCall { - KeLowerIrqlCall() { this.getTarget().getName().matches(any(["KeLowerIrql", "KfLowerIrql"])) } - - /** - * A heuristic evaluation of the IRQL that the system is lowering to. This is defined as - * "the IRQL before the most recent KeRaiseIrql call". - */ - int getIrqlLevel() { - result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) - } - - int getIrqlLevelAccurate() { - result = -1 //TODO - } - - KeRaiseIrqlCall getMostRecentRaise() { - result = - any(KeRaiseIrqlCall sgic | - this.getAPredecessor*() = sgic and - not exists(KeRaiseIrqlCall kric2 | kric2 != sgic and kric2.getAPredecessor*() = sgic) - ) - } -} - -class IrqlLiteral extends Literal { - IrqlLiteral() { - this.getValueText() - .matches(any([ - "PASSIVE_LEVEL", "LOW_LEVEL", "APC_LEVEL", "DISPATCH_LEVEL", "CMCI_LEVEL", - "CLOCK_LEVEL", "IPI_LEVEL", "DRS_LEVEL", "POWER_LEVEL", "HIGH_LEVEL" - ] - )) or - this.getValueText().toInt() = any([0 .. 31]) - } - - string getRealValue() { result = this.getValue() } -} -// TODO: Add support for KeRaiseIrql/KeLowerIrql and variants -/* - * _IRQL_requires_max_(HIGH_LEVEL) - * _IRQL_raises_(NewIrql) - * _IRQL_saves_ - * NTKERNELAPI - * KIRQL - * KfRaiseIrql ( - * _In_ KIRQL NewIrql - * ); - */ - -// The problem here is that it's a dynamic value based on the NewIrql being passed in. Do we have a way to marry an annotation -// and a parameter? We can match on name, and then store the index in question... and then in logic we would need to check -// the argument passed in at parameter [x]. The value of x itself would depend on data-flow analysis, blech. Maybe that's -// too much for a V1. Still, if x is a literal, or a constant that can we coerce into an int, things get easier. -// Let me review the actual check(s) that CA performs and see what parity looks like. -// Comments from experimenting a bit: -// CA yells at you if you directly call KeRaiseIrql, etc. without an annotation. -// CA does _not_ yell at you if you call a function that directly calls KeRaiseIrql, etc. without an annotation. -// CA _does_ yell at you if you raise the IRQL in a conditional before calling a function which doesn't allow itself to be raised that high. -// -/* - * The following code gets the following warning: - * - * _IRQL_raises_(irqlToSet) - * NTSTATUS - * Defect_SetIRQL2(KIRQL* outIrql, KIRQL irqlToSet) - * { - * KeRaiseIrql(irqlToSet, outIrql); - * return STATUS_SUCCESS; - * } - * - * const KIRQL myIrqlLiteral = DISPATCH_LEVEL; - * - * NTSTATUS - * Defect_IRQL2(int doIrql)//, KIRQL irqlToSet) - * { - * KIRQL outIrql; - * if (doIrql) { - * Defect_SetIRQL2(&outIrql, myIrqlLiteral); - * } - * Defect_MaxIRQL(); - * return STATUS_SUCCESS; - * } - * - * Severity Code Description Project File Line Suppression State - * Warning C28167 The function 'Defect_IRQL2' changes the IRQL and does not restore the IRQL before it exits. It should be annotated to reflect the change or the IRQL should be restored. IRQL was last set at line 1576. defect_toastmon C:\Users\natede\source\repos\Windows-driver-samples\tools\dv\samples\DV-FailDriver-WDM\defect_toastmon.c 1572 - * - * In other words, it does not track constants. - * - * However, if I pass DISPATCH_LEVEL in directly, that *does* flag the "Irql too high" error: - * - * Severity Code Description Project File Line Suppression State - * Warning C28121 The function 'Defect_MaxIRQL' is not permitted to be called at the current IRQ level. The current level is too high: IRQL was last set to 2 at line 1576. The level might have been inferred from the function signature. defect_toastmon C:\Users\natede\source\repos\Windows-driver-samples\tools\dv\samples\DV-FailDriver-WDM\defect_toastmon.c 1578 - * - * So. We _do_ need to support literals. - * Also, CA yells at me if I use _IRQL_raises_(outIrql), so it is tracking which parameter becomes the IRQL... dang. - * - * Maybe a better way to handle all this is to do analyses at call-time? - */ - -/* - * More noodling. How do I track the IRQL at a given statement? - * - * I guess we could evaluate it at every statement, with a default of 0. Like a recursive function with logic of - * - * if this statement cannot change irql: - * irql = any(irql of previous statements) - * - * if this statement CAN change irql, either by being a function call to a function that raises IRQL or one that lowers, then we need to do proper analysis. - * if KeRaise: irql = (whatever the passed in value is) - * if KeLower: irql = any(data flow for the passed in variable) - * if calling a function annotated to raise: irql = (whatever the annotation is) - * if calling a function guaranteed to not change irql: irql = irql - * - * if first statement in a function: irql = any([whatever the irql value at the call site(s) is]) - * can also use annotations...? - * - * Wait, hold on. I'm getting my wires crossed. What I'm describing is "actual" irql flow. What CA does is look for contradictions in annotations, right? - */ - From 6861e39334ba5a201c0fbf7c07ab9f7d92d3aeca Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 3 Oct 2023 20:19:46 -0700 Subject: [PATCH 08/54] Replace old Irql high/low checks with new version and update library. Still needs cleanup. --- .../general/queries/IrqlTooLow/IrqlTooLow2.ql | 46 -- .../experimental/IrqTooHigh/IrqTooHigh.qhelp | 0 .../IrqTooHigh/IrqTooHigh.ql} | 21 +- .../experimental/IrqTooHigh/IrqTooHigh.sarif | 411 ++++++++++++++++++ .../experimental/IrqTooHigh/driver_snippet.c | 0 .../experimental/IrqTooLow/IrqTooLow.qhelp | 0 .../experimental/IrqTooLow/IrqTooLow.ql | 36 ++ .../experimental/IrqTooLow/IrqTooLow.sarif | 331 ++++++++++++++ .../experimental/IrqTooLow/driver_snippet.c | 0 src/drivers/libraries/Irql.qll | 245 ++++++++--- .../experimental/IrqTooHigh/IrqTooHigh.ql | 61 --- .../experimental/IrqTooHigh/IrqTooHigh.sarif | 169 ------- .../experimental/IrqTooLow/IrqTooLow.ql | 26 -- .../experimental/IrqTooLow/IrqTooLow.sarif | 107 ----- 14 files changed, 964 insertions(+), 489 deletions(-) delete mode 100644 src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql rename src/drivers/{wdm => general}/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp (100%) rename src/drivers/general/queries/{IrqlTooLow/IrqlTooHigh.ql => experimental/IrqTooHigh/IrqTooHigh.ql} (52%) create mode 100644 src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif rename src/drivers/{wdm => general}/queries/experimental/IrqTooHigh/driver_snippet.c (100%) rename src/drivers/{wdm => general}/queries/experimental/IrqTooLow/IrqTooLow.qhelp (100%) create mode 100644 src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql create mode 100644 src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif rename src/drivers/{wdm => general}/queries/experimental/IrqTooLow/driver_snippet.c (100%) delete mode 100644 src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.ql delete mode 100644 src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.sarif delete mode 100644 src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.ql delete mode 100644 src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.sarif diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql deleted file mode 100644 index 5e7e19be..00000000 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow2.ql +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * @id cpp/drivers/irql-too-low - * @name IRQL too low - * @description A function annotated with IRQL requirements was called at an IRQL too low for the requirements. - * @platform Desktop - * @security.severity Low - * @feature.area Multiple - * @impact Insecure Coding Practice - * @repro.text A function annotated with IRQL requirements was called at an IRQL too low for the requirements. - * @owner.email sdat@microsoft.com - * @kind problem - * @problem.severity warning - * @precision medium - * @tags correctness - * wddst - * @query-version v1 - */ - -import cpp -import drivers.libraries.Irql -import semmle.code.cpp.controlflow.Guards - -//TODO: What do we do with cases like FILTER_LOCK, where there is a guard around using a call? - -// Take it from the top... -from FunctionCall fc, IrqlMinAnnotatedFunction imaf -where - fc.getTarget() = imaf and - imaf.getIrqlLevel() > max(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) - and not exists(GuardCondition c | c.controls(fc.getBasicBlock(), false)) -select fc, - "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", - fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel(), - fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) -/* - * fc.getTarget() instanceof IrqlMinAnnotatedFunction and - * fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel() > - * max(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) - * select fc, - * "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", - * fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel(), - * fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) - */ - diff --git a/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp b/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp similarity index 100% rename from src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp rename to src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql b/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.ql similarity index 52% rename from src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql rename to src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.ql index 74f1bbb7..a152242c 100644 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.ql @@ -2,7 +2,7 @@ // Licensed under the MIT license. /** * @id cpp/drivers/irql-too-high - * @name IRQL too low + * @name IRQL too low (C28120) * @description A function annotated with IRQL requirements was called at an IRQL too high for the requirements. * @platform Desktop * @security.severity Low @@ -21,13 +21,16 @@ import cpp import drivers.libraries.Irql -// Take it from the top... -from FunctionCall fc +from FunctionCall fc, IrqlRestrictsFunction imaf, ControlFlowNode e, int irqlRequirement where - fc.getTarget() instanceof IrqlMaxAnnotatedFunction and - fc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < - min(getPotentialExitIrqlAtCfn(any(fc.getAPredecessor()))) + fc.getTarget() = imaf and + e = fc.getAPredecessor() and + ( + imaf.(IrqlMaxAnnotatedFunction).getIrqlLevel() = irqlRequirement + or + imaf.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement + ) and + irqlRequirement < min(getPotentialExitIrqlAtCfn(e)) select fc, - "IRQL potentially too low high this call ($@). Maximum irql level of this call: $@, Irql level at preceding node: $@", - fc, fc.getTarget().toString(), fc, "" + fc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel(), - fc, "" + getPotentialExitIrqlAtCfn(any(fc.getAPredecessor())) + "IRQL potentially too high at this call ($@). Maximum irql level of this call: $@, Irql level at preceding node: $@", + fc, fc.getTarget().toString(), fc, "" + irqlRequirement, e, "" + min(getPotentialExitIrqlAtCfn(e)) diff --git a/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif b/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif new file mode 100644 index 00000000..9a8ca16f --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif @@ -0,0 +1,411 @@ +{ + "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", + "version" : "2.1.0", + "runs" : [ { + "tool" : { + "driver" : { + "name" : "CodeQL", + "organization" : "GitHub", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], + "rules" : [ { + "id" : "cpp/drivers/irql-too-high", + "name" : "cpp/drivers/irql-too-high", + "shortDescription" : { + "text" : "IRQL too low (C28120)" + }, + "fullDescription" : { + "text" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "properties" : { + "tags" : [ "correctness", "wddst" ], + "description" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.", + "feature.area" : "Multiple", + "id" : "cpp/drivers/irql-too-high", + "impact" : "Insecure Coding Practice", + "kind" : "problem", + "name" : "IRQL too low (C28120)", + "owner.email" : "sdat@microsoft.com", + "platform" : "Desktop", + "precision" : "medium", + "problem.severity" : "warning", + "query-version" : "v1", + "repro.text" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.", + "security.severity" : "Low" + } + } ] + }, + "extensions" : [ { + "name" : "microsoft/windows-drivers", + "semanticVersion" : "0.2.0+564d095a856d34a82d25fe14755646b9db824593", + "locations" : [ { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", + "description" : { + "text" : "The QL pack root directory." + } + }, { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", + "description" : { + "text" : "The QL pack definition file." + } + } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], + "artifacts" : [ { + "location" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } ], + "results" : [ { + "ruleId" : "cpp/drivers/irql-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-too-high", + "index" : 0 + }, + "message" : { + "text" : "IRQL potentially too high at this call ([TestInner2](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "startColumn" : 12, + "endColumn" : 22 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "1defbc9e59f0310b:1", + "primaryLocationStartColumnFingerprint" : "7" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "TestInner2" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "1" + } + }, { + "id" : 3, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "startColumn" : 5, + "endColumn" : 25 + } + }, + "message" : { + "text" : "2" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-too-high", + "index" : 0 + }, + "message" : { + "text" : "IRQL potentially too high at this call ([TestInner4](1)). Maximum irql level of this call: [0](2), Irql level at preceding node: [2](3)" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 36, + "startColumn" : 14, + "endColumn" : 24 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "7ae2af586e0dd70a:1", + "primaryLocationStartColumnFingerprint" : "9" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 36, + "startColumn" : 14, + "endColumn" : 24 + } + }, + "message" : { + "text" : "TestInner4" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 36, + "startColumn" : 14, + "endColumn" : 24 + } + }, + "message" : { + "text" : "0" + } + }, { + "id" : 3, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 36, + "startColumn" : 5, + "endColumn" : 27 + } + }, + "message" : { + "text" : "2" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-too-high", + "index" : 0 + }, + "message" : { + "text" : "IRQL potentially too high at this call ([IoGetInitialStack](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 366, + "startColumn" : 5, + "endColumn" : 22 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "48e9dbeaff18e9e7:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 366, + "startColumn" : 5, + "endColumn" : 22 + } + }, + "message" : { + "text" : "IoGetInitialStack" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 366, + "startColumn" : 5, + "endColumn" : 22 + } + }, + "message" : { + "text" : "1" + } + }, { + "id" : 3, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + }, + "region" : { + "startLine" : 366, + "startColumn" : 5, + "endColumn" : 25 + } + }, + "message" : { + "text" : "2" + } + } ] + } ], + "columnKind" : "utf16CodeUnits", + "properties" : { + "semmle.formatSpecifier" : "sarifv2.1.0" + } + } ] +} \ No newline at end of file diff --git a/src/drivers/wdm/queries/experimental/IrqTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqTooHigh/driver_snippet.c similarity index 100% rename from src/drivers/wdm/queries/experimental/IrqTooHigh/driver_snippet.c rename to src/drivers/general/queries/experimental/IrqTooHigh/driver_snippet.c diff --git a/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.qhelp b/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.qhelp similarity index 100% rename from src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.qhelp rename to src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.qhelp diff --git a/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql b/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql new file mode 100644 index 00000000..e01e533e --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-too-low + * @name IRQL too low (C28121) + * @description A function annotated with IRQL requirements was called at an IRQL too low for the requirements. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Insecure Coding Practice + * @repro.text A function annotated with IRQL requirements was called at an IRQL too low for the requirements. + * @owner.email sdat@microsoft.com + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @query-version v1 + */ + +import cpp +import drivers.libraries.Irql + +from FunctionCall fc, IrqlRestrictsFunction imaf, ControlFlowNode e, int irqlRequirement +where + fc.getTarget() = imaf and + e = fc.getAPredecessor() and + ( + imaf.(IrqlMinAnnotatedFunction).getIrqlLevel() = irqlRequirement + or + imaf.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement + ) and + irqlRequirement > max(getPotentialExitIrqlAtCfn(e)) +select fc, + "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", + fc, fc.getTarget().toString(), fc, "" + irqlRequirement, e, "" + max(getPotentialExitIrqlAtCfn(e)) diff --git a/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif b/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif new file mode 100644 index 00000000..026d716e --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif @@ -0,0 +1,331 @@ +{ + "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", + "version" : "2.1.0", + "runs" : [ { + "tool" : { + "driver" : { + "name" : "CodeQL", + "organization" : "GitHub", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], + "rules" : [ { + "id" : "cpp/drivers/irql-too-low", + "name" : "cpp/drivers/irql-too-low", + "shortDescription" : { + "text" : "IRQL too low (C28121)" + }, + "fullDescription" : { + "text" : "A function annotated with IRQL requirements was called at an IRQL too low for the requirements." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "properties" : { + "tags" : [ "correctness", "wddst" ], + "description" : "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.", + "feature.area" : "Multiple", + "id" : "cpp/drivers/irql-too-low", + "impact" : "Insecure Coding Practice", + "kind" : "problem", + "name" : "IRQL too low (C28121)", + "owner.email" : "sdat@microsoft.com", + "platform" : "Desktop", + "precision" : "medium", + "problem.severity" : "warning", + "query-version" : "v1", + "repro.text" : "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.", + "security.severity" : "Low" + } + } ] + }, + "extensions" : [ { + "name" : "microsoft/windows-drivers", + "semanticVersion" : "0.2.0+564d095a856d34a82d25fe14755646b9db824593", + "locations" : [ { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", + "description" : { + "text" : "The QL pack root directory." + } + }, { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", + "description" : { + "text" : "The QL pack definition file." + } + } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], + "artifacts" : [ { + "location" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } ], + "results" : [ { + "ruleId" : "cpp/drivers/irql-too-low", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-too-low", + "index" : 0 + }, + "message" : { + "text" : "IRQL potentially too low at this call ([TestInner2](1)). Minimum irql level of this call: [1](2), Irql level at preceding node: [0](3)" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 41, + "startColumn" : 12, + "endColumn" : 22 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "1defbc9e59f0310b:1", + "primaryLocationStartColumnFingerprint" : "7" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 41, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "TestInner2" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 41, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "1" + } + }, { + "id" : 3, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 41, + "startColumn" : 5, + "endColumn" : 25 + } + }, + "message" : { + "text" : "0" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-too-low", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-too-low", + "index" : 0 + }, + "message" : { + "text" : "IRQL potentially too low at this call ([TestInner3](1)). Minimum irql level of this call: [2](2), Irql level at preceding node: [0](3)" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 21, + "startColumn" : 12, + "endColumn" : 22 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "bf32240018f4d9fb:1", + "primaryLocationStartColumnFingerprint" : "7" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 21, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "TestInner3" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 21, + "startColumn" : 12, + "endColumn" : 22 + } + }, + "message" : { + "text" : "2" + } + }, { + "id" : 3, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 21, + "startColumn" : 5, + "endColumn" : 25 + } + }, + "message" : { + "text" : "0" + } + } ] + } ], + "columnKind" : "utf16CodeUnits", + "properties" : { + "semmle.formatSpecifier" : "sarifv2.1.0" + } + } ] +} \ No newline at end of file diff --git a/src/drivers/wdm/queries/experimental/IrqTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqTooLow/driver_snippet.c similarity index 100% rename from src/drivers/wdm/queries/experimental/IrqTooLow/driver_snippet.c rename to src/drivers/general/queries/experimental/IrqTooLow/driver_snippet.c diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index e9a7e9e4..b2d9dc01 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -69,7 +69,10 @@ class IrqlAnnotation extends SALAnnotation { IrqlAnnotation() { // Needs to include other function and parameter annotations too this.getMacroName() - .matches(["_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_"]) and + .matches([ + "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", + "_IRQL_saves_" + ]) and irqlAnnotationName = this.getMacroName() and irqlMacroInvocation.getParentInvocation() = this and irqlLevel = irqlMacroInvocation.getMacro().getHead() @@ -154,10 +157,11 @@ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { } /** - * A SAL annotation indicating that the parameter in - * question will have the current IRQL saved to it. + * A SAL annotation indicating that can be used in two ways: + * - If applied to a function, the function returns the previous IRQL. + * - If applied to a parameter, the function saves the IRQL to the parameter. */ -class IrqlSaveAnnotation extends IrqlParameterAnnotation { +class IrqlSaveAnnotation extends IrqlAnnotation { IrqlSaveAnnotation() { this.getMacroName().matches(["_IRQL_saves_"]) } } @@ -289,25 +293,99 @@ class IrqlRestoresGlobalAnnotatedFunction extends IrqlChangesFunction { int getIrqlParameterSlot() { result = irqlParamIndex } } -//Evaluates to true if a FunctionCall at some points calls Irql annotated Function in its call hierarchy -predicate containsIrqlCall(FunctionCall fc) { - exists(Function fc2 | - fc.getTarget().calls*(fc2) and - fc2 instanceof IrqlRestrictsFunction - ) +abstract class IrqlSavesFunction extends Function { } + +/** A function that has a parameter annotated _IRQL_saves_. */ +class IrqlSavesToParameterFunction extends IrqlSavesFunction { + IrqlSaveParameter saveParameter; + int irqlParamIndex; + + IrqlSavesToParameterFunction() { this.getParameter(irqlParamIndex) = saveParameter } + + int getIrqlParameterSlot() { result = irqlParamIndex } } -//Returns functions in the ControlFlow path that are instance of IrqlRestrictsFunction -IrqlRestrictsFunction getActualIrqlFunc(FunctionCall fc) { - exists(Function fc2 | - fc.getTarget().calls*(fc2) and - fc2 instanceof IrqlRestrictsFunction and - result = fc2 - ) +/** A function that saves the IRQL as a return value. */ +class IrqlSavesViaReturnFunction extends IrqlSavesFunction { + IrqlSaveAnnotation irqlAnnotation; + + IrqlSavesViaReturnFunction() { + exists(FunctionDeclarationEntry fde | + fde = this.getADeclarationEntry() and + irqlAnnotation.getDeclarationEntry() = fde + ) + } } -class CallsToIrqlAnnotatedFunction extends FunctionCall { - CallsToIrqlAnnotatedFunction() { containsIrqlCall(this) } +/** A function that has a parameter annotated _IRQL_restores_. */ +class IrqlRestoreAnnotatedFunction extends Function { + IrqlRestoreParameter restoreParameter; + int irqlParamIndex; + + IrqlRestoreAnnotatedFunction() { this.getParameter(irqlParamIndex) = restoreParameter } + + int getIrqlParameterSlot() { result = irqlParamIndex } +} + +/** A call to a function that has a parameter annotated _IRQL_restores_. */ +class IrqlRestoreCall extends FunctionCall { + IrqlRestoreCall() { this.getTarget() instanceof IrqlRestoreAnnotatedFunction } + + /** + * A heuristic evaluation of the IRQL that the system is changing to. This is defined as + * "the IRQL before the corresponding save global call." + */ + int getIrqlLevel() { + result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + } + + /** Returns the matching call to a function that saved the IRQL. */ + IrqlSaveCall getMostRecentRaise() { + result = + any(IrqlSaveCall sgic | + this.getAPredecessor*() = sgic and + matchingSaveCall(sgic) and + not exists(SavesGlobalIrqlCall sgic2 | + sgic2 != sgic and sgic2.getAPredecessor*() = sgic and matchingSaveCall(sgic2) + ) + ) + } + + /** + * Holds if a given call to an _IRQL_saves_global_ annotated function is using the same IRQL location as this. + */ + private predicate matchingSaveCall(IrqlSaveCall sgic) { + // Attempting to match all expr children leads to an explosion in runtime, so for now just compare + // the expr itself and the first child of each argument. This covers the common &variable case. + exists(int i, int j | + i = this.getTarget().(IrqlRestoreAnnotatedFunction).getIrqlParameterSlot() and + j = sgic.getTarget().(IrqlSavesToParameterFunction).getIrqlParameterSlot() and + exprsMatchText(this.getArgument(i), sgic.getArgument(j)) + ) + or + exists(int i | + i = this.getTarget().(IrqlRestoreAnnotatedFunction).getIrqlParameterSlot() and + sgic.getTarget() instanceof IrqlSavesViaReturnFunction and + exprsMatchText(this.getArgument(i), sgic.getSavedValue()) + ) and + this.getControlFlowScope() = sgic.getControlFlowScope() + } +} + +/** A call to a function that has a parameter annotated _IRQL_saves_. */ +class IrqlSaveCall extends FunctionCall { + IrqlSaveCall() { this.getTarget() instanceof IrqlSavesFunction } + + Expr getSavedValue() { + result = + any(Expr e | + exists(AssignExpr ae | + ae.getLValue() = e and + ae.getRValue() = this and + this.getTarget() instanceof IrqlSavesViaReturnFunction + ) + ) + } } /** A call to a KeRaiseIRQL API that directly raises the IRQL. */ @@ -364,7 +442,7 @@ class RestoresGlobalIrqlCall extends FunctionCall { RestoresGlobalIrqlCall() { this.getTarget() instanceof IrqlRestoresGlobalAnnotatedFunction } /** - * A heuristic evaluation of the IRQL that the system is lowering to. This is defined as + * A heuristic evaluation of the IRQL that the system is changing to. This is defined as * "the IRQL before the corresponding save global call." */ int getIrqlLevel() { @@ -385,9 +463,6 @@ class RestoresGlobalIrqlCall extends FunctionCall { /** * Holds if a given call to an _IRQL_saves_global_ annotated function is using the same IRQL location as this. - * - * We use a lazy evaluation here of checking that the literal text passed in as an argument to this call - * matches the text that was passed in to the saving call. */ private predicate matchingSaveCall(SavesGlobalIrqlCall sgic) { // Attempting to match all expr children leads to an explosion in runtime, so for now just compare @@ -395,26 +470,32 @@ class RestoresGlobalIrqlCall extends FunctionCall { exists(int i, int j | i = this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlParameterSlot() and j = sgic.getTarget().(IrqlSavesGlobalAnnotatedFunction).getIrqlParameterSlot() and - this.getArgument(i).toString().matches(sgic.getArgument(j).toString()) and - ( - exists(Expr child | - child = this.getArgument(i).getAChild() and - this.getArgument(i) - .getChild(0) - .toString() - .matches(sgic.getArgument(j).getChild(0).toString()) - ) - or - not exists(Expr child | - child = this.getArgument(i).getAChild() or child = sgic.getArgument(j).getAChild() - ) - ) + exprsMatchText(this.getArgument(i), sgic.getArgument(j)) ) and this.getTarget().(IrqlRestoresGlobalAnnotatedFunction).getIrqlKind() = sgic.getTarget().(IrqlSavesGlobalAnnotatedFunction).getIrqlKind() } } +/** + * A utility function to determine if two exprs are (textually) the same. + * Because checking all children of the expression causes an explosion in evaluation time, we just + * check the first child. + * + * This function is obviously _not_ a guarantee that two expressions refer to the same thing. + * Use this locally and with caution. + */ +pragma[inline] +private predicate exprsMatchText(Expr e1, Expr e2) { + e1.toString().matches(e2.toString()) and + exists(Expr child | + child = e1.getAChild() and + e1.getChild(0).toString().matches(e2.getChild(0).toString()) + ) + or + not exists(Expr child | child = e1.getAChild() or child = e2.getAChild()) +} + /** * Attempt to provide the IRQL **once this control flow node exits**, based on annotations and direct calls to raising/lowering functions. * This predicate functions as follows: @@ -424,6 +505,7 @@ class RestoresGlobalIrqlCall extends FunctionCall { * - If calling a function annotated to raise the IRQL, then it returns the annotated value (the target IRQL). * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN. * - If this node immediately precedes a call to a call annotated _Irql_Requires_, then the result is the annotated value for that call. + * - If this node is calling a function with no annotations, the result is the IRQL that function exits at. * - If there is a prior CFN in the CFG, the result is the result for that prior CFN. * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function. * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. @@ -442,56 +524,77 @@ int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { if cfn instanceof RestoresGlobalIrqlCall then result = cfn.(RestoresGlobalIrqlCall).getIrqlLevel() else - if - cfn instanceof FunctionCall and - cfn.(FunctionCall).getTarget() instanceof IrqlRaisesAnnotatedFunction - then result = cfn.(FunctionCall).getTarget().(IrqlRaisesAnnotatedFunction).getIrqlLevel() + if cfn instanceof IrqlRestoreCall + then result = cfn.(IrqlRestoreCall).getIrqlLevel() else if cfn instanceof FunctionCall and - cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction - then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + cfn.(FunctionCall).getTarget() instanceof IrqlRaisesAnnotatedFunction + then result = cfn.(FunctionCall).getTarget().(IrqlRaisesAnnotatedFunction).getIrqlLevel() else if - exists(ControlFlowNode cfn2 | - cfn2 = cfn.getASuccessor() and - cfn2.(FunctionCall).getTarget() instanceof IrqlRequiresAnnotatedFunction - ) - then - result = - any(cfn.getASuccessor() - .(FunctionCall) - .getTarget() - .(IrqlRequiresAnnotatedFunction) - .getIrqlLevel() - ) + cfn instanceof FunctionCall and + cfn.(FunctionCall).getTarget() instanceof IrqlRequiresSameAnnotatedFunction + then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) else - if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor()) - then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + if cfn instanceof FunctionCall + then + result = + any(getPotentialExitIrqlAtCfn(getExitPointsOfFunction(cfn.(FunctionCall) + .getTarget())) + ) else - if - exists(FunctionCall fc, ControlFlowNode cfn2 | - fc.getTarget() = cfn.getControlFlowScope() and - cfn2.getASuccessor() = fc +/* if + exists(ControlFlowNode cfn2 | + cfn2 = cfn.getASuccessor() and + cfn2.(FunctionCall).getTarget() instanceof IrqlRequiresAnnotatedFunction ) then result = - any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 | - cfn2.getASuccessor().(FunctionCall).getTarget() = - cfn.getControlFlowScope() - )) + any(cfn.getASuccessor() + .(FunctionCall) + .getTarget() + .(IrqlRequiresAnnotatedFunction) + .getIrqlLevel() ) - else - if - cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and - getAllowableIrqlLevel(cfn.getControlFlowScope()) != -1 - then result = getAllowableIrqlLevel(cfn.getControlFlowScope()) - else result = 0 + else*/ + if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor()) + then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + else + if + exists(FunctionCall fc, ControlFlowNode cfn2 | + fc.getTarget() = cfn.getControlFlowScope() and + cfn2.getASuccessor() = fc + ) + then + result = + any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 | + cfn2.getASuccessor().(FunctionCall).getTarget() = + cfn.getControlFlowScope() + )) + ) + else + if + cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and + getAllowableIrqlLevel(cfn.getControlFlowScope()) != -1 + then result = getAllowableIrqlLevel(cfn.getControlFlowScope()) + else result = 0 // TODO: How to handle cases where the function is annotated _IRQL_MIN_, etc? // May need to split into two libraries: "Actual" IRQL tracking and "annotation-based" IRQL tracking. // Or maybe we keep the actual tracking for queries. } +import semmle.code.cpp.controlflow.Dominance + +/** Utility function to get exit points of a function. */ +private ControlFlowNode getExitPointsOfFunction(Function f) { + result = + any(ControlFlowNode cfn | + cfn.getControlFlowScope() = f and + functionExit(cfn) + ) +} + /** * Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function. */ diff --git a/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.ql b/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.ql deleted file mode 100644 index 0f57ca5c..00000000 --- a/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.ql +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * @name IrqTooHigh - * @kind problem - * @description The function is not permitted to be called at the current IRQ level. The current level is too high. - * @problem.severity error - * @id cpp/portedqueries/irq-too-high - * @platform Desktop - * @repro.text The following line(s) potentially contains a function call that is supposed to be called at a higher Irql level. - * @feature.area Multiple - * @version 1.0 - */ - -import cpp -import drivers.libraries.Irql - -//Evaluates to true if KeLowerIrql call is made before a call to IrqlAnnotatedFunction is made -predicate preceedingKeLowerIrqlCall(CallsToIrqlAnnotatedFunction iafc) { - exists(FunctionCall fc2, Function fc3 | - iafc.getAPredecessor*() = fc2 and - ( - fc2.getTarget().getName() = "KeLowerIrql" - or - fc2.getTarget().calls*(fc3) and fc3.getName() = "KeLowerIrql" - ) - ) -} - -// Evaluates to true for FunctionCalls inside IrqlAnnotatedFunction where the call requires a lower Irql level -predicate irqlAnnotationViolatingCall(CallsToIrqlAnnotatedFunction ciaf) { - exists(IrqlAnnotatedFunction iaf, int current, int called | - ciaf.getEnclosingFunction() = iaf and - iaf.getIrqlLevel() = current and - getActualIrqlFunc(ciaf).getIrqlLevel() = called and - current > called - ) -} - -//Evaluates to true if there is a call from KeRaiseIrql to a IrqlAnnotatedFunction before any KeLowerIrql call in between. -predicate irqlNotLoweredCall(CallsToIrqlAnnotatedFunction fc) { - exists(FunctionCall kr, int called, int current | - kr.getASuccessor*() = fc and - getActualIrqlFunc(fc).getIrqlLevel() = called and - ( - kr.getTarget().getName().matches("KfRaiseIrql") and - kr.getArgument(0).getValue().toInt() = current - or - kr.getTarget().getName().matches("KeRaiseIrqlToDpcLevel") and - 2 = current - ) and - called < current and - not preceedingKeLowerIrqlCall(fc) - ) -} - -from CallsToIrqlAnnotatedFunction ciaf -where irqlNotLoweredCall(ciaf) or irqlAnnotationViolatingCall(ciaf) -select ciaf, - ciaf.getTarget().getName() + - " can not be called at the current Irql level. The current level is too high" diff --git a/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.sarif b/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.sarif deleted file mode 100644 index 622dbeb8..00000000 --- a/src/drivers/wdm/queries/experimental/IrqTooHigh/IrqTooHigh.sarif +++ /dev/null @@ -1,169 +0,0 @@ -{ - "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", - "version" : "2.1.0", - "runs" : [ { - "tool" : { - "driver" : { - "name" : "CodeQL", - "organization" : "GitHub", - "semanticVersion" : "2.11.5", - "rules" : [ { - "id" : "cpp/portedqueries/irq-too-high", - "name" : "cpp/portedqueries/irq-too-high", - "shortDescription" : { - "text" : "IrqTooHigh" - }, - "fullDescription" : { - "text" : "The function is not permitted to be called at the current IRQ level. The current level is too high." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "error" - }, - "properties" : { - "description" : "The function is not permitted to be called at the current IRQ level. The current level is too high.", - "feature.area" : "Multiple", - "id" : "cpp/portedqueries/irq-too-high", - "kind" : "problem", - "name" : "IrqTooHigh", - "platform" : "Desktop", - "problem.severity" : "error", - "repro.text" : "The following line(s) potentially contains a function call that is supposed to be called at a higher Irql level.", - "version" : "1.0" - } - } ] - }, - "extensions" : [ { - "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.1.0+933e876f096a70922173e4d5ad604d99d4481af4", - "locations" : [ { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", - "description" : { - "text" : "The QL pack root directory." - } - }, { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." - } - } ] - }, { - "name" : "legacy-upgrades", - "semanticVersion" : "0.0.0", - "locations" : [ { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/", - "description" : { - "text" : "The QL pack root directory." - } - }, { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." - } - } ] - } ] - }, - "artifacts" : [ { - "location" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - } - }, { - "location" : { - "uri" : "driver/fail_driver1.c", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - } - } ], - "results" : [ { - "ruleId" : "cpp/portedqueries/irq-too-high", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/portedqueries/irq-too-high", - "index" : 0 - }, - "message" : { - "text" : "IrqlLowTestFunction can not be called at the current Irql level. The current level is too high" - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 63, - "startColumn" : 5, - "endColumn" : 24 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "1b74530608bc3ddf:1", - "primaryLocationStartColumnFingerprint" : "0" - } - }, { - "ruleId" : "cpp/portedqueries/irq-too-high", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/portedqueries/irq-too-high", - "index" : 0 - }, - "message" : { - "text" : "TestInner4 can not be called at the current Irql level. The current level is too high" - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 36, - "startColumn" : 14, - "endColumn" : 24 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "7ae2af586e0dd70a:1", - "primaryLocationStartColumnFingerprint" : "9" - } - }, { - "ruleId" : "cpp/portedqueries/irq-too-high", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/portedqueries/irq-too-high", - "index" : 0 - }, - "message" : { - "text" : "failForIrqlTooHigh can not be called at the current Irql level. The current level is too high" - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/fail_driver1.c", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - }, - "region" : { - "startLine" : 322, - "startColumn" : 5, - "endColumn" : 23 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "251f68b02b7c2bea:1", - "primaryLocationStartColumnFingerprint" : "0" - } - } ], - "columnKind" : "utf16CodeUnits", - "properties" : { - "semmle.formatSpecifier" : "sarifv2.1.0" - } - } ] -} \ No newline at end of file diff --git a/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.ql b/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.ql deleted file mode 100644 index 5fda52f7..00000000 --- a/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.ql +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * @name IrqTooLow - * @kind problem - * @description The function is not permitted to be called at the current IRQ level. The current level is too low. - * @problem.severity error - * @id cpp/portedqueries/irq-too-low - * @platform Desktop - * @repro.text The following line(s) potentially contains a function call that is supposed to be called at a lower Irql level. - * @feature.area Multiple - * @version 1.0 - */ - -import cpp -import drivers.libraries.Irql - -from IrqlAnnotatedFunction iaf, CallsToIrqlAnnotatedFunction ciaf, int curr, int called -where - ciaf.getEnclosingFunction() = iaf and - iaf.getIrqlLevel() = curr and - getActualIrqlFunc(ciaf).getIrqlLevel() = called and - curr < called -select ciaf, - "Irql was set to " + curr + " in " + iaf.getName() + " but " + ciaf.getTarget().getName() + - "() in its call hierarchy requires " + called + " Irql level." diff --git a/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.sarif b/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.sarif deleted file mode 100644 index 0e3b8d32..00000000 --- a/src/drivers/wdm/queries/experimental/IrqTooLow/IrqTooLow.sarif +++ /dev/null @@ -1,107 +0,0 @@ -{ - "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", - "version" : "2.1.0", - "runs" : [ { - "tool" : { - "driver" : { - "name" : "CodeQL", - "organization" : "GitHub", - "semanticVersion" : "2.11.5", - "rules" : [ { - "id" : "cpp/portedqueries/irq-too-low", - "name" : "cpp/portedqueries/irq-too-low", - "shortDescription" : { - "text" : "IrqTooLow" - }, - "fullDescription" : { - "text" : "The function is not permitted to be called at the current IRQ level. The current level is too low." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "error" - }, - "properties" : { - "description" : "The function is not permitted to be called at the current IRQ level. The current level is too low.", - "feature.area" : "Multiple", - "id" : "cpp/portedqueries/irq-too-low", - "kind" : "problem", - "name" : "IrqTooLow", - "platform" : "Desktop", - "problem.severity" : "error", - "repro.text" : "The following line(s) potentially contains a function call that is supposed to be called at a lower Irql level.", - "version" : "1.0" - } - } ] - }, - "extensions" : [ { - "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.1.0+933e876f096a70922173e4d5ad604d99d4481af4", - "locations" : [ { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", - "description" : { - "text" : "The QL pack root directory." - } - }, { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." - } - } ] - }, { - "name" : "legacy-upgrades", - "semanticVersion" : "0.0.0", - "locations" : [ { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/", - "description" : { - "text" : "The QL pack root directory." - } - }, { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." - } - } ] - } ] - }, - "artifacts" : [ { - "location" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - } - } ], - "results" : [ { - "ruleId" : "cpp/portedqueries/irq-too-low", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/portedqueries/irq-too-low", - "index" : 0 - }, - "message" : { - "text" : "Irql was set to 1 in TestInner2 but someFunc() in its call hierarchy requires 2 Irql level." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 31, - "startColumn" : 14, - "endColumn" : 22 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "ad7afdefc432f9c8:1", - "primaryLocationStartColumnFingerprint" : "9" - } - } ], - "columnKind" : "utf16CodeUnits", - "properties" : { - "semmle.formatSpecifier" : "sarifv2.1.0" - } - } ] -} \ No newline at end of file From 80a70de0db74cb029b88ad47565c4b2a637c1bb0 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:07:26 -0700 Subject: [PATCH 09/54] Irql.qll cleanup --- src/drivers/libraries/Irql.qll | 127 ++++++++++++++------------------- 1 file changed, 55 insertions(+), 72 deletions(-) diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index b2d9dc01..5d335316 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -38,7 +38,7 @@ class IrqlMacro extends Macro { } } -/** Represents an _IRQL_saves_global_(parameter, kind) annotation. */ +/** An \_IRQL\_saves\_global\_(parameter, kind) annotation. */ class IrqlSavesGlobalAnnotation extends SALAnnotation { MacroInvocation irqlMacroInvocation; @@ -49,7 +49,7 @@ class IrqlSavesGlobalAnnotation extends SALAnnotation { } } -/** Represents an _IRQL_restores_global_(parameter, kind) annotation. */ +/** An \_IRQL\_restores\_global\_(parameter, kind) annotation. */ class IrqlRestoresGlobalAnnotation extends SALAnnotation { MacroInvocation irqlMacroInvocation; @@ -60,14 +60,13 @@ class IrqlRestoresGlobalAnnotation extends SALAnnotation { } } -/** Represents standard IRQL annotations which refer to explicit IRQL levels. */ -class IrqlAnnotation extends SALAnnotation { +/** Standard IRQL annotations which apply to entire functions and manipulate or constrain the IRQL. */ +class IrqlFunctionAnnotation extends SALAnnotation { string irqlLevel; string irqlAnnotationName; MacroInvocation irqlMacroInvocation; - IrqlAnnotation() { - // Needs to include other function and parameter annotations too + IrqlFunctionAnnotation() { this.getMacroName() .matches([ "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", @@ -79,32 +78,31 @@ class IrqlAnnotation extends SALAnnotation { } /** Returns the raw text of the IRQL value used in this annotation. */ - string getIrqlLevelFull() { result = irqlLevel } + string getIrqlLevelString() { result = irqlLevel } - /** Returns the text of this annotation (i.e. _IRQL_requires_, etc.) */ + /** Returns the text of this annotation (i.e. \_IRQL\_requires\_, etc.) */ string getIrqlMacroName() { result = irqlAnnotationName } /** Evaluate the IRQL specified in this annotation, if possible. */ int getIrqlLevel() { - if exists(IrqlMacro im | im.getHead().matches(this.getIrqlLevelFull())) + if exists(IrqlMacro im | im.getHead().matches(this.getIrqlLevelString())) then result = any(int i | exists(IrqlMacro im | im.getIrqlLevel() = i and - im.getHead().matches(this.getIrqlLevelFull()) + im.getHead().matches(this.getIrqlLevelString()) ) ) else result = -1 } } -/** Represents an "_IRQL_requires_same" annotation. */ +/** Represents an "\_IRQL\_requires\_same\_" annotation. */ class IrqlSameAnnotation extends SALAnnotation { string irqlAnnotationName; IrqlSameAnnotation() { - //Needs to include other function and parameter annotations too this.getMacroName().matches(["_IRQL_requires_same_"]) and irqlAnnotationName = this.getMacroName() } @@ -112,29 +110,29 @@ class IrqlSameAnnotation extends SALAnnotation { string getIrqlMacroName() { result = irqlAnnotationName } } -/** An "_IRQL_requires_max" annotation. */ -class IrqlMaxAnnotation extends IrqlAnnotation { +/** An "\_IRQL\_requires\_max\_" annotation. */ +class IrqlMaxAnnotation extends IrqlFunctionAnnotation { IrqlMaxAnnotation() { this.getMacroName().matches("_IRQL_requires_max_") } } -/** An "_IRQL_raises_" annotation. */ -class IrqlRaisesAnnotation extends IrqlAnnotation { +/** An "\_IRQL\_raises\_" annotation. */ +class IrqlRaisesAnnotation extends IrqlFunctionAnnotation { IrqlRaisesAnnotation() { this.getMacroName().matches("_IRQL_raises_") } } -/** An "IRQL_requires_min" annotation. */ -class IrqlMinAnnotation extends IrqlAnnotation { +/** An "\_IRQL\_requires\_min\_" annotation. */ +class IrqlMinAnnotation extends IrqlFunctionAnnotation { IrqlMinAnnotation() { this.getMacroName().matches("_IRQL_requires_min_") } } -/** An "_IRQL_requires_" annotation. */ -class IrqlRequiresAnnotation extends IrqlAnnotation { +/** An "\_IRQL\_requires\_" annotation. */ +class IrqlRequiresAnnotation extends IrqlFunctionAnnotation { IrqlRequiresAnnotation() { this.getMacroName().matches("_IRQL_requires_") } } /** * A SAL annotation indicating that the parameter in - * question is used as part of adjusting the IRQL. + * question is used to store or restore the IRQL. */ class IrqlParameterAnnotation extends SALAnnotation { string irqlAnnotationName; @@ -145,6 +143,7 @@ class IrqlParameterAnnotation extends SALAnnotation { exists(MacroInvocation mi | mi.getParentInvocation() = this) } + /** Get the text of the annotation. */ string getIrqlMacroName() { result = irqlAnnotationName } } @@ -158,10 +157,10 @@ class IrqlRestoreAnnotation extends IrqlParameterAnnotation { /** * A SAL annotation indicating that can be used in two ways: - * - If applied to a function, the function returns the previous IRQL. + * - If applied to a function, the function returns the previous IRQL or otherwise saves the IRQL. * - If applied to a parameter, the function saves the IRQL to the parameter. */ -class IrqlSaveAnnotation extends IrqlAnnotation { +class IrqlSaveAnnotation extends IrqlFunctionAnnotation { IrqlSaveAnnotation() { this.getMacroName().matches(["_IRQL_saves_"]) } } @@ -177,11 +176,11 @@ class IrqlSaveParameter extends Parameter { /** A typedef that has IRQL annotations applied to it. */ class IrqlAnnotatedTypedef extends TypedefType { - IrqlAnnotation irqlAnnotation; + IrqlFunctionAnnotation irqlAnnotation; IrqlAnnotatedTypedef() { irqlAnnotation.getTypedefDeclarations() = this } - IrqlAnnotation getIrqlAnnotation() { result = irqlAnnotation } + IrqlFunctionAnnotation getIrqlAnnotation() { result = irqlAnnotation } } /** @@ -191,7 +190,7 @@ class IrqlAnnotatedTypedef extends TypedefType { */ cached class IrqlRestrictsFunction extends Function { - IrqlAnnotation irqlAnnotation; + IrqlFunctionAnnotation irqlAnnotation; cached IrqlRestrictsFunction() { @@ -213,7 +212,7 @@ class IrqlRestrictsFunction extends Function { /** A function that changes the IRQL. */ abstract class IrqlChangesFunction extends Function { } -/** A function that is explicitly annotated to not change the IRQL. */ +/** A function that is explicitly annotated to enter and exit at the same IRQL. */ class IrqlRequiresSameAnnotatedFunction extends Function { IrqlSameAnnotation irqlAnnotation; @@ -293,9 +292,13 @@ class IrqlRestoresGlobalAnnotatedFunction extends IrqlChangesFunction { int getIrqlParameterSlot() { result = irqlParamIndex } } +/** + * An abstract class for functions that use the \_IRQL\_saves\_ annotation, + * either on the function definition or on a specific parameter. + */ abstract class IrqlSavesFunction extends Function { } -/** A function that has a parameter annotated _IRQL_saves_. */ +/** A function that has a parameter annotated \_IRQL\_saves\_. */ class IrqlSavesToParameterFunction extends IrqlSavesFunction { IrqlSaveParameter saveParameter; int irqlParamIndex; @@ -317,7 +320,7 @@ class IrqlSavesViaReturnFunction extends IrqlSavesFunction { } } -/** A function that has a parameter annotated _IRQL_restores_. */ +/** A function that has a parameter annotated \_IRQL\_restores\_. */ class IrqlRestoreAnnotatedFunction extends Function { IrqlRestoreParameter restoreParameter; int irqlParamIndex; @@ -327,7 +330,7 @@ class IrqlRestoreAnnotatedFunction extends Function { int getIrqlParameterSlot() { result = irqlParamIndex } } -/** A call to a function that has a parameter annotated _IRQL_restores_. */ +/** A call to a function that has a parameter annotated \_IRQL\_restores\_. */ class IrqlRestoreCall extends FunctionCall { IrqlRestoreCall() { this.getTarget() instanceof IrqlRestoreAnnotatedFunction } @@ -352,7 +355,7 @@ class IrqlRestoreCall extends FunctionCall { } /** - * Holds if a given call to an _IRQL_saves_global_ annotated function is using the same IRQL location as this. + * Holds if a given call to an \_IRQL\_saves\_global\_ annotated function is using the same IRQL location as this. */ private predicate matchingSaveCall(IrqlSaveCall sgic) { // Attempting to match all expr children leads to an explosion in runtime, so for now just compare @@ -372,7 +375,7 @@ class IrqlRestoreCall extends FunctionCall { } } -/** A call to a function that has a parameter annotated _IRQL_saves_. */ +/** A call to a function that has is annotated \_IRQL\_saves\_. */ class IrqlSaveCall extends FunctionCall { IrqlSaveCall() { this.getTarget() instanceof IrqlSavesFunction } @@ -420,8 +423,6 @@ class KeLowerIrqlCall extends FunctionCall { /** * Get the most recent call before this call that explicitly raised the IRQL. - * - * TODO: Should be updated to account for functions that are annotated _IRQL_raises_. */ KeRaiseIrqlCall getMostRecentRaise() { result = @@ -504,14 +505,13 @@ private predicate exprsMatchText(Expr e1, Expr e2) { * - If calling a function annotated to restore the IRQL from a previously saved spot, then the result is the IRQL before that save call. * - If calling a function annotated to raise the IRQL, then it returns the annotated value (the target IRQL). * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN. - * - If this node immediately precedes a call to a call annotated _Irql_Requires_, then the result is the annotated value for that call. * - If this node is calling a function with no annotations, the result is the IRQL that function exits at. * - If there is a prior CFN in the CFG, the result is the result for that prior CFN. * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function. * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. * - If there is nothing else, then IRQL is 0. - * TODO: _IRQL_limited_to_(DISPATCH_LEVEL); - * TODO: Functions not explicitly annotated at the function level, but which have _IRQL_saves_ or _IRQL_restores_ parameter annotations. + * + * Not implemented: _IRQL_limited_to_ */ cached int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { @@ -544,44 +544,27 @@ int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { .getTarget())) ) else -/* if - exists(ControlFlowNode cfn2 | - cfn2 = cfn.getASuccessor() and - cfn2.(FunctionCall).getTarget() instanceof IrqlRequiresAnnotatedFunction - ) - then - result = - any(cfn.getASuccessor() - .(FunctionCall) - .getTarget() - .(IrqlRequiresAnnotatedFunction) - .getIrqlLevel() + if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor()) + then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + else + if + exists(FunctionCall fc, ControlFlowNode cfn2 | + fc.getTarget() = cfn.getControlFlowScope() and + cfn2.getASuccessor() = fc ) - else*/ - if exists(ControlFlowNode cfn2 | cfn2 = cfn.getAPredecessor()) - then result = any(getPotentialExitIrqlAtCfn(cfn.getAPredecessor())) + then + result = + any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 | + cfn2.getASuccessor().(FunctionCall).getTarget() = + cfn.getControlFlowScope() + )) + ) else if - exists(FunctionCall fc, ControlFlowNode cfn2 | - fc.getTarget() = cfn.getControlFlowScope() and - cfn2.getASuccessor() = fc - ) - then - result = - any(getPotentialExitIrqlAtCfn(any(ControlFlowNode cfn2 | - cfn2.getASuccessor().(FunctionCall).getTarget() = - cfn.getControlFlowScope() - )) - ) - else - if - cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and - getAllowableIrqlLevel(cfn.getControlFlowScope()) != -1 - then result = getAllowableIrqlLevel(cfn.getControlFlowScope()) - else result = 0 - // TODO: How to handle cases where the function is annotated _IRQL_MIN_, etc? - // May need to split into two libraries: "Actual" IRQL tracking and "annotation-based" IRQL tracking. - // Or maybe we keep the actual tracking for queries. + cfn.getControlFlowScope() instanceof IrqlRestrictsFunction and + getAllowableIrqlLevel(cfn.getControlFlowScope()) != -1 + then result = getAllowableIrqlLevel(cfn.getControlFlowScope()) + else result = 0 } import semmle.code.cpp.controlflow.Dominance From ebb570de6e53e81d118d915f418f6b7f96006b73 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:34:14 -0700 Subject: [PATCH 10/54] Get rid of old prototype version of IrqlTooLow --- .../general/queries/IrqlTooLow/IrqlTooLow.ql | 173 ------------------ 1 file changed, 173 deletions(-) delete mode 100644 src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql diff --git a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql deleted file mode 100644 index e6b41b5c..00000000 --- a/src/drivers/general/queries/IrqlTooLow/IrqlTooLow.ql +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * @id cpp/drivers/irql-not-used - * @name IRQL not restored - * @description Any parameter annotated \_IRQL\_restores\_ must be read and used to restore the IRQL value. - * @platform Desktop - * @security.severity Low - * @feature.area Multiple - * @impact Insecure Coding Practice - * @repro.text This function has a parameter annotated \_IRQL\_restores\_, but does not have a code path where this parameter is read and used to restore the IRQL. - * @owner.email sdat@microsoft.com - * @kind problem - * @problem.severity warning - * @precision medium - * @tags correctness - * wddst - * @query-version v1 - */ - -import cpp -import drivers.libraries.Irql - -/** Represents a call to a function that has IRQL annotations restricting the range of IRQLs it can run at. */ -class IrqlRestrainedCall extends FunctionCall { - IrqlRestrainedCall() { this.getTarget() instanceof IrqlAnnotatedFunction } - - int getIrqlLevel() { result = this.getTarget().(IrqlAnnotatedFunction).getIrqlLevel() } - - string getFuncIrqlAnnotation() { - result = this.getTarget().(IrqlAnnotatedFunction).getFuncIrqlAnnotation() - } -} - -/** - * Attempt to find the range of valid IRQL values when **exiting** a given function. - * TODO: Make a version of this focused on calls that we can recursively call to track the IRQL. - * TODO: Cases where annotated min and max - * BUG: Returning 15 unexpectedly in places. - */ -int getPotentialIrql(IrqlAnnotatedFunction irqlFunc) { - if irqlFunc instanceof IrqlRaisesAnnotatedFunction - then result = irqlFunc.getIrqlLevel() - else - if - irqlFunc instanceof IrqlRequiresAnnotatedFunction and - irqlFunc instanceof IrqlRequiresSameAnnotatedFunction - then result = irqlFunc.getIrqlLevel() - else - if - irqlFunc instanceof IrqlMaxAnnotatedFunction and - irqlFunc instanceof IrqlMinAnnotatedFunction and - irqlFunc instanceof IrqlRequiresSameAnnotatedFunction - then - result = - any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. irqlFunc - .(IrqlMaxAnnotatedFunction) - .getIrqlLevel()] - ) - else - if - irqlFunc instanceof IrqlMaxAnnotatedFunction and - irqlFunc instanceof IrqlRequiresSameAnnotatedFunction - then result = any([0 .. irqlFunc.getIrqlLevel()]) - else - if - irqlFunc instanceof IrqlMinAnnotatedFunction and - irqlFunc instanceof IrqlRequiresSameAnnotatedFunction - then result = any([irqlFunc.getIrqlLevel() .. 15]) - else - // Below indicates we cannot determine the correct IRQL - result = -1 -} - -cached -int getIrqlAtThisStatement(Expr e) { - if e instanceof KeRaiseIrqlCall - then result = e.(KeRaiseIrqlCall).getIrqlLevel() - else - if not exists(ControlFlowNode cfn | cfn = e.getAPredecessor()) - then result = 0 - else result = any(getIrqlAtThisStatement(e.getAPredecessor())) -} - -/** Given a IrqlRestrainedCall, gets the most recent prior call in the block. */ -IrqlRestrainedCall getPrecedingCallInSameBasicBlock(IrqlRestrainedCall irc) { - result = - irc.getBasicBlock() - .getNode(max(int precPos | - exists(IrqlRestrainedCall prec, int callPos | - irc.getBasicBlock().getNode(precPos) = prec and - irc.getBasicBlock().getNode(callPos) = irc and - precPos < callPos - ) - )) -} - -/** Get the most recent basic block(s) before a given block that also adjust the IRQL. */ -BasicBlock getPrecedingBasicBlocksWithIrqlCalls(BasicBlock inBlock) { - result = - any(BasicBlock bb | - bb.getANode() instanceof IrqlRestrainedCall and - bb.getASuccessor+() = inBlock and - not exists(BasicBlock otherBlock | - bb.getASuccessor+() = otherBlock and - otherBlock.getASuccessor+() = otherBlock and - otherBlock.getANode() instanceof IrqlRestrainedCall - ) - ) -} - -/** Given a basic block, return the last irql-restrained call in that block. */ -IrqlRestrainedCall lastIrqlCallInBlock(BasicBlock inBlock) { - result = inBlock.getNode(max(int i | inBlock.getNode(i) instanceof IrqlRestrainedCall)) -} - -/** Given a irql-restrained call, return the most recent set of irql restrictions prior to it. */ -int getAMostRecentIrql(IrqlRestrainedCall irc) { - if - exists(IrqlRestrainedCall previousCall, int precPos, int callPos | - irc.getBasicBlock().contains(previousCall) and - irc != previousCall and - irc.getBasicBlock().getNode(precPos) = previousCall and - irc.getBasicBlock().getNode(callPos) = irc - ) - then result = getPotentialIrql(getPrecedingCallInSameBasicBlock(irc).getTarget()) - else - // look for most recent basic block(s) with Irql calls - if - exists(BasicBlock previousIrqlBlock, IrqlRestrainedCall previousCall | - irc.getBasicBlock().getAPredecessor+() = previousIrqlBlock and - previousCall.getBasicBlock() = previousIrqlBlock - ) - then - // Can we use the same algorithm as the intra-block search? - // Foreach preceding block that has an IrqlCall, use its values iff not exists - // some other block s.t. there is a path from the preceding block to the other block to our block. - result = - ( - any(IrqlRestrainedCall previousCall | - previousCall = - lastIrqlCallInBlock(getPrecedingBasicBlocksWithIrqlCalls(irc.getBasicBlock())) - ) - ).getIrqlLevel() - else - // Else look at function signature overall - if irc.getEnclosingFunction() instanceof IrqlAnnotatedFunction - then result = getPotentialIrql(irc.getEnclosingFunction()) - else - // Else invalid - result = -1 -} - -// TODO: Track IRQL recursively -/* - * from IrqlRestrainedCall irc, int previousLevel - * where - * irc.getTarget() instanceof IrqlMinAnnotatedFunction and - * previousLevel != -1 and - * previousLevel = max(int i | i = getAMostRecentIrql(irc)) and - * irc.getTarget().(IrqlMinAnnotatedFunction).getIrqlLevel() > previousLevel - * select irc, "IRQL is potentially too low at call $@ - min " + irc.getIrqlLevel() + ", found " + previousLevel, irc, irc.toString() - */ - -// TODO: Track IRQL recursively -from IrqlRestrainedCall irc, int previousLevel -where - irc.getTarget() instanceof IrqlMaxAnnotatedFunction and - previousLevel != -1 and - previousLevel = min(int i | i = getAMostRecentIrql(irc)) and - irc.getTarget().(IrqlMaxAnnotatedFunction).getIrqlLevel() < previousLevel -select irc, "IRQL is too high at call $@ - max " + irc.getIrqlLevel() + ", found " + previousLevel, - irc, irc.toString() From ee4b80cf40f183a89706b6fa7e217102663c9b2b Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:37:15 -0700 Subject: [PATCH 11/54] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 81b6d62b..891f27de 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository contains open-source components for supplemental use in developi | Branch to use | CodeQL CLI version | |--------------------------|--------------------| -| main | 2.11.5 | +| main | 2.14.4 | ### For Windows Hardware Compatibility Program Use @@ -17,7 +17,7 @@ This repository contains open-source components for supplemental use in developi | Windows 11 | WHCP_21H2 | 2.4.6 | | Windows 11, version 22H2 | WHCP_22H2 | 2.6.3 | -For general use, use the `main` branch along with [version 2.11.5 of the CodeQL CLI](https://github.com/github/codeql-cli-binaries/releases/tag/v2.11.5). +For general use, use the `main` branch along with [version 2.14.4 of the CodeQL CLI](https://github.com/github/codeql-cli-binaries/releases/tag/v2.14.4). ## Quickstart @@ -30,7 +30,7 @@ For general use, use the `main` branch along with [version 2.11.5 of the CodeQL For the WHCP Program, use the CodeQL CLI version in accordance with the table above and Windows release you are certifying for: [version 2.4.6](https://github.com/github/codeql-cli-binaries/releases/tag/v2.4.6) or [version 2.6.3](https://github.com/github/codeql-cli-binaries/releases/tag/v2.6.3). - For general use with the `main` branch, use [CodeQL CLI version 2.11.5](https://github.com/github/codeql-cli-binaries/releases/tag/v2.11.5). + For general use with the `main` branch, use [CodeQL CLI version 2.14.4](https://github.com/github/codeql-cli-binaries/releases/tag/v2.14.4). 1. Clone and install the Windows Driver Developer Supplemental Tools repository which contains the CodeQL queries specific for drivers: @@ -56,8 +56,8 @@ For general use, use the `main` branch along with [version 2.11.5 of the CodeQL 1. Verify CodeQL is installed correctly by checking the version: ``` D:\codeql-home\codeql>codeql --version - CodeQL command-line toolchain release 2.11.5. - Copyright (C) 2019-2022 GitHub, Inc. + CodeQL command-line toolchain release 2.14.4. + Copyright (C) 2019-2023 GitHub, Inc. Unpacked in: D:\codeql-home\codeql Analysis results depend critically on separately distributed query and extractor modules. To list modules that are visible to the toolchain, From e1ddb6adde60e8ab5e23ef1b6bd4d83478cee484 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:26:49 -0700 Subject: [PATCH 12/54] Clean up file names --- .../IrqTooHigh.qhelp => IrqlTooHigh/IrqlTooHigh.qhelp} | 0 .../{IrqTooHigh/IrqTooHigh.ql => IrqlTooHigh/IrqlTooHigh.ql} | 0 .../IrqTooHigh.sarif => IrqlTooHigh/IrqlTooHigh.sarif} | 0 .../experimental/{IrqTooHigh => IrqlTooHigh}/driver_snippet.c | 0 .../{IrqTooLow/IrqTooLow.qhelp => IrqlTooLow/IrqlTooLow.qhelp} | 0 .../{IrqTooLow/IrqTooLow.ql => IrqlTooLow/IrqlTooLow.ql} | 0 .../{IrqTooLow/IrqTooLow.sarif => IrqlTooLow/IrqlTooLow.sarif} | 0 .../experimental/{IrqTooLow => IrqlTooLow}/driver_snippet.c | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/drivers/general/queries/experimental/{IrqTooHigh/IrqTooHigh.qhelp => IrqlTooHigh/IrqlTooHigh.qhelp} (100%) rename src/drivers/general/queries/experimental/{IrqTooHigh/IrqTooHigh.ql => IrqlTooHigh/IrqlTooHigh.ql} (100%) rename src/drivers/general/queries/experimental/{IrqTooHigh/IrqTooHigh.sarif => IrqlTooHigh/IrqlTooHigh.sarif} (100%) rename src/drivers/general/queries/experimental/{IrqTooHigh => IrqlTooHigh}/driver_snippet.c (100%) rename src/drivers/general/queries/experimental/{IrqTooLow/IrqTooLow.qhelp => IrqlTooLow/IrqlTooLow.qhelp} (100%) rename src/drivers/general/queries/experimental/{IrqTooLow/IrqTooLow.ql => IrqlTooLow/IrqlTooLow.ql} (100%) rename src/drivers/general/queries/experimental/{IrqTooLow/IrqTooLow.sarif => IrqlTooLow/IrqlTooLow.sarif} (100%) rename src/drivers/general/queries/experimental/{IrqTooLow => IrqlTooLow}/driver_snippet.c (100%) diff --git a/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.qhelp rename to src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp diff --git a/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.ql b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.ql rename to src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql diff --git a/src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooHigh/IrqTooHigh.sarif rename to src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif diff --git a/src/drivers/general/queries/experimental/IrqTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlTooHigh/driver_snippet.c similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooHigh/driver_snippet.c rename to src/drivers/general/queries/experimental/IrqlTooHigh/driver_snippet.c diff --git a/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.qhelp b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.qhelp rename to src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp diff --git a/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.ql rename to src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql diff --git a/src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooLow/IrqTooLow.sarif rename to src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif diff --git a/src/drivers/general/queries/experimental/IrqTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlTooLow/driver_snippet.c similarity index 100% rename from src/drivers/general/queries/experimental/IrqTooLow/driver_snippet.c rename to src/drivers/general/queries/experimental/IrqlTooLow/driver_snippet.c From 6dd4a611a490432d21eef33c3e37e92d5dcc0c85 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:37:08 -0700 Subject: [PATCH 13/54] Clean up queries. --- .../IrqlTooHigh/IrqlTooHigh.qhelp | 2 +- .../experimental/IrqlTooHigh/IrqlTooHigh.ql | 30 +++++++++++-------- .../experimental/IrqlTooLow/IrqlTooLow.qhelp | 2 +- .../experimental/IrqlTooLow/IrqlTooLow.ql | 27 +++++++++-------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp index fda952f8..83ee1a7c 100644 --- a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp +++ b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.qhelp @@ -7,7 +7,7 @@

- The driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. + The driver is executing at an IRQL that is too high for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.

diff --git a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql index a152242c..afd1a25a 100644 --- a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql @@ -2,35 +2,39 @@ // Licensed under the MIT license. /** * @id cpp/drivers/irql-too-high - * @name IRQL too low (C28120) + * @name IRQL too high (C28120) * @description A function annotated with IRQL requirements was called at an IRQL too high for the requirements. * @platform Desktop * @security.severity Low * @feature.area Multiple - * @impact Insecure Coding Practice - * @repro.text A function annotated with IRQL requirements was called at an IRQL too high for the requirements. + * @impact Exploitable Design + * @repro.text The following function call is taking place at an IRQL too high for what the call target is annotated as. * @owner.email sdat@microsoft.com + * @opaqueid CQLD-C28120 * @kind problem * @problem.severity warning * @precision medium * @tags correctness * wddst - * @query-version v1 + * @scope domainspecific + * @query-version v2 */ import cpp import drivers.libraries.Irql -from FunctionCall fc, IrqlRestrictsFunction imaf, ControlFlowNode e, int irqlRequirement +from FunctionCall call, IrqlRestrictsFunction irqlFunc, ControlFlowNode prior, int irqlRequirement where - fc.getTarget() = imaf and - e = fc.getAPredecessor() and + call.getTarget() = irqlFunc and + prior = call.getAPredecessor() and ( - imaf.(IrqlMaxAnnotatedFunction).getIrqlLevel() = irqlRequirement + irqlFunc.(IrqlMaxAnnotatedFunction).getIrqlLevel() = irqlRequirement or - imaf.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement + irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and - irqlRequirement < min(getPotentialExitIrqlAtCfn(e)) -select fc, - "IRQL potentially too high at this call ($@). Maximum irql level of this call: $@, Irql level at preceding node: $@", - fc, fc.getTarget().toString(), fc, "" + irqlRequirement, e, "" + min(getPotentialExitIrqlAtCfn(e)) + irqlRequirement < min(getPotentialExitIrqlAtCfn(prior)) +select call, + "$@: IRQL potentially too high at call to $@. Maximum IRQL for this call: " + irqlRequirement + + ", IRQL at preceding node: " + min(getPotentialExitIrqlAtCfn(prior)), + call.getControlFlowScope(), call.getControlFlowScope().getQualifiedName(), call, + call.getTarget().toString() diff --git a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp index cda052cd..7582b8fb 100644 --- a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp +++ b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.qhelp @@ -7,7 +7,7 @@

- The driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. + The driver is executing at an IRQL that is too low for the function that it is calling. Consult the WDK documentation for the function and verify the IRQL at which the function can be called. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate.

diff --git a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql index e01e533e..9b42ad7a 100644 --- a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql @@ -7,30 +7,33 @@ * @platform Desktop * @security.severity Low * @feature.area Multiple - * @impact Insecure Coding Practice - * @repro.text A function annotated with IRQL requirements was called at an IRQL too low for the requirements. + * @impact Exploitable Design + * @repro.text The following function call is taking place at an IRQL too low for what the call target is annotated as. * @owner.email sdat@microsoft.com + * @opaqueid CQLD-C28121 * @kind problem * @problem.severity warning * @precision medium * @tags correctness * wddst - * @query-version v1 + * @scope domainspecific + * @query-version v2 */ import cpp import drivers.libraries.Irql -from FunctionCall fc, IrqlRestrictsFunction imaf, ControlFlowNode e, int irqlRequirement +from FunctionCall call, IrqlRestrictsFunction irqlFunc, ControlFlowNode prior, int irqlRequirement where - fc.getTarget() = imaf and - e = fc.getAPredecessor() and + call.getTarget() = irqlFunc and + prior = call.getAPredecessor() and ( - imaf.(IrqlMinAnnotatedFunction).getIrqlLevel() = irqlRequirement + irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() = irqlRequirement or - imaf.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement + irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and - irqlRequirement > max(getPotentialExitIrqlAtCfn(e)) -select fc, - "IRQL potentially too low at this call ($@). Minimum irql level of this call: $@, Irql level at preceding node: $@", - fc, fc.getTarget().toString(), fc, "" + irqlRequirement, e, "" + max(getPotentialExitIrqlAtCfn(e)) + irqlRequirement > max(getPotentialExitIrqlAtCfn(prior)) +select call, + "$@: IRQL potentially too low at call to $@. Minimum IRQL for this call: " + irqlRequirement + + ", IRQL at preceding node: " + max(getPotentialExitIrqlAtCfn(prior)), call.getControlFlowScope(), + call.getControlFlowScope().getQualifiedName(), call, call.getTarget().toString() From c9dc15e22738808d05710cadd0e48a7662ca47ff Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:56:18 -0700 Subject: [PATCH 14/54] Update test script for IRQL queries. --- .../test/build_create_analyze_test.cmd | 4 ++-- src/drivers/test/diff/IrqlTooHigh.sarif | 21 +++++++++++++++++++ src/drivers/test/diff/IrqlTooLow.sarif | 21 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/drivers/test/diff/IrqlTooHigh.sarif create mode 100644 src/drivers/test/diff/IrqlTooLow.sarif diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index 9948923d..c62f32f9 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -7,8 +7,8 @@ call :test NoPagingSegment WDMTestTemplate wdm queries call :test OpaqueMdlUse WDMTestTemplate wdm queries call :test OpaqueMdlWrite WDMTestTemplate wdm queries call :test KeWaitLocal WDMTestTemplate wdm queries -call :test IrqTooHigh WDMTestTemplate wdm queries\experimental -call :test IrqTooLow WDMTestTemplate wdm queries\experimental +call :test IrqlTooHigh WDMTestTemplate wdm queries\experimental +call :test IrqlTooLow WDMTestTemplate wdm queries\experimental call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries call :test ExtendedDeprecatedApis WDMTestTemplate general queries call :test WdkDeprecatedApis WDMTestTemplate general queries diff --git a/src/drivers/test/diff/IrqlTooHigh.sarif b/src/drivers/test/diff/IrqlTooHigh.sarif new file mode 100644 index 00000000..dea8275e --- /dev/null +++ b/src/drivers/test/diff/IrqlTooHigh.sarif @@ -0,0 +1,21 @@ +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } +} \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlTooLow.sarif b/src/drivers/test/diff/IrqlTooLow.sarif new file mode 100644 index 00000000..dea8275e --- /dev/null +++ b/src/drivers/test/diff/IrqlTooLow.sarif @@ -0,0 +1,21 @@ +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } +} \ No newline at end of file From d9641753d48dee16b10deff09146dd72bd505abb Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:06:42 -0700 Subject: [PATCH 15/54] Update build-codeql.yaml Signed-off-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> --- .github/workflows/build-codeql.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-codeql.yaml b/.github/workflows/build-codeql.yaml index 62562631..3c358b1d 100644 --- a/.github/workflows/build-codeql.yaml +++ b/.github/workflows/build-codeql.yaml @@ -32,7 +32,7 @@ jobs: with: owner: "github" repo: "codeql-cli-binaries" - tag: "v2.11.5" + tag: "v2.14.4" file: "codeql-win64.zip" - name: Unzip CodeQL CLI From 9aaa8ff8ddf16f4e1a51fb324750355bd3b65545 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 4 Oct 2023 19:08:34 -0700 Subject: [PATCH 16/54] Update ported_driver_ca_checks.qls --- src/suites/ported_driver_ca_checks.qls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/suites/ported_driver_ca_checks.qls b/src/suites/ported_driver_ca_checks.qls index e417ffc2..c4a43c99 100644 --- a/src/suites/ported_driver_ca_checks.qls +++ b/src/suites/ported_driver_ca_checks.qls @@ -13,8 +13,8 @@ - drivers/general/queries/PoolTagIntegral/PoolTagIntegral.ql - drivers/general/queries/WdkDeprecatedApis/wdk-deprecated-api.ql - drivers/kmdf/queries/StrSafe/StrSafe.ql - - drivers/wdm/experimental/IrqTooHigh/IrqTooHigh.ql - - drivers/wdm/experimental/IrqTooLow/IrqTooLow.ql + - drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql + - drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql - drivers/wdm/queries/ExaminedValue/ExaminedValue.ql - drivers/wdm/queries/IllegalFieldAccess/IllegalFieldAccess.ql - drivers/wdm/queries/IllegalFieldAccess2/IllegalFieldAccess2.ql From bb06b891b948b1c3e773bdaaf23a43895efe761c Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:55:08 -0700 Subject: [PATCH 17/54] Add IrqlSetTooHigh/IrqlSetTooLow queries. --- .../IrqlSetTooHigh/IrqlSetTooHigh.qhelp | 23 +++++++ .../IrqlSetTooHigh/IrqlSetTooHigh.ql | 42 +++++++++++++ .../IrqlSetTooLow/IrqlSetTooLow.qhelp | 23 +++++++ .../IrqlSetTooLow/IrqlSetTooLow.ql | 35 +++++++++++ src/drivers/libraries/Irql.qll | 63 ++++++++++++++----- 5 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.qhelp create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.qhelp create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.qhelp b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.qhelp new file mode 100644 index 00000000..19ac4ad8 --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.qhelp @@ -0,0 +1,23 @@ + + + +

+ The function has raised the IRQL to a level above what is allowed. +

+
+ +

+ A function has been annotated as having a max IRQL, but the execution of that function raises the IRQL above that maximum. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate. +

+
+ + + + +
  • + + C28150 + +
  • +
    +
    diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql new file mode 100644 index 00000000..1a26247e --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-set-too-high + * @name IRQL set too high (C28150) + * @description A function annotated with a maximum IRQL for execution raises the IRQL above that amount. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Exploitable Design + * @repro.text The following statement exits at an IRQL too high for the function it is contained in. + * @owner.email sdat@microsoft.com + * @opaqueid CQLD-C28150 + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @scope domainspecific + * @query-version v2 + */ + +import cpp +import drivers.libraries.Irql + +from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +where + statement.getControlFlowScope() = irqlFunc and + ( + irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement + or + // If we don't have an explicit max annotation but do raise the IRQL, + // we treat the raised-to level as the implicit max. + not irqlFunc instanceof IrqlAlwaysMaxFunction and + irqlFunc.(IrqlRaisesAnnotatedFunction).getIrqlLevel() = irqlRequirement + ) and + irqlRequirement != -1 and + irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) +select statement, + "$@: IRQL potentially set too high at $@. Maximum IRQL for this function: " + irqlRequirement + + ", IRQL at statement: " + min(getPotentialExitIrqlAtCfn(statement)), irqlFunc, + irqlFunc.getQualifiedName(), statement, statement.toString() diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.qhelp b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.qhelp new file mode 100644 index 00000000..440aca9c --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.qhelp @@ -0,0 +1,23 @@ + + + +

    + The function has lowered the IRQL to a level below what is allowed. +

    +
    + +

    + A function has been annotated as having a minimum IRQL, but the execution of that function lowers the IRQL below that minimum. If you have applied custom IRQL annotations to your own functions, confirm that they are accurate. +

    +
    + + + + +
  • + + C28124 + +
  • +
    +
    diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql new file mode 100644 index 00000000..09c3a91b --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * @id cpp/drivers/irql-set-too-low + * @name IRQL set too low (C28124) + * @description A function annotated with a minimum IRQL for execution lowers the IRQL below that amount. + * @platform Desktop + * @security.severity Low + * @feature.area Multiple + * @impact Exploitable Design + * @repro.text The following statement exits at an IRQL too low for the function it is contained in. + * @owner.email sdat@microsoft.com + * @opaqueid CQLD-C28124 + * @kind problem + * @problem.severity warning + * @precision medium + * @tags correctness + * wddst + * @scope domainspecific + * @query-version v2 + */ + +import cpp +import drivers.libraries.Irql + +from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +where + statement.getControlFlowScope() = irqlFunc and + irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and + irqlRequirement > max(getPotentialExitIrqlAtCfn(statement)) and + irqlRequirement != -1 +select statement, + "$@: IRQL potentially set too low at $@. Minimum IRQL for this function: " + irqlRequirement + + ", IRQL at statement: " + max(getPotentialExitIrqlAtCfn(statement)), irqlFunc, + irqlFunc.getQualifiedName(), statement, statement.toString() diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 5d335316..10dbb80b 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -60,21 +60,21 @@ class IrqlRestoresGlobalAnnotation extends SALAnnotation { } } -/** Standard IRQL annotations which apply to entire functions and manipulate or constrain the IRQL. */ +/** + * Standard IRQL annotations which apply to entire functions and manipulate or constrain the IRQL. + */ class IrqlFunctionAnnotation extends SALAnnotation { string irqlLevel; string irqlAnnotationName; - MacroInvocation irqlMacroInvocation; IrqlFunctionAnnotation() { this.getMacroName() .matches([ "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", - "_IRQL_saves_" + "_IRQL_saves_", "_IRQL_always_function_max_", "IRQL_always_function_min_" ]) and irqlAnnotationName = this.getMacroName() and - irqlMacroInvocation.getParentInvocation() = this and - irqlLevel = irqlMacroInvocation.getMacro().getHead() + irqlLevel = this.getUnexpandedArgument(0) } /** Returns the raw text of the IRQL value used in this annotation. */ @@ -83,18 +83,30 @@ class IrqlFunctionAnnotation extends SALAnnotation { /** Returns the text of this annotation (i.e. \_IRQL\_requires\_, etc.) */ string getIrqlMacroName() { result = irqlAnnotationName } - /** Evaluate the IRQL specified in this annotation, if possible. */ + /** + * Evaluate the IRQL specified in this annotation, if possible. + * + * This will return -1 if the IRQL specified is anything other than a standard + * IRQL level (i.e. PASSIVE_LEVEL). This includes statements like "DPC_LEVEL - 1". + */ int getIrqlLevel() { - if exists(IrqlMacro im | im.getHead().matches(this.getIrqlLevelString())) - then - result = - any(int i | - exists(IrqlMacro im | - im.getIrqlLevel() = i and - im.getHead().matches(this.getIrqlLevelString()) + // Special case for DPC_LEVEL, which is not defined normally + if this.getIrqlLevelString().matches("DPC_LEVEL") + then result = 2 + else + if exists(IrqlMacro im | im.getHead().matches(this.getIrqlLevelString())) + then + result = + any(int i | + exists(IrqlMacro im | + im.getIrqlLevel() = i and + im.getHead().matches(this.getIrqlLevelString()) + ) ) - ) - else result = -1 + else + if exists(int i | i = this.getIrqlLevelString().toInt()) + then result = this.getIrqlLevelString().toInt() + else result = -1 } } @@ -130,6 +142,14 @@ class IrqlRequiresAnnotation extends IrqlFunctionAnnotation { IrqlRequiresAnnotation() { this.getMacroName().matches("_IRQL_requires_") } } +class IrqlAlwaysMaxAnnotation extends IrqlFunctionAnnotation { + IrqlAlwaysMaxAnnotation() { this.getMacroName().matches("_IRQL_always_function_max_") } +} + +class IrqlAlwaysMinAnnotation extends IrqlFunctionAnnotation { + IrqlAlwaysMinAnnotation() { this.getMacroName().matches("_IRQL_always_function_min_") } +} + /** * A SAL annotation indicating that the parameter in * question is used to store or restore the IRQL. @@ -252,6 +272,18 @@ class IrqlRaisesAnnotatedFunction extends IrqlRestrictsFunction, IrqlChangesFunc int getIrqlLevel() { result = irqlAnnotation.(IrqlRaisesAnnotation).getIrqlLevel() } } +class IrqlAlwaysMaxFunction extends IrqlRestrictsFunction { + IrqlAlwaysMaxFunction() { irqlAnnotation instanceof IrqlAlwaysMaxAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlAlwaysMaxAnnotation).getIrqlLevel() } +} + +class IrqlAlwaysMinFunction extends IrqlRestrictsFunction { + IrqlAlwaysMinFunction() { irqlAnnotation instanceof IrqlAlwaysMinAnnotation } + + int getIrqlLevel() { result = irqlAnnotation.(IrqlAlwaysMinAnnotation).getIrqlLevel() } +} + /** A function annotated to save the IRQL at the specified location upon entry. */ class IrqlSavesGlobalAnnotatedFunction extends IrqlChangesFunction { IrqlSavesGlobalAnnotation irqlAnnotation; @@ -514,6 +546,7 @@ private predicate exprsMatchText(Expr e1, Expr e2) { * Not implemented: _IRQL_limited_to_ */ cached +pragma[assume_small_delta] int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { if cfn instanceof KeRaiseIrqlCall then result = cfn.(KeRaiseIrqlCall).getIrqlLevel() From 4842fd4116871d3b47eede85c2c4497b43c34d57 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:38:57 -0700 Subject: [PATCH 18/54] Bugfix for IrqlTooHigh/IrqlTooLow The changes to Irql.qll needed for IrqlSetTooHigh, etc. means we are more likely to see IRQL evaluations that return -1. Update queries to exclude those numbers. --- .../general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql | 1 + .../general/queries/experimental/IrqlTooLow/IrqlTooLow.ql | 1 + 2 files changed, 2 insertions(+) diff --git a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql index afd1a25a..fbec0213 100644 --- a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql @@ -32,6 +32,7 @@ where or irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and + irqlRequirement != -1 and irqlRequirement < min(getPotentialExitIrqlAtCfn(prior)) select call, "$@: IRQL potentially too high at call to $@. Maximum IRQL for this call: " + irqlRequirement + diff --git a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql index 9b42ad7a..e0234179 100644 --- a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql @@ -32,6 +32,7 @@ where or irqlFunc.(IrqlRequiresAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and + irqlRequirement != -1 and irqlRequirement > max(getPotentialExitIrqlAtCfn(prior)) select call, "$@: IRQL potentially too low at call to $@. Minimum IRQL for this call: " + irqlRequirement + From d27b6cdb2841aba3d022343162fd69daa89d51a5 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:11:42 -0700 Subject: [PATCH 19/54] Fix test issues for several IRQL checks. --- .../IrqlTooHigh/IrqlTooHigh.sarif | 108 +++++------------- .../experimental/IrqlTooLow/IrqlTooLow.sarif | 76 ++++-------- src/drivers/libraries/Irql.qll | 23 ++-- .../test/build_create_analyze_test.cmd | 4 +- 4 files changed, 68 insertions(+), 143 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif index 9a8ca16f..52a2f7a3 100644 --- a/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif +++ b/src/drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.sarif @@ -27,7 +27,7 @@ "id" : "cpp/drivers/irql-too-high", "name" : "cpp/drivers/irql-too-high", "shortDescription" : { - "text" : "IRQL too low (C28120)" + "text" : "IRQL too high (C28120)" }, "fullDescription" : { "text" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements." @@ -41,22 +41,24 @@ "description" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.", "feature.area" : "Multiple", "id" : "cpp/drivers/irql-too-high", - "impact" : "Insecure Coding Practice", + "impact" : "Exploitable Design", "kind" : "problem", - "name" : "IRQL too low (C28120)", + "name" : "IRQL too high (C28120)", + "opaqueid" : "CQLD-C28120", "owner.email" : "sdat@microsoft.com", "platform" : "Desktop", "precision" : "medium", "problem.severity" : "warning", - "query-version" : "v1", - "repro.text" : "A function annotated with IRQL requirements was called at an IRQL too high for the requirements.", + "query-version" : "v2", + "repro.text" : "The following function call is taking place at an IRQL too high for what the call target is annotated as.", + "scope" : "domainspecific", "security.severity" : "Low" } } ] }, "extensions" : [ { "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.2.0+564d095a856d34a82d25fe14755646b9db824593", + "semanticVersion" : "0.2.0+4842fd4116871d3b47eede85c2c4497b43c34d57", "locations" : [ { "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", "description" : { @@ -75,9 +77,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "driver/fail_driver1.c", + "uri" : "driver/driver_snippet.c", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 0 } } } ], @@ -98,9 +100,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "driver/driver_snippet.c", + "uri" : "driver/fail_driver1.c", "uriBaseId" : "%SRCROOT%", - "index" : 0 + "index" : 1 } } } ], @@ -170,7 +172,7 @@ "index" : 0 }, "message" : { - "text" : "IRQL potentially too high at this call ([TestInner2](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)" + "text" : "[TestInner1](1): IRQL potentially too high at call to [TestInner2](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2" }, "locations" : [ { "physicalLocation" : { @@ -199,13 +201,13 @@ "index" : 0 }, "region" : { - "startLine" : 42, - "startColumn" : 12, - "endColumn" : 22 + "startLine" : 41, + "startColumn" : 10, + "endColumn" : 20 } }, "message" : { - "text" : "TestInner2" + "text" : "TestInner1" } }, { "id" : 2, @@ -222,24 +224,7 @@ } }, "message" : { - "text" : "1" - } - }, { - "id" : 3, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 42, - "startColumn" : 5, - "endColumn" : 25 - } - }, - "message" : { - "text" : "2" + "text" : "TestInner2" } } ] }, { @@ -250,7 +235,7 @@ "index" : 0 }, "message" : { - "text" : "IRQL potentially too high at this call ([TestInner4](1)). Maximum irql level of this call: [0](2), Irql level at preceding node: [2](3)" + "text" : "[TestInner2](1): IRQL potentially too high at call to [TestInner4](2). Maximum IRQL for this call: 0, IRQL at preceding node: 2" }, "locations" : [ { "physicalLocation" : { @@ -279,13 +264,13 @@ "index" : 0 }, "region" : { - "startLine" : 36, - "startColumn" : 14, - "endColumn" : 24 + "startLine" : 26, + "startColumn" : 10, + "endColumn" : 20 } }, "message" : { - "text" : "TestInner4" + "text" : "TestInner2" } }, { "id" : 2, @@ -302,24 +287,7 @@ } }, "message" : { - "text" : "0" - } - }, { - "id" : 3, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 36, - "startColumn" : 5, - "endColumn" : 27 - } - }, - "message" : { - "text" : "2" + "text" : "TestInner4" } } ] }, { @@ -330,7 +298,7 @@ "index" : 0 }, "message" : { - "text" : "IRQL potentially too high at this call ([IoGetInitialStack](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)" + "text" : "[DpcForIsrRoutine](1): IRQL potentially too high at call to [IoGetInitialStack](2). Maximum IRQL for this call: 1, IRQL at preceding node: 2" }, "locations" : [ { "physicalLocation" : { @@ -359,13 +327,12 @@ "index" : 1 }, "region" : { - "startLine" : 366, - "startColumn" : 5, - "endColumn" : 22 + "startLine" : 347, + "endColumn" : 17 } }, "message" : { - "text" : "IoGetInitialStack" + "text" : "DpcForIsrRoutine" } }, { "id" : 2, @@ -382,24 +349,7 @@ } }, "message" : { - "text" : "1" - } - }, { - "id" : 3, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/fail_driver1.c", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - }, - "region" : { - "startLine" : 366, - "startColumn" : 5, - "endColumn" : 25 - } - }, - "message" : { - "text" : "2" + "text" : "IoGetInitialStack" } } ] } ], diff --git a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif index 026d716e..3c5d989e 100644 --- a/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif +++ b/src/drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.sarif @@ -41,22 +41,24 @@ "description" : "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.", "feature.area" : "Multiple", "id" : "cpp/drivers/irql-too-low", - "impact" : "Insecure Coding Practice", + "impact" : "Exploitable Design", "kind" : "problem", "name" : "IRQL too low (C28121)", + "opaqueid" : "CQLD-C28121", "owner.email" : "sdat@microsoft.com", "platform" : "Desktop", "precision" : "medium", "problem.severity" : "warning", - "query-version" : "v1", - "repro.text" : "A function annotated with IRQL requirements was called at an IRQL too low for the requirements.", + "query-version" : "v2", + "repro.text" : "The following function call is taking place at an IRQL too low for what the call target is annotated as.", + "scope" : "domainspecific", "security.severity" : "Low" } } ] }, "extensions" : [ { "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.2.0+564d095a856d34a82d25fe14755646b9db824593", + "semanticVersion" : "0.2.0+4842fd4116871d3b47eede85c2c4497b43c34d57", "locations" : [ { "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", "description" : { @@ -75,9 +77,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "driver/driver_snippet.c", + "uri" : "driver/fail_driver1.c", "uriBaseId" : "%SRCROOT%", - "index" : 0 + "index" : 1 } } } ], @@ -98,9 +100,9 @@ "locations" : [ { "physicalLocation" : { "artifactLocation" : { - "uri" : "driver/fail_driver1.c", + "uri" : "driver/driver_snippet.c", "uriBaseId" : "%SRCROOT%", - "index" : 1 + "index" : 0 } } } ], @@ -170,7 +172,7 @@ "index" : 0 }, "message" : { - "text" : "IRQL potentially too low at this call ([TestInner2](1)). Minimum irql level of this call: [1](2), Irql level at preceding node: [0](3)" + "text" : "[TestInner1](1): IRQL potentially too low at call to [TestInner2](2). Minimum IRQL for this call: 1, IRQL at preceding node: 0" }, "locations" : [ { "physicalLocation" : { @@ -199,13 +201,13 @@ "index" : 0 }, "region" : { - "startLine" : 41, - "startColumn" : 12, - "endColumn" : 22 + "startLine" : 40, + "startColumn" : 10, + "endColumn" : 20 } }, "message" : { - "text" : "TestInner2" + "text" : "TestInner1" } }, { "id" : 2, @@ -222,24 +224,7 @@ } }, "message" : { - "text" : "1" - } - }, { - "id" : 3, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 41, - "startColumn" : 5, - "endColumn" : 25 - } - }, - "message" : { - "text" : "0" + "text" : "TestInner2" } } ] }, { @@ -250,7 +235,7 @@ "index" : 0 }, "message" : { - "text" : "IRQL potentially too low at this call ([TestInner3](1)). Minimum irql level of this call: [2](2), Irql level at preceding node: [0](3)" + "text" : "[someFunc](1): IRQL potentially too low at call to [TestInner3](2). Minimum IRQL for this call: 2, IRQL at preceding node: 0" }, "locations" : [ { "physicalLocation" : { @@ -279,13 +264,13 @@ "index" : 0 }, "region" : { - "startLine" : 21, - "startColumn" : 12, - "endColumn" : 22 + "startLine" : 20, + "startColumn" : 10, + "endColumn" : 18 } }, "message" : { - "text" : "TestInner3" + "text" : "someFunc" } }, { "id" : 2, @@ -302,24 +287,7 @@ } }, "message" : { - "text" : "2" - } - }, { - "id" : 3, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 21, - "startColumn" : 5, - "endColumn" : 25 - } - }, - "message" : { - "text" : "0" + "text" : "TestInner3" } } ] } ], diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 10dbb80b..4896e677 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -68,13 +68,20 @@ class IrqlFunctionAnnotation extends SALAnnotation { string irqlAnnotationName; IrqlFunctionAnnotation() { - this.getMacroName() - .matches([ - "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", - "_IRQL_saves_", "_IRQL_always_function_max_", "IRQL_always_function_min_" - ]) and - irqlAnnotationName = this.getMacroName() and - irqlLevel = this.getUnexpandedArgument(0) + ( + this.getMacroName() + .matches([ + "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", + "_IRQL_always_function_max_", "IRQL_always_function_min_" + ]) and + irqlLevel = this.getUnexpandedArgument(0) + or + // Special case: _IRQL_saves_ annotations can apply to a whole function, + // but do not have an associated IRQL value. + this.getMacroName().matches("_IRQL_saves_") and + irqlLevel = "NA_IRQL_SAVES" + ) and + irqlAnnotationName = this.getMacroName() } /** Returns the raw text of the IRQL value used in this annotation. */ @@ -545,8 +552,8 @@ private predicate exprsMatchText(Expr e1, Expr e2) { * * Not implemented: _IRQL_limited_to_ */ -cached pragma[assume_small_delta] +cached int getPotentialExitIrqlAtCfn(ControlFlowNode cfn) { if cfn instanceof KeRaiseIrqlCall then result = cfn.(KeRaiseIrqlCall).getIrqlLevel() diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index c62f32f9..e471e9c7 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -7,8 +7,8 @@ call :test NoPagingSegment WDMTestTemplate wdm queries call :test OpaqueMdlUse WDMTestTemplate wdm queries call :test OpaqueMdlWrite WDMTestTemplate wdm queries call :test KeWaitLocal WDMTestTemplate wdm queries -call :test IrqlTooHigh WDMTestTemplate wdm queries\experimental -call :test IrqlTooLow WDMTestTemplate wdm queries\experimental +call :test IrqlTooHigh WDMTestTemplate general queries\experimental +call :test IrqlTooLow WDMTestTemplate general queries\experimental call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries call :test ExtendedDeprecatedApis WDMTestTemplate general queries call :test WdkDeprecatedApis WDMTestTemplate general queries From 23ec263b39ae7abb4ebe18f42ec1c25c7410b5b8 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Tue, 10 Oct 2023 16:19:49 -0700 Subject: [PATCH 20/54] WIP unit tests for IrqlSetTooHigh and IrqlSetTooLow queries --- .../test/build_create_analyze_test.cmd | 52 ++++++++-------- src/drivers/test/diff/ExaminedValue.sarif | 46 ++++++++------ .../test/diff/IllegalFieldAccess.sarif | 51 ++++++++++------ .../test/diff/IllegalFieldAccess2.sarif | 61 +++++++++++++------ src/drivers/test/diff/IllegalFieldWrite.sarif | 61 +++++++++++++------ src/drivers/test/diff/IrqlNotSaved.sarif | 51 ++++++++++------ src/drivers/test/diff/IrqlNotUsed.sarif | 51 ++++++++++------ src/drivers/test/diff/IrqlSetTooHigh.sarif | 21 +++++++ src/drivers/test/diff/IrqlSetTooLow.sarif | 21 +++++++ src/drivers/test/diff/IrqlTooHigh.sarif | 56 +++++++++++------ src/drivers/test/diff/IrqlTooLow.sarif | 51 ++++++++++------ src/drivers/test/diff/KeWaitLocal.sarif | 51 ++++++++++------ src/drivers/test/diff/MultiplePagedCode.sarif | 46 ++++++++------ src/drivers/test/diff/NoPagedCode.sarif | 46 ++++++++------ src/drivers/test/diff/NoPagingSegment.sarif | 46 ++++++++------ src/drivers/test/diff/OpaqueMdlUse.sarif | 40 ++++++------ src/drivers/test/diff/OpaqueMdlWrite.sarif | 46 ++++++++------ .../test/diff/PendingStatusError.sarif | 40 ++++++------ src/drivers/test/diff/StrSafe.sarif | 46 ++++++++------ .../diff/WrongDispatchTableAssignment.sarif | 56 +++++++++++------ 20 files changed, 574 insertions(+), 365 deletions(-) create mode 100644 src/drivers/test/diff/IrqlSetTooHigh.sarif create mode 100644 src/drivers/test/diff/IrqlSetTooLow.sarif diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index c62f32f9..c60bd131 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -1,28 +1,30 @@ -call :test PendingStatusError WDMTestTemplate wdm queries -call :test ExaminedValue WDMTestTemplate wdm queries -call :test StrSafe KMDFTestTemplate kmdf queries -call :test MultiplePagedCode WDMTestTemplate wdm queries -call :test NoPagedCode WDMTestTemplate wdm queries -call :test NoPagingSegment WDMTestTemplate wdm queries -call :test OpaqueMdlUse WDMTestTemplate wdm queries -call :test OpaqueMdlWrite WDMTestTemplate wdm queries -call :test KeWaitLocal WDMTestTemplate wdm queries -call :test IrqlTooHigh WDMTestTemplate wdm queries\experimental -call :test IrqlTooLow WDMTestTemplate wdm queries\experimental -call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -call :test ExtendedDeprecatedApis WDMTestTemplate general queries -call :test WdkDeprecatedApis WDMTestTemplate general queries -call :test IllegalFieldAccess WDMTestTemplate wdm queries -call :test PoolTagIntegral WDMTestTemplate general queries -call :test ObReferenceMode WDMTestTemplate wdm queries -call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -call :test DefaultPoolTag WDMTestTemplate general queries -call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -call :test InitNotCleared WDMTestTemplate wdm queries -call :test IrqlNotUsed WDMTestTemplate general queries -call :test IrqlNotSaved WDMTestTemplate general queries -call :test IllegalFieldWrite WDMTestTemplate wdm queries -call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +@REM call :test PendingStatusError WDMTestTemplate wdm queries +@REM call :test ExaminedValue WDMTestTemplate wdm queries +@REM call :test StrSafe KMDFTestTemplate kmdf queries +@REM call :test MultiplePagedCode WDMTestTemplate wdm queries +@REM call :test NoPagedCode WDMTestTemplate wdm queries +@REM call :test NoPagingSegment WDMTestTemplate wdm queries +@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries +@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries +@REM call :test KeWaitLocal WDMTestTemplate wdm queries +@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental +@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental +call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental +@REM call :test IrqlSetTooLow WDMTestTemplate general queries\experimental +@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries +@REM call :test WdkDeprecatedApis WDMTestTemplate general queries +@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries +@REM call :test PoolTagIntegral WDMTestTemplate general queries +@REM call :test ObReferenceMode WDMTestTemplate wdm queries +@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +@REM call :test DefaultPoolTag WDMTestTemplate general queries +@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +@REM call :test InitNotCleared WDMTestTemplate wdm queries +@REM call :test IrqlNotUsed WDMTestTemplate general queries +@REM call :test IrqlNotSaved WDMTestTemplate general queries +@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries +@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 diff --git a/src/drivers/test/diff/ExaminedValue.sarif b/src/drivers/test/diff/ExaminedValue.sarif index dea8275e..3c23aa49 100644 --- a/src/drivers/test/diff/ExaminedValue.sarif +++ b/src/drivers/test/diff/ExaminedValue.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/examined-value Result of call to func2 is ignored; 77% of calls to this function have their result checked. Checked return values = 7 total calls = 9", + 2, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldAccess.sarif b/src/drivers/test/diff/IllegalFieldAccess.sarif index dea8275e..8c5dc8d0 100644 --- a/src/drivers/test/diff/IllegalFieldAccess.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess.sarif @@ -1,21 +1,32 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/illegal-field-access An assignment to an IO DPC or one of its fields has been made directly. It should be made by IoInitializeDpcRequest.", + 2, + 0 + ], + [ + "cpp/drivers/illegal-field-access An assignment to an IRP CancelRoutine field was made directly. It should be made by IoSetCancelRoutine.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldAccess2.sarif b/src/drivers/test/diff/IllegalFieldAccess2.sarif index dea8275e..5649b882 100644 --- a/src/drivers/test/diff/IllegalFieldAccess2.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess2.sarif @@ -1,21 +1,42 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 4 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 4, + "codes": [ + [ + "cpp/drivers/illegal-field-access-2 The 'Flags' field of the DriverObject struct cannot be accessed by a driver.", + 2, + 0 + ], + [ + "cpp/drivers/illegal-field-access-2 The 'NextDevice' field of the DeviceObject struct can only be accessed in DriverEntry or DriverUnload.", + 1, + 0 + ], + [ + "cpp/drivers/illegal-field-access-2 The 'Dpc' field of the DeviceObject struct cannot be accessed by a driver.", + 1, + 0 + ], + [ + "cpp/drivers/illegal-field-access-2 The 'DriverExtension' field of the DriverObject struct can only be accessed in a DriverEntry routine.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldWrite.sarif b/src/drivers/test/diff/IllegalFieldWrite.sarif index dea8275e..e7aea252 100644 --- a/src/drivers/test/diff/IllegalFieldWrite.sarif +++ b/src/drivers/test/diff/IllegalFieldWrite.sarif @@ -1,21 +1,42 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 4 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 4, + "codes": [ + [ + "cpp/drivers/illegal-field-write The 'DeviceObject' field of the DriverObject struct is read-only.", + 2, + 0 + ], + [ + "cpp/drivers/illegal-field-write The 'DriverObject' field of the DeviceObject struct is read-only.", + 2, + 0 + ], + [ + "cpp/drivers/illegal-field-write The 'NextDevice' field of the DeviceObject struct is read-only.", + 1, + 0 + ], + [ + "cpp/drivers/illegal-field-write The 'SecurityDescriptor' field of the DeviceObject struct is read-only.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlNotSaved.sarif b/src/drivers/test/diff/IrqlNotSaved.sarif index dea8275e..4b88bd8d 100644 --- a/src/drivers/test/diff/IrqlNotSaved.sarif +++ b/src/drivers/test/diff/IrqlNotSaved.sarif @@ -1,21 +1,32 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-saved The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-saved The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlNotUsed.sarif b/src/drivers/test/diff/IrqlNotUsed.sarif index dea8275e..e54b351e 100644 --- a/src/drivers/test/diff/IrqlNotUsed.sarif +++ b/src/drivers/test/diff/IrqlNotUsed.sarif @@ -1,21 +1,32 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [inIrql](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif new file mode 100644 index 00000000..8d5a80f9 --- /dev/null +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -0,0 +1,21 @@ +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } +} \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooLow.sarif b/src/drivers/test/diff/IrqlSetTooLow.sarif new file mode 100644 index 00000000..8d5a80f9 --- /dev/null +++ b/src/drivers/test/diff/IrqlSetTooLow.sarif @@ -0,0 +1,21 @@ +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } +} \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlTooHigh.sarif b/src/drivers/test/diff/IrqlTooHigh.sarif index dea8275e..d26ced59 100644 --- a/src/drivers/test/diff/IrqlTooHigh.sarif +++ b/src/drivers/test/diff/IrqlTooHigh.sarif @@ -1,21 +1,37 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 3 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 3, + "codes": [ + [ + "cpp/drivers/irql-too-high IRQL potentially too high at this call ([TestInner2](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)", + 1, + 0 + ], + [ + "cpp/drivers/irql-too-high IRQL potentially too high at this call ([TestInner4](1)). Maximum irql level of this call: [0](2), Irql level at preceding node: [2](3)", + 1, + 0 + ], + [ + "cpp/drivers/irql-too-high IRQL potentially too high at this call ([IoGetInitialStack](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlTooLow.sarif b/src/drivers/test/diff/IrqlTooLow.sarif index dea8275e..1e452b32 100644 --- a/src/drivers/test/diff/IrqlTooLow.sarif +++ b/src/drivers/test/diff/IrqlTooLow.sarif @@ -1,21 +1,32 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-too-low IRQL potentially too low at this call ([TestInner2](1)). Minimum irql level of this call: [1](2), Irql level at preceding node: [0](3)", + 1, + 0 + ], + [ + "cpp/drivers/irql-too-low IRQL potentially too low at this call ([TestInner3](1)). Minimum irql level of this call: [2](2), Irql level at preceding node: [0](3)", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/KeWaitLocal.sarif b/src/drivers/test/diff/KeWaitLocal.sarif index dea8275e..b0674846 100644 --- a/src/drivers/test/diff/KeWaitLocal.sarif +++ b/src/drivers/test/diff/KeWaitLocal.sarif @@ -1,21 +1,32 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 1, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 1, + "-": 1, + "codes": [ + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode [good_use](1): KeWaitForSingleObject should have a KernelMode AccessMode when the [first argument](2) is local", + 0, + 1 + ], + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode KeWaitForSingleObject should have a KernelMode AccessMode when the first argument is local", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/MultiplePagedCode.sarif b/src/drivers/test/diff/MultiplePagedCode.sarif index dea8275e..d84a3a59 100644 --- a/src/drivers/test/diff/MultiplePagedCode.sarif +++ b/src/drivers/test/diff/MultiplePagedCode.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/multiple-paged-code Functions in a paged section must have exactly one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/NoPagedCode.sarif b/src/drivers/test/diff/NoPagedCode.sarif index dea8275e..e317c641 100644 --- a/src/drivers/test/diff/NoPagedCode.sarif +++ b/src/drivers/test/diff/NoPagedCode.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/no-paged-code The function has been declared to be in a paged segment, but neither PAGED_CODE nor PAGED_CODE_LOCKED was found.", + 3, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/NoPagingSegment.sarif b/src/drivers/test/diff/NoPagingSegment.sarif index dea8275e..6ef2c1d4 100644 --- a/src/drivers/test/diff/NoPagingSegment.sarif +++ b/src/drivers/test/diff/NoPagingSegment.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/no-paged-code The function has PAGED_CODE or PAGED_CODE_LOCKED but is not declared to be in a paged segment", + 2, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/OpaqueMdlUse.sarif b/src/drivers/test/diff/OpaqueMdlUse.sarif index dea8275e..8d5a80f9 100644 --- a/src/drivers/test/diff/OpaqueMdlUse.sarif +++ b/src/drivers/test/diff/OpaqueMdlUse.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/OpaqueMdlWrite.sarif b/src/drivers/test/diff/OpaqueMdlWrite.sarif index dea8275e..acae8d46 100644 --- a/src/drivers/test/diff/OpaqueMdlWrite.sarif +++ b/src/drivers/test/diff/OpaqueMdlWrite.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/opaque-mdl-write The driver is writing to an opaque MDL field (ByteCount). MDLs are semi-opaque and opaque fields should not be modified.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/PendingStatusError.sarif b/src/drivers/test/diff/PendingStatusError.sarif index dea8275e..8d5a80f9 100644 --- a/src/drivers/test/diff/PendingStatusError.sarif +++ b/src/drivers/test/diff/PendingStatusError.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/StrSafe.sarif b/src/drivers/test/diff/StrSafe.sarif index dea8275e..08ebd237 100644 --- a/src/drivers/test/diff/StrSafe.sarif +++ b/src/drivers/test/diff/StrSafe.sarif @@ -1,21 +1,27 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 1, + "codes": [ + [ + "cpp/drivers/str-safe Kernel Mode drivers should use ntstrsafe.h, not strsafe.h. Found in source file", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif index dea8275e..7b0d7fc4 100644 --- a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif +++ b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif @@ -1,21 +1,37 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 3 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 3, + "codes": [ + [ + "cpp/drivers/wrong-dispatch-table-assignment The dispatch function does not have a dispatch type annotation matching this dispatch table entry.", + 1, + 0 + ], + [ + "cpp/drivers/wrong-dispatch-table-assignment Dispatch table assignment should have a DRIVER_DISPATCH type routine as its right-hand side value.", + 1, + 0 + ], + [ + "cpp/drivers/wrong-dispatch-table-assignment The dispatch function does not have a dispatch type annotation.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file From b8256c922e111c0b03a666b712c014bcf46fcadd Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Tue, 10 Oct 2023 16:20:11 -0700 Subject: [PATCH 21/54] WIP unit tests for IrqlSetTooHigh and IrqlSetTooLow queries --- .../IrqlSetTooHigh/IrqlSetTooHigh.ql | 1 + .../IrqlSetTooHigh/IrqlSetTooHigh.sarif | 173 ++++++++++++++++++ .../IrqlSetTooHigh/driver_snippet.c | 66 +++++++ .../IrqlSetTooLow/IrqlSetTooLow.sarif | 21 +++ .../IrqlSetTooLow/driver_snippet.c | 8 + 5 files changed, 269 insertions(+) create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif create mode 100644 src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql index 1a26247e..b726f1b7 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -23,6 +23,7 @@ import cpp import drivers.libraries.Irql + from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement where statement.getControlFlowScope() = irqlFunc and diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif new file mode 100644 index 00000000..5e46fa5e --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif @@ -0,0 +1,173 @@ +{ + "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", + "version" : "2.1.0", + "runs" : [ { + "tool" : { + "driver" : { + "name" : "CodeQL", + "organization" : "GitHub", + "semanticVersion" : "2.14.6", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], + "rules" : [ { + "id" : "cpp/drivers/irql-set-too-high", + "name" : "cpp/drivers/irql-set-too-high", + "shortDescription" : { + "text" : "IRQL set too high (C28150)" + }, + "fullDescription" : { + "text" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "properties" : { + "tags" : [ "correctness", "wddst" ], + "description" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount.", + "feature.area" : "Multiple", + "id" : "cpp/drivers/irql-set-too-high", + "impact" : "Exploitable Design", + "kind" : "problem", + "name" : "IRQL set too high (C28150)", + "opaqueid" : "CQLD-C28150", + "owner.email" : "sdat@microsoft.com", + "platform" : "Desktop", + "precision" : "medium", + "problem.severity" : "warning", + "query-version" : "v2", + "repro.text" : "The following statement exits at an IRQL too high for the function it is contained in.", + "scope" : "domainspecific", + "security.severity" : "Low" + } + } ] + }, + "extensions" : [ { + "name" : "microsoft/windows-drivers", + "semanticVersion" : "0.2.0+bb06b891b948b1c3e773bdaaf23a43895efe761c", + "locations" : [ { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", + "description" : { + "text" : "The QL pack root directory." + } + }, { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", + "description" : { + "text" : "The QL pack definition file." + } + } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], + "artifacts" : [ { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + }, { + "location" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } ], + "results" : [ ], + "columnKind" : "utf16CodeUnits", + "properties" : { + "semmle.formatSpecifier" : "sarifv2.1.0" + } + } ] + } \ No newline at end of file diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c new file mode 100644 index 00000000..c1112a28 --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +// driver_snippet.c +// + + +#define SET_DISPATCH 1 + + +// Template. Not called in this test. +void top_level_call() {} + + +#include +/* +IRQL values: +PASSIVE_LEVEL +APC_LEVEL +DISPATCH_LEVEL +DIRQL +*/ + +/* +_IRQL_requires_max_(irql) //The irql is the maximum IRQL at which the function can be called. +_IRQL_requires_min_(irql) //The irql is the minimum IRQL at which the function can be called. +_IRQL_requires_(irql) //The function must be entered at the IRQL specified by irql. +_IRQL_raises_(irql) //The function exits at the specified irql, but it can only be called to raise (not lower) the current IRQL. +_IRQL_saves_ //The annotated parameter saves the current IRQL to restore later. +_IRQL_restores_ //The annotated parameter contains an IRQL value from IRQL_saves that is to be restored when the function returns. +_IRQL_saves_global_(kind, param) //The current IRQL is saved into a location that is internal to the code analysis tools from which the IRQL is to be restored. This annotation is used to annotate a function. The location is identified by kind and further refined by param. For example, OldIrql could be the kind, and FastMutex could be the parameter that held that old IRQL value. +_IRQL_restores_global_(kind, param) //The IRQL saved by the function annotated with IRQL_saves_global is restored from a location that is internal to the Code Analysis tools. +_IRQL_always_function_min_(value) //The IRQL value is the minimum value to which the function can lower the IRQL. +_IRQL_always_function_max_(value) //The IRQL value is the maximum value to which the function can raise the IRQL. +_IRQL_requires_same_ //The annotated function must enter and exit at the same IRQL. The function can change the IRQL, but it must restore the IRQL to its original value before exiting. +_IRQL_uses_cancel_ //The annotated parameter is the IRQL value that should be restored by a DRIVER_CANCEL callback function. In most cases, use the IRQL_is_cancel annotation instead. +*/ + + + + + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID IrqlSetLower_fail(void){ + __noop; +} + + +VOID CallLowerIRQLFunction(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + IrqlSetLower_fail(); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID IrqlRaiseLevelExplicit_fail1(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +_IRQL_raises_(PASSIVE_LEVEL) +VOID IrqlRaiseLevelImplicit(void){ +//TODO +} \ No newline at end of file diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif new file mode 100644 index 00000000..8d5a80f9 --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif @@ -0,0 +1,21 @@ +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } +} \ No newline at end of file diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c new file mode 100644 index 00000000..e2555541 --- /dev/null +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +// driver_snippet.c +// + +#define SET_DISPATCH 1 +void top_level_call() {} From ed5d9d5619a65f504b57979b821e3e5eb657ca3f Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 08:46:29 -0700 Subject: [PATCH 22/54] WIP more tests and comments --- .../IrqlSetTooHigh/driver_snippet.c | 83 +++++++++++++++++-- .../test/build_create_analyze_test.cmd | 5 ++ src/drivers/test/diff/IrqlSetTooHigh.sarif | 32 ++++++- 3 files changed, 111 insertions(+), 9 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index c1112a28..94d7776c 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -39,28 +39,99 @@ _IRQL_uses_cancel_ //The annotated parameter is the IRQL value t - +/* +Function which should only be called from PASSIVE_LEVEL +*/ _IRQL_requires_max_(PASSIVE_LEVEL) -VOID IrqlSetLower_fail(void){ +VOID DoNothing_Passive(void){ __noop; } +/* +Function which should only be called from DISPATCH_LEVEL +*/ +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID DoNothing_Dispatch(void){ + __noop; +} -VOID CallLowerIRQLFunction(void){ +/* +Function which should only be called from PASSIVE_LEVEL but raises the IRQL to DISPATCH_LEVEL +*/ +_IRQL_raises_(PASSIVE_LEVEL) +VOID IrqlSetHigherFromPassive(void){ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - IrqlSetLower_fail(); } +/* +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from PASSIVE_LEVEL +*/ _IRQL_requires_max_(PASSIVE_LEVEL) VOID IrqlRaiseLevelExplicit_fail1(void){ + // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_Passive(); } +/* +Function is entered at PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. +This is allowed because _IRQL_raises_(PASSIVE_LEVEL) specifies that the function can only be called to raise (not lower) the current IRQL of PASSIVE_LEVEL. +*/ _IRQL_raises_(PASSIVE_LEVEL) -VOID IrqlRaiseLevelImplicit(void){ -//TODO +VOID IrqlRaiseLevelExplicit_pass(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Function specifies it must be called with max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CallFunctionThatRaisesIRQL_fail(void){ + IrqlSetHigherFromPassive(); +} + +/* +Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) +VOID IrqlRaiseLevelExplicit_fail2(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) +VOID IrqlRaiseLevelExplicit_pass(void){ + DoNothing_Passive(); +} + +/* +Function must enter and exit at the same IRQL, but raises and does not lower the IRQL +*/ +_IRQL_requires_same_(PASSIVE_LEVEL) +VOID IrqlRequiresSame_fail(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. +*/ +_IRQL_requires_same_(PASSIVE_LEVEL) +VOID IrqlRequiresSame_pass(void){ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + KeLowerIrql(oldIRQL); } \ No newline at end of file diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index c60bd131..b41aa0d1 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -1,3 +1,8 @@ +rd /s /q working >NUL 2>&1 +rd /s /q TestDB >NUL 2>&1 +rd /s /q AnalysisFiles >NUL 2>&1 + + @REM call :test PendingStatusError WDMTestTemplate wdm queries @REM call :test ExaminedValue WDMTestTemplate wdm queries @REM call :test StrSafe KMDFTestTemplate kmdf queries diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index 8d5a80f9..4996594a 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 0, + "+": 5, "-": 0 }, "error": { @@ -9,9 +9,35 @@ "codes": [] }, "warning": { - "+": 0, + "+": 5, "-": 0, - "codes": [] + "codes": [ + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [IrqlRaiseLevelImplicit](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ] + ] }, "note": { "+": 0, From 48a157a8341c0a49637d26a16613b12f136696f2 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 08:55:30 -0700 Subject: [PATCH 23/54] bug fixes --- .../IrqlSetTooHigh/driver_snippet.c | 6 +- src/drivers/test/diff/IrqlSetTooHigh.sarif | 64 +++++++++++++++++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 94d7776c..51583684 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -111,14 +111,14 @@ VOID IrqlRaiseLevelExplicit_fail2(void){ Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL */ _IRQL_always_function_max_(PASSIVE_LEVEL) -VOID IrqlRaiseLevelExplicit_pass(void){ +VOID IrqlDontChange_pass(void){ DoNothing_Passive(); } /* Function must enter and exit at the same IRQL, but raises and does not lower the IRQL */ -_IRQL_requires_same_(PASSIVE_LEVEL) +_IRQL_requires_same_ VOID IrqlRequiresSame_fail(void){ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); @@ -128,7 +128,7 @@ VOID IrqlRequiresSame_fail(void){ /* Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. */ -_IRQL_requires_same_(PASSIVE_LEVEL) +_IRQL_requires_same_ VOID IrqlRequiresSame_pass(void){ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index 4996594a..b2853d62 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 5, + "+": 15, "-": 0 }, "error": { @@ -9,31 +9,81 @@ "codes": [] }, "warning": { - "+": 5, + "+": 15, "-": 0, "codes": [ [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [IrqlRaiseLevelImplicit](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail2](1). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelImplicit](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [IrqlSetHigherFromPassive](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_pass](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlSetHigherFromPassive](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlSetHigherFromPassive](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ] From 671cd9c3c188fa32aaa9e41a6e3fbad0a1eaeb5f Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 10:55:04 -0700 Subject: [PATCH 24/54] WIP updates to tests --- .../IrqlSetTooHigh/driver_snippet.c | 123 +++++++++++++---- .../IrqlSetTooLow/driver_snippet.c | 130 ++++++++++++++++++ src/drivers/test/diff/IrqlSetTooHigh.sarif | 34 ++++- 3 files changed, 256 insertions(+), 31 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 51583684..1a65d405 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -4,17 +4,14 @@ // driver_snippet.c // - #define SET_DISPATCH 1 - // Template. Not called in this test. void top_level_call() {} - #include /* -IRQL values: +IRQL values: PASSIVE_LEVEL APC_LEVEL DISPATCH_LEVEL @@ -36,46 +33,103 @@ _IRQL_requires_same_ //The annotated function must enter and exit at _IRQL_uses_cancel_ //The annotated parameter is the IRQL value that should be restored by a DRIVER_CANCEL callback function. In most cases, use the IRQL_is_cancel annotation instead. */ +/* +Function which should only be called from PASSIVE_LEVEL +*/ +_IRQL_requires_max_(APC_LEVEL) + VOID DoNothing_MaxPassive(void) +{ + __noop; +} - +/* +Function which should only be called from DISPATCH_LEVEL +*/ +_IRQL_requires_max_(DISPATCH_LEVEL) + VOID DoNothing_MaxDispatch(void) +{ + __noop; +} /* Function which should only be called from PASSIVE_LEVEL */ -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID DoNothing_Passive(void){ - __noop; +_IRQL_requires_(PASSIVE_LEVEL) + VOID DoNothing_RequiresPassive(void) +{ + __noop; } /* Function which should only be called from DISPATCH_LEVEL */ -_IRQL_requires_max_(DISPATCH_LEVEL) -VOID DoNothing_Dispatch(void){ - __noop; +_IRQL_requires_(DISPATCH_LEVEL) + VOID DoNothing_RequiresDispatch(void) +{ + __noop; } + /* Function which should only be called from PASSIVE_LEVEL but raises the IRQL to DISPATCH_LEVEL */ _IRQL_raises_(PASSIVE_LEVEL) -VOID IrqlSetHigherFromPassive(void){ + VOID IrqlSetHigherFromPassive(void) +{ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } +/* +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +*/ +VOID IrqlRaiseLevelExplicit_fail1(void) +{ + // Set IRQL to DISPATCH_LEVEL + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_MaxPassive(); +} + +/* +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +*/ +VOID IrqlRaiseLevelExplicit_pass1(void) +{ + // Set IRQL to DISPATCH_LEVEL + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_MaxDispatch(); +} +/* +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +*/ +VOID IrqlRaiseLevelExplicit_pass2(void) +{ + // Set IRQL to DISPATCH_LEVEL + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(APC_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_MaxDispatch(); +} + /* Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from PASSIVE_LEVEL */ -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID IrqlRaiseLevelExplicit_fail1(void){ +VOID IrqlRaiseLevelExplicit_fail2(void) +{ // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_Passive(); + DoNothing_RequiresPassive(); } /* @@ -83,7 +137,8 @@ Function is entered at PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. This is allowed because _IRQL_raises_(PASSIVE_LEVEL) specifies that the function can only be called to raise (not lower) the current IRQL of PASSIVE_LEVEL. */ _IRQL_raises_(PASSIVE_LEVEL) -VOID IrqlRaiseLevelExplicit_pass(void){ + VOID IrqlRaiseLevelExplicit_pass(void) +{ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); @@ -92,8 +147,9 @@ VOID IrqlRaiseLevelExplicit_pass(void){ /* Function specifies it must be called with max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. */ -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID CallFunctionThatRaisesIRQL_fail(void){ +_IRQL_requires_max_(PASSIVE_LEVEL) + VOID CallFunctionThatRaisesIRQL_fail(void) +{ IrqlSetHigherFromPassive(); } @@ -101,25 +157,42 @@ VOID CallFunctionThatRaisesIRQL_fail(void){ Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL */ _IRQL_always_function_max_(PASSIVE_LEVEL) -VOID IrqlRaiseLevelExplicit_fail2(void){ + VOID IrqlRaiseLevelExplicit_fail3(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} +/* +Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL and then lowers it. Desipite lowering the IRQL, the function is still annotated for max IRQL PASSIVE_LEVEL +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) + VOID IrqlRaiseLevelExplicit_fail4(void) +{ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + KeLowerIrql(oldIRQL); } -/* + +/* Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL */ _IRQL_always_function_max_(PASSIVE_LEVEL) -VOID IrqlDontChange_pass(void){ - DoNothing_Passive(); + VOID IrqlDontChange_pass(void) +{ + DoNothing_MaxPassive(); } + /* Function must enter and exit at the same IRQL, but raises and does not lower the IRQL */ _IRQL_requires_same_ -VOID IrqlRequiresSame_fail(void){ + VOID + IrqlRequiresSame_fail(void) +{ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); @@ -129,7 +202,9 @@ VOID IrqlRequiresSame_fail(void){ Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. */ _IRQL_requires_same_ -VOID IrqlRequiresSame_pass(void){ + VOID + IrqlRequiresSame_pass(void) +{ KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c index e2555541..15d6cd28 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -5,4 +5,134 @@ // #define SET_DISPATCH 1 + +// Template. Not called in this test. void top_level_call() {} + +#include +/* +IRQL values: +PASSIVE_LEVEL +APC_LEVEL +DISPATCH_LEVEL +DIRQL +*/ + +/* +_IRQL_requires_max_(irql) //The irql is the maximum IRQL at which the function can be called. +_IRQL_requires_min_(irql) //The irql is the minimum IRQL at which the function can be called. +_IRQL_requires_(irql) //The function must be entered at the IRQL specified by irql. +_IRQL_raises_(irql) //The function exits at the specified irql, but it can only be called to raise (not lower) the current IRQL. +_IRQL_saves_ //The annotated parameter saves the current IRQL to restore later. +_IRQL_restores_ //The annotated parameter contains an IRQL value from IRQL_saves that is to be restored when the function returns. +_IRQL_saves_global_(kind, param) //The current IRQL is saved into a location that is internal to the code analysis tools from which the IRQL is to be restored. This annotation is used to annotate a function. The location is identified by kind and further refined by param. For example, OldIrql could be the kind, and FastMutex could be the parameter that held that old IRQL value. +_IRQL_restores_global_(kind, param) //The IRQL saved by the function annotated with IRQL_saves_global is restored from a location that is internal to the Code Analysis tools. +_IRQL_always_function_min_(value) //The IRQL value is the minimum value to which the function can lower the IRQL. +_IRQL_always_function_max_(value) //The IRQL value is the maximum value to which the function can raise the IRQL. +_IRQL_requires_same_ //The annotated function must enter and exit at the same IRQL. The function can change the IRQL, but it must restore the IRQL to its original value before exiting. +_IRQL_uses_cancel_ //The annotated parameter is the IRQL value that should be restored by a DRIVER_CANCEL callback function. In most cases, use the IRQL_is_cancel annotation instead. +*/ + +/* +Function which should only be called from PASSIVE_LEVEL +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) + VOID DoNothing_Passive(void) +{ + __noop; +} + +/* +Function which should only be called from DISPATCH_LEVEL +*/ +_IRQL_requires_max_(DISPATCH_LEVEL) + VOID DoNothing_Dispatch(void) +{ + __noop; +} + +/* +Function which should only be called from DISPATCH_LEVEL but lowers the IRQL to PASSIVE_LEVEL +*/ +_IRQL_requires_min_(DISPATCH_LEVEL) + VOID IrqlSetLowerFromDispatch(void) +{ + KeLowerIrql(PASSIVE_LEVEL); +} + +/* +Funciton which lowers the IRQL to PASSIVE_LEVEL and then calls a function which should only be called from DISPATCH_LEVEL +*/ +VOID IrqlRaiseLevelExplicit_fail1(void) +{ + // Set IRQL to DISPATCH_LEVEL + KeLowerIrql(PASSIVE_LEVEL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_Dispatch(); +} + +/* +Function is entered at PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. +This is allowed because _IRQL_raises_(PASSIVE_LEVEL) specifies that the function can only be called to raise (not lower) the current IRQL of PASSIVE_LEVEL. +*/ +_IRQL_raises_(PASSIVE_LEVEL) + VOID IrqlRaiseLevelExplicit_pass(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Function specifies it must be called with max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) + VOID CallFunctionThatRaisesIRQL_fail(void) +{ + IrqlSetHigherFromPassive(); +} + +/* +Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) + VOID IrqlRaiseLevelExplicit_fail2(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) + VOID IrqlDontChange_pass(void) +{ + DoNothing_Passive(); +} + +/* +Function must enter and exit at the same IRQL, but raises and does not lower the IRQL +*/ +_IRQL_requires_same_ + VOID + IrqlRequiresSame_fail(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. +*/ +_IRQL_requires_same_ + VOID + IrqlRequiresSame_pass(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + KeLowerIrql(oldIRQL); +} \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index b2853d62..a6cfa826 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 15, + "+": 19, "-": 0 }, "error": { @@ -9,31 +9,51 @@ "codes": [] }, "warning": { - "+": 15, + "+": 19, "-": 0, "codes": [ [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail2](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 2 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [ExprStmt](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail3](1). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail2](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], From a042bd8c50670f5e52265087208f24e8b966f439 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 13:13:05 -0700 Subject: [PATCH 25/54] WIP update tests --- .../IrqlSetTooHigh/driver_snippet.c | 107 ++++++++++++------ src/drivers/test/diff/IrqlSetTooHigh.sarif | 46 +++----- 2 files changed, 88 insertions(+), 65 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 1a65d405..94c5ca5c 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -34,16 +34,16 @@ _IRQL_uses_cancel_ //The annotated parameter is the IRQL value t */ /* -Function which should only be called from PASSIVE_LEVEL +Function which should only be called from max APC_LEVEL */ _IRQL_requires_max_(APC_LEVEL) - VOID DoNothing_MaxPassive(void) + VOID DoNothing_MaxAPC(void) { __noop; } /* -Function which should only be called from DISPATCH_LEVEL +Function which should only be called from max DISPATCH_LEVEL */ _IRQL_requires_max_(DISPATCH_LEVEL) VOID DoNothing_MaxDispatch(void) @@ -69,59 +69,63 @@ _IRQL_requires_(DISPATCH_LEVEL) __noop; } - -/* -Function which should only be called from PASSIVE_LEVEL but raises the IRQL to DISPATCH_LEVEL -*/ -_IRQL_raises_(PASSIVE_LEVEL) - VOID IrqlSetHigherFromPassive(void) +_IRQL_raises_(DISPATCH_LEVEL) + VOID IrqlSetHigherFromPassive_pass0(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } + /* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +Function can be called to raise the IRQL but needs to exit at DISPATCH_LEVEL. */ -VOID IrqlRaiseLevelExplicit_fail1(void) +_IRQL_raises_(DISPATCH_LEVEL) + VOID IrqlRaiseLevelExplicit_pass1(void) { - // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxPassive(); + KeRaiseIrql(APC_LEVEL, &oldIRQL); // Raise level + DoNothing_MaxDispatch(); // call function with max DISPATCH_LEVEL. This is OK since we're at APC_LEVEL and that is less than DISPATCH_LEVEL + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Raise level again + DoNothing_MaxDispatch(); // call function with max DISPATCH_LEVEL. This is OK since we're at DISPATCH_LEVEL + // Function Exits at DISPATCH_LEVEL } + + /* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +Function can be called to raise the IRQL but needs to exit at APC_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. */ -VOID IrqlRaiseLevelExplicit_pass1(void) +_IRQL_raises_(APC_LEVEL) + VOID IrqlRaiseLevelExplicit_fail0(void) { - // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxDispatch(); } + + /* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max APC_LEVEL +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should be called from *max* APC_LEVEL */ -VOID IrqlRaiseLevelExplicit_pass2(void) +// TODO Is this OK? +_IRQL_raises_(DISPATCH_LEVEL) +VOID IrqlRaiseLevelExplicit_fail1(void) { // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(APC_LEVEL, &oldIRQL); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxDispatch(); + DoNothing_MaxAPC(); } /* Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from PASSIVE_LEVEL */ +// TODO Is this OK? VOID IrqlRaiseLevelExplicit_fail2(void) { // Set IRQL to DISPATCH_LEVEL @@ -132,27 +136,33 @@ VOID IrqlRaiseLevelExplicit_fail2(void) DoNothing_RequiresPassive(); } + /* -Function is entered at PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. -This is allowed because _IRQL_raises_(PASSIVE_LEVEL) specifies that the function can only be called to raise (not lower) the current IRQL of PASSIVE_LEVEL. +Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max DISPATCH_LEVEL */ -_IRQL_raises_(PASSIVE_LEVEL) - VOID IrqlRaiseLevelExplicit_pass(void) +VOID IrqlRaiseLevelExplicit_pass3(void) { + // Set IRQL to DISPATCH_LEVEL KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_MaxDispatch(); } - /* -Function specifies it must be called with max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +Funciton which raises the IRQL to APC_LEVEL and then calls a function which should only be called from max DISPATCH_LEVEL */ -_IRQL_requires_max_(PASSIVE_LEVEL) - VOID CallFunctionThatRaisesIRQL_fail(void) +VOID IrqlRaiseLevelExplicit_pass2(void) { - IrqlSetHigherFromPassive(); + // Set IRQL to DISPATCH_LEVEL + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(APC_LEVEL, &oldIRQL); + // Call a function at a lower IRQL than DISPATCH_LEVEL + DoNothing_MaxDispatch(); } + /* Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL */ @@ -175,6 +185,25 @@ _IRQL_always_function_max_(PASSIVE_LEVEL) KeLowerIrql(oldIRQL); } +/* +Function is annotated for max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) + VOID CallFunctionThatRaisesIRQL_fail5(void) +{ + IrqlSetHigherFromPassive_pass0(); +} + +/* +Function is annotated for max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +*/ +// TODO what is the IRQL by default if not set? +_IRQL_requires_same_ + VOID CallFunctionThatRaisesIRQL_fail6(void) +{ + IrqlSetHigherFromPassive_pass0(); +} + /* Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL @@ -182,7 +211,7 @@ Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL _IRQL_always_function_max_(PASSIVE_LEVEL) VOID IrqlDontChange_pass(void) { - DoNothing_MaxPassive(); + DoNothing_MaxAPC(); } @@ -191,11 +220,11 @@ Function must enter and exit at the same IRQL, but raises and does not lower the */ _IRQL_requires_same_ VOID - IrqlRequiresSame_fail(void) + IrqlRequiresSame_fail7(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + KeRaiseIrql(oldIRQL+1, &oldIRQL); } /* @@ -209,4 +238,8 @@ _IRQL_requires_same_ oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); KeLowerIrql(oldIRQL); -} \ No newline at end of file +} + +// TODO multi-threaded tests +// function has max IRQL requirement, creates two threads where one is above that requirement and one is below +// TODO test for IRQL change with function pointer \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index a6cfa826..8dfd13e4 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 19, + "+": 17, "-": 0 }, "error": { @@ -9,7 +9,7 @@ "codes": [] }, "warning": { - "+": 19, + "+": 17, "-": 0, "codes": [ [ @@ -18,92 +18,82 @@ 2 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [CallFunctionThatRaisesIRQL_fail5](1). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [ExprStmt](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail3](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [call to IrqlSetHigherFromPassive_pass0](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [ExprStmt](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [IrqlSetHigherFromPassive](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail3](1). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_pass](1). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_pass](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail0](1). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlSetHigherFromPassive](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlSetHigherFromPassive](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 1, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, 1 ], [ - "cpp/drivers/irql-set-too-high [IrqlSetHigherFromPassive](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, 1 ] From 495add6a46df9da873730e47df30d4141832c7c4 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 13:31:50 -0700 Subject: [PATCH 26/54] remove bad tests. Fix run script to run all tests again. run script now cleans first automatically. --- .../IrqlSetTooHigh/driver_snippet.c | 44 +++++----------- .../test/build_create_analyze_test.cmd | 52 +++++++++---------- 2 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 94c5ca5c..f0b2487a 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -107,36 +107,6 @@ _IRQL_raises_(APC_LEVEL) } -/* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should be called from *max* APC_LEVEL -*/ -// TODO Is this OK? -_IRQL_raises_(DISPATCH_LEVEL) -VOID IrqlRaiseLevelExplicit_fail1(void) -{ - // Set IRQL to DISPATCH_LEVEL - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxAPC(); -} - -/* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from PASSIVE_LEVEL -*/ -// TODO Is this OK? -VOID IrqlRaiseLevelExplicit_fail2(void) -{ - // Set IRQL to DISPATCH_LEVEL - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_RequiresPassive(); -} - - /* Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max DISPATCH_LEVEL */ @@ -221,12 +191,26 @@ Function must enter and exit at the same IRQL, but raises and does not lower the _IRQL_requires_same_ VOID IrqlRequiresSame_fail7(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); +} + +/* +Function must enter and exit at the same IRQL, but raises and does not lower the IRQL +*/ +_IRQL_requires_same_ + VOID + IrqlRequiresSame_notsupported(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(oldIRQL+1, &oldIRQL); } + + /* Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. */ diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index b41aa0d1..8dd6ebd1 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -3,33 +3,33 @@ rd /s /q TestDB >NUL 2>&1 rd /s /q AnalysisFiles >NUL 2>&1 -@REM call :test PendingStatusError WDMTestTemplate wdm queries -@REM call :test ExaminedValue WDMTestTemplate wdm queries -@REM call :test StrSafe KMDFTestTemplate kmdf queries -@REM call :test MultiplePagedCode WDMTestTemplate wdm queries -@REM call :test NoPagedCode WDMTestTemplate wdm queries -@REM call :test NoPagingSegment WDMTestTemplate wdm queries -@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries -@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries -@REM call :test KeWaitLocal WDMTestTemplate wdm queries -@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental -@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental +call :test PendingStatusError WDMTestTemplate wdm queries +call :test ExaminedValue WDMTestTemplate wdm queries +call :test StrSafe KMDFTestTemplate kmdf queries +call :test MultiplePagedCode WDMTestTemplate wdm queries +call :test NoPagedCode WDMTestTemplate wdm queries +call :test NoPagingSegment WDMTestTemplate wdm queries +call :test OpaqueMdlUse WDMTestTemplate wdm queries +call :test OpaqueMdlWrite WDMTestTemplate wdm queries +call :test KeWaitLocal WDMTestTemplate wdm queries +call :test IrqlTooHigh WDMTestTemplate general queries\experimental +call :test IrqlTooLow WDMTestTemplate general queries\experimental call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental -@REM call :test IrqlSetTooLow WDMTestTemplate general queries\experimental -@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries -@REM call :test WdkDeprecatedApis WDMTestTemplate general queries -@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries -@REM call :test PoolTagIntegral WDMTestTemplate general queries -@REM call :test ObReferenceMode WDMTestTemplate wdm queries -@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -@REM call :test DefaultPoolTag WDMTestTemplate general queries -@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -@REM call :test InitNotCleared WDMTestTemplate wdm queries -@REM call :test IrqlNotUsed WDMTestTemplate general queries -@REM call :test IrqlNotSaved WDMTestTemplate general queries -@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries -@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +call :test IrqlSetTooLow WDMTestTemplate general queries\experimental +call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +call :test ExtendedDeprecatedApis WDMTestTemplate general queries +call :test WdkDeprecatedApis WDMTestTemplate general queries +call :test IllegalFieldAccess WDMTestTemplate wdm queries +call :test PoolTagIntegral WDMTestTemplate general queries +call :test ObReferenceMode WDMTestTemplate wdm queries +call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +call :test DefaultPoolTag WDMTestTemplate general queries +call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +call :test InitNotCleared WDMTestTemplate wdm queries +call :test IrqlNotUsed WDMTestTemplate general queries +call :test IrqlNotSaved WDMTestTemplate general queries +call :test IllegalFieldWrite WDMTestTemplate wdm queries +call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 From a49921c194df08ec1edac867cfe8d9913ca259ef Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 14:29:58 -0700 Subject: [PATCH 27/54] update tests for IrqlSetTooHigh --- .../IrqlSetTooHigh/driver_snippet.c | 76 +++++++++++-------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index f0b2487a..1033ad18 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -10,6 +10,7 @@ void top_level_call() {} #include + /* IRQL values: PASSIVE_LEVEL @@ -93,8 +94,6 @@ _IRQL_raises_(DISPATCH_LEVEL) // Function Exits at DISPATCH_LEVEL } - - /* Function can be called to raise the IRQL but needs to exit at APC_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. */ @@ -106,33 +105,6 @@ _IRQL_raises_(APC_LEVEL) KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } - -/* -Funciton which raises the IRQL to DISPATCH_LEVEL and then calls a function which should only be called from max DISPATCH_LEVEL -*/ -VOID IrqlRaiseLevelExplicit_pass3(void) -{ - // Set IRQL to DISPATCH_LEVEL - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxDispatch(); -} -/* -Funciton which raises the IRQL to APC_LEVEL and then calls a function which should only be called from max DISPATCH_LEVEL -*/ -VOID IrqlRaiseLevelExplicit_pass2(void) -{ - // Set IRQL to DISPATCH_LEVEL - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(APC_LEVEL, &oldIRQL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_MaxDispatch(); -} - - /* Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL */ @@ -224,6 +196,50 @@ _IRQL_requires_same_ KeLowerIrql(oldIRQL); } +/* +Function that calls another function by reference which correctly raises the IRQL. +This should pass since IrqlInderectCall_pass0 is not annotated for max IRQL. +*/ +VOID IrqlInderectCall_pass0(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlSetHigherFromPassive_pass0; + funcPtr(); +} +/* +Function that calls another function by reference which correctly raises the IRQL. +This should pass since IrqlInderectCall_pass0 is annotated for max DISPATCH_LEVEL. +*/ +_IRQL_always_function_max_(DISPATCH_LEVEL) +VOID IrqlInderectCall_pass1(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlSetHigherFromPassive_pass0; + funcPtr(); +} + +/* +Function that calls another function by reference which incorrectly raises the IRQL. +This should fail because the function pointer points to a function that should fail. +*/ +VOID IrqlInderectCall_fail0(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlRaiseLevelExplicit_fail0; + funcPtr(); +} +/* +Function that calls another function by reference which incorrectly raises the IRQL. +This should fail because the function pointer points to a function that that raises the IRQL above PASSIVE_LEVEL. +*/ +_IRQL_always_function_max_(PASSIVE_LEVEL) +VOID IrqlInderectCall_fail1(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlSetHigherFromPassive_pass0; + funcPtr(); +} + + // TODO multi-threaded tests // function has max IRQL requirement, creates two threads where one is above that requirement and one is below -// TODO test for IRQL change with function pointer \ No newline at end of file From 3208b0b10518377f837f5a6c4554db4b3e5947ad Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Wed, 11 Oct 2023 15:48:10 -0700 Subject: [PATCH 28/54] WIP IrqlSetTooLow tests --- .../IrqlSetTooLow/driver_snippet.c | 166 ++++++++++++++---- 1 file changed, 134 insertions(+), 32 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c index 15d6cd28..94857573 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -10,6 +10,7 @@ void top_level_call() {} #include + /* IRQL values: PASSIVE_LEVEL @@ -34,94 +35,144 @@ _IRQL_uses_cancel_ //The annotated parameter is the IRQL value t */ /* -Function which should only be called from PASSIVE_LEVEL +Function which should only be called from min APC_LEVEL */ -_IRQL_requires_max_(PASSIVE_LEVEL) - VOID DoNothing_Passive(void) +_IRQL_requires_min_(APC_LEVEL) + VOID DoNothing_MinAPC(void) { __noop; } /* -Function which should only be called from DISPATCH_LEVEL +Function which should only be called from min DISPATCH_LEVEL */ -_IRQL_requires_max_(DISPATCH_LEVEL) - VOID DoNothing_Dispatch(void) +_IRQL_requires_min_(DISPATCH_LEVEL) + VOID DoNothing_MinDispatch(void) { __noop; } /* -Function which should only be called from DISPATCH_LEVEL but lowers the IRQL to PASSIVE_LEVEL +Function which should only be called from PASSIVE_LEVEL */ -_IRQL_requires_min_(DISPATCH_LEVEL) - VOID IrqlSetLowerFromDispatch(void) +_IRQL_requires_(PASSIVE_LEVEL) + VOID DoNothing_RequiresPassive(void) { - KeLowerIrql(PASSIVE_LEVEL); + __noop; } /* -Funciton which lowers the IRQL to PASSIVE_LEVEL and then calls a function which should only be called from DISPATCH_LEVEL +Function which should only be called from DISPATCH_LEVEL */ -VOID IrqlRaiseLevelExplicit_fail1(void) +_IRQL_requires_(DISPATCH_LEVEL) + VOID DoNothing_RequiresDispatch(void) +{ + __noop; +} + +_IRQL_requires_min_(DISPATCH_LEVEL) + VOID IrqlSetLowerFromDispatch_pass0(void) { - // Set IRQL to DISPATCH_LEVEL KeLowerIrql(PASSIVE_LEVEL); - // Call a function at a lower IRQL than DISPATCH_LEVEL - DoNothing_Dispatch(); } +_IRQL_requires_min_(DISPATCH_LEVEL) + VOID IrqlSetAPCFromDispatch_pass0(void) +{ + KeLowerIrql(APC_LEVEL); +} + +/* +Function is annotated for min IRQL APC_LEVEL but lowers the IRQL +*/ +_IRQL_always_function_min_(APC_LEVEL) + VOID IrqlLowerLevelExplicit_fail1(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Raise above APC_LEVEL + DoNothing_MinAPC(); + KeLowerIrql(PASSIVE_LEVEL); // Lower to PASSIVE_LEVEL, which is below the min IRQL +} /* -Function is entered at PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL. -This is allowed because _IRQL_raises_(PASSIVE_LEVEL) specifies that the function can only be called to raise (not lower) the current IRQL of PASSIVE_LEVEL. +Function is annotated for min IRQL APC_LEVEL but raises the IRQL and then lowers it. */ -_IRQL_raises_(PASSIVE_LEVEL) - VOID IrqlRaiseLevelExplicit_pass(void) +_IRQL_always_function_min_(APC_LEVEL) + VOID IrqlLowerLevelExplicit_fail4(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + KeLowerIrql(PASSIVE_LEVEL); } /* -Function specifies it must be called with max IRQL PASSIVE_LEVEL, but it raises the IRQL to DISPATCH_LEVEL through another function call. +Function is annotated for min IRQL DISPATCH_LEVEL, but it lowers the IRQL to PASSIVE_LEVEL through another function call. */ -_IRQL_requires_max_(PASSIVE_LEVEL) - VOID CallFunctionThatRaisesIRQL_fail(void) +_IRQL_always_function_min_(DISPATCH_LEVEL) + VOID CallFunctionThatLowersIRQL_fail5(void) { - IrqlSetHigherFromPassive(); + IrqlSetLowerFromDispatch_pass0(); } /* -Function is annotated for max IRQL PASSIVE_LEVEL but raises the IRQL +Function is annotated for require same, but it lowers the IRQL to APC_LEVEL through another function call after raising. */ -_IRQL_always_function_max_(PASSIVE_LEVEL) - VOID IrqlRaiseLevelExplicit_fail2(void) +_IRQL_requires_same_ + VOID + CallFunctionThatLowersIRQL_fail6(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + IrqlSetAPCFromDispatch_pass0(); } /* -Function is annotated for max IRQL PASSIVE_LEVEL and does not raise the IRQL +Function is annotated for min IRQL PASSIVE_LEVEL and does not raise the IRQL */ -_IRQL_always_function_max_(PASSIVE_LEVEL) +_IRQL_always_function_min_(PASSIVE_LEVEL) VOID IrqlDontChange_pass(void) { - DoNothing_Passive(); + KeLowerIrql(PASSIVE_LEVEL); } /* -Function must enter and exit at the same IRQL, but raises and does not lower the IRQL +Function must enter and exit at the same IRQL, but raises and does not lower the IRQL fully */ _IRQL_requires_same_ VOID - IrqlRequiresSame_fail(void) + IrqlRequiresSame_fail7(void) { KIRQL oldIRQL; oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + if (oldIRQL <= PASSIVE_LEVEL) + { + KeLowerIrql(APC_LEVEL); + } + else if (oldIRQL <= APC_LEVEL) + { + KeLowerIrql(PASSIVE_LEVEL); + } + else + { + KeLowerIrql(DISPATCH_LEVEL); + } +} + +/* +Function must enter and exit at the same IRQL, but raises and does not lower the IRQL +*/ +_IRQL_requires_same_ + VOID + IrqlRequiresSame_notsupported(void) +{ + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(oldIRQL + 2, &oldIRQL); + KeLowerIrql(oldIRQL + 1); } /* @@ -135,4 +186,55 @@ _IRQL_requires_same_ oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); KeLowerIrql(oldIRQL); -} \ No newline at end of file +} + +/* +Function that calls another function by reference which correctly lowers the IRQL. +This should pass since IrqlInderectCall_pass0 is not annotated for min IRQL. +*/ +VOID IrqlInderectCall_pass0(void) +{ + void (*funcPtr)(void); + KIRQL oldIRQL; + oldIRQL = KeGetCurrentIrql(); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); + funcPtr = &IrqlSetLowerFromDispatch_pass0; + funcPtr(); +} + +/* +Function that calls another function by reference which correctly lowers the IRQL. +This should pass since IrqlInderectCall_pass0 is annotated for min PASSIVE_LEVEL. +*/ +_IRQL_always_function_min_(PASSIVE_LEVEL) + VOID IrqlInderectCall_pass1(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlSetLowerFromDispatch_pass0; + funcPtr(); +} + +/* +Function that calls another function by reference which incorrectly lowers the IRQL. +This should fail because the function pointer points to a function that should fail. +*/ +VOID IrqlInderectCall_fail0(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlLowerLevelExplicit_fail1; + funcPtr(); +} +/* +Function that calls another function by reference which incorrectly raises the IRQL. +This should fail because the function pointer points to a function that that raises the IRQL above PASSIVE_LEVEL. +*/ +_IRQL_always_function_min_(PASSIVE_LEVEL) + VOID IrqlInderectCall_fail1(void) +{ + void (*funcPtr)(void); + funcPtr = &IrqlSetLowerFromDispatch_pass0; + funcPtr(); +} + +// TODO multi-threaded tests +// function has max IRQL requirement, creates two threads where one is above that requirement and one is below From fbbf3605bbb92315b408c07e2f08eccd02c3b5c3 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:57:40 -0700 Subject: [PATCH 29/54] Fix typo in Irql.qll --- src/drivers/libraries/Irql.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 4896e677..5f8c85c0 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -72,7 +72,7 @@ class IrqlFunctionAnnotation extends SALAnnotation { this.getMacroName() .matches([ "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", - "_IRQL_always_function_max_", "IRQL_always_function_min_" + "_IRQL_always_function_max_", "_IRQL_always_function_min_" ]) and irqlLevel = this.getUnexpandedArgument(0) or From 6aaf6d5894eacc27efb1447b08adce9fa9514502 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:57:40 -0700 Subject: [PATCH 30/54] Fix typo in Irql.qll --- src/drivers/libraries/Irql.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 4896e677..5f8c85c0 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -72,7 +72,7 @@ class IrqlFunctionAnnotation extends SALAnnotation { this.getMacroName() .matches([ "_IRQL_requires_", "_IRQL_requires_min_", "_IRQL_requires_max_", "_IRQL_raises_", - "_IRQL_always_function_max_", "IRQL_always_function_min_" + "_IRQL_always_function_max_", "_IRQL_always_function_min_" ]) and irqlLevel = this.getUnexpandedArgument(0) or From 6ee7ddd8b665bd7759f8e486cc977d5b09cae865 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Thu, 12 Oct 2023 07:58:45 -0700 Subject: [PATCH 31/54] irqlSetTooHigh tests remove calls to KeGetCurrentIRQL as they are not needed --- .../IrqlSetTooHigh/driver_snippet.c | 8 --- .../test/build_create_analyze_test.cmd | 52 +++++++++---------- src/drivers/test/diff/IrqlSetTooHigh.sarif | 10 ++-- 3 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 1033ad18..6a38792a 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -74,7 +74,6 @@ _IRQL_raises_(DISPATCH_LEVEL) VOID IrqlSetHigherFromPassive_pass0(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } @@ -86,7 +85,6 @@ _IRQL_raises_(DISPATCH_LEVEL) VOID IrqlRaiseLevelExplicit_pass1(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(APC_LEVEL, &oldIRQL); // Raise level DoNothing_MaxDispatch(); // call function with max DISPATCH_LEVEL. This is OK since we're at APC_LEVEL and that is less than DISPATCH_LEVEL KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Raise level again @@ -101,7 +99,6 @@ _IRQL_raises_(APC_LEVEL) VOID IrqlRaiseLevelExplicit_fail0(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } @@ -112,7 +109,6 @@ _IRQL_always_function_max_(PASSIVE_LEVEL) VOID IrqlRaiseLevelExplicit_fail3(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } /* @@ -122,7 +118,6 @@ _IRQL_always_function_max_(PASSIVE_LEVEL) VOID IrqlRaiseLevelExplicit_fail4(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); KeLowerIrql(oldIRQL); } @@ -165,7 +160,6 @@ _IRQL_requires_same_ IrqlRequiresSame_fail7(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); } @@ -177,7 +171,6 @@ _IRQL_requires_same_ IrqlRequiresSame_notsupported(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(oldIRQL+1, &oldIRQL); } @@ -191,7 +184,6 @@ _IRQL_requires_same_ IrqlRequiresSame_pass(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); KeLowerIrql(oldIRQL); } diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index 8dd6ebd1..dd3e5cd3 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -3,33 +3,33 @@ rd /s /q TestDB >NUL 2>&1 rd /s /q AnalysisFiles >NUL 2>&1 -call :test PendingStatusError WDMTestTemplate wdm queries -call :test ExaminedValue WDMTestTemplate wdm queries -call :test StrSafe KMDFTestTemplate kmdf queries -call :test MultiplePagedCode WDMTestTemplate wdm queries -call :test NoPagedCode WDMTestTemplate wdm queries -call :test NoPagingSegment WDMTestTemplate wdm queries -call :test OpaqueMdlUse WDMTestTemplate wdm queries -call :test OpaqueMdlWrite WDMTestTemplate wdm queries -call :test KeWaitLocal WDMTestTemplate wdm queries -call :test IrqlTooHigh WDMTestTemplate general queries\experimental -call :test IrqlTooLow WDMTestTemplate general queries\experimental -call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental +@REM call :test PendingStatusError WDMTestTemplate wdm queries +@REM call :test ExaminedValue WDMTestTemplate wdm queries +@REM call :test StrSafe KMDFTestTemplate kmdf queries +@REM call :test MultiplePagedCode WDMTestTemplate wdm queries +@REM call :test NoPagedCode WDMTestTemplate wdm queries +@REM call :test NoPagingSegment WDMTestTemplate wdm queries +@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries +@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries +@REM call :test KeWaitLocal WDMTestTemplate wdm queries +@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental +@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental +@REM call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental call :test IrqlSetTooLow WDMTestTemplate general queries\experimental -call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -call :test ExtendedDeprecatedApis WDMTestTemplate general queries -call :test WdkDeprecatedApis WDMTestTemplate general queries -call :test IllegalFieldAccess WDMTestTemplate wdm queries -call :test PoolTagIntegral WDMTestTemplate general queries -call :test ObReferenceMode WDMTestTemplate wdm queries -call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -call :test DefaultPoolTag WDMTestTemplate general queries -call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -call :test InitNotCleared WDMTestTemplate wdm queries -call :test IrqlNotUsed WDMTestTemplate general queries -call :test IrqlNotSaved WDMTestTemplate general queries -call :test IllegalFieldWrite WDMTestTemplate wdm queries -call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries +@REM call :test WdkDeprecatedApis WDMTestTemplate general queries +@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries +@REM call :test PoolTagIntegral WDMTestTemplate general queries +@REM call :test ObReferenceMode WDMTestTemplate wdm queries +@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +@REM call :test DefaultPoolTag WDMTestTemplate general queries +@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +@REM call :test InitNotCleared WDMTestTemplate wdm queries +@REM call :test IrqlNotUsed WDMTestTemplate general queries +@REM call :test IrqlNotSaved WDMTestTemplate general queries +@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries +@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index 8dfd13e4..c724da45 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -17,6 +17,11 @@ 0, 2 ], + [ + "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail0](1). Maximum IRQL for this function: 1, IRQL at statement: 2", + 0, + 1 + ], [ "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [CallFunctionThatRaisesIRQL_fail5](1). Maximum IRQL for this function: 0, IRQL at statement: 2", 0, @@ -72,11 +77,6 @@ 0, 1 ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail0](1). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ], [ "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 1, IRQL at statement: 2", 0, From a6988231d4aba912fd8973342306a5672469d7be Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Thu, 12 Oct 2023 09:39:20 -0700 Subject: [PATCH 32/54] update IrqlSetTooLow tests --- .../IrqlSetTooLow/driver_snippet.c | 197 +++--------------- .../test/build_create_analyze_test.cmd | 52 ++--- 2 files changed, 59 insertions(+), 190 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c index 94857573..b1c449ef 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -35,206 +35,75 @@ _IRQL_uses_cancel_ //The annotated parameter is the IRQL value t */ /* -Function which should only be called from min APC_LEVEL +Call a function which should always be min DISPATCH_LEVEL but takes in an argument set to APC_LEVEL */ -_IRQL_requires_min_(APC_LEVEL) - VOID DoNothing_MinAPC(void) -{ - __noop; -} - -/* -Function which should only be called from min DISPATCH_LEVEL -*/ -_IRQL_requires_min_(DISPATCH_LEVEL) - VOID DoNothing_MinDispatch(void) -{ - __noop; -} - -/* -Function which should only be called from PASSIVE_LEVEL -*/ -_IRQL_requires_(PASSIVE_LEVEL) - VOID DoNothing_RequiresPassive(void) -{ - __noop; -} - -/* -Function which should only be called from DISPATCH_LEVEL -*/ -_IRQL_requires_(DISPATCH_LEVEL) - VOID DoNothing_RequiresDispatch(void) -{ - __noop; -} - -_IRQL_requires_min_(DISPATCH_LEVEL) - VOID IrqlSetLowerFromDispatch_pass0(void) +_IRQL_always_function_min_(DISPATCH_LEVEL) + VOID IrqlMinDispatchLowerIrql_fail(KIRQL *oldIRQL) { - KeLowerIrql(PASSIVE_LEVEL); + KeLowerIrql(*oldIRQL); } -_IRQL_requires_min_(DISPATCH_LEVEL) - VOID IrqlSetAPCFromDispatch_pass0(void) -{ - KeLowerIrql(APC_LEVEL); -} - -/* -Function is annotated for min IRQL APC_LEVEL but lowers the IRQL -*/ -_IRQL_always_function_min_(APC_LEVEL) - VOID IrqlLowerLevelExplicit_fail1(void) +VOID IrqlLowerWithFunctionCall(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // Raise above APC_LEVEL - DoNothing_MinAPC(); - KeLowerIrql(PASSIVE_LEVEL); // Lower to PASSIVE_LEVEL, which is below the min IRQL -} -/* -Function is annotated for min IRQL APC_LEVEL but raises the IRQL and then lowers it. -*/ -_IRQL_always_function_min_(APC_LEVEL) - VOID IrqlLowerLevelExplicit_fail4(void) -{ - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - KeLowerIrql(PASSIVE_LEVEL); + KeRaiseIrql(APC_LEVEL, &oldIRQL); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL + IrqlMinDispatchLowerIrql_fail(&oldIRQL); } /* -Function is annotated for min IRQL DISPATCH_LEVEL, but it lowers the IRQL to PASSIVE_LEVEL through another function call. +Call a function which should always be min APC_LEVEL but takes in an argument set to DISPATCH_LEVEL */ -_IRQL_always_function_min_(DISPATCH_LEVEL) - VOID CallFunctionThatLowersIRQL_fail5(void) +_IRQL_always_function_min_(APC_LEVEL) + VOID IrqlMinAPCLowerIrql(KIRQL *oldIRQL) { - IrqlSetLowerFromDispatch_pass0(); + KeLowerIrql(*oldIRQL); } -/* -Function is annotated for require same, but it lowers the IRQL to APC_LEVEL through another function call after raising. -*/ -_IRQL_requires_same_ - VOID - CallFunctionThatLowersIRQL_fail6(void) +VOID IrqlLowerWithFunctionCall_pass(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - IrqlSetAPCFromDispatch_pass0(); + KeRaiseIrql(APC_LEVEL, &oldIRQL); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL + IrqlMinAPCLowerIrql(&oldIRQL); } -/* -Function is annotated for min IRQL PASSIVE_LEVEL and does not raise the IRQL -*/ -_IRQL_always_function_min_(PASSIVE_LEVEL) - VOID IrqlDontChange_pass(void) +/* Set IRQL to PASSIVE_LEVEL inside function which is min APC_LEVEL*/ +_IRQL_always_function_min_(APC_LEVEL) + VOID IrqlAlwaysMinAPC_fail(KIRQL *oldIRQL) { - KeLowerIrql(PASSIVE_LEVEL); + KeLowerIrql(*oldIRQL); // lowers to PASSIVE_LEVEL which is lower than APC_LEVEL } -/* -Function must enter and exit at the same IRQL, but raises and does not lower the IRQL fully -*/ -_IRQL_requires_same_ - VOID - IrqlRequiresSame_fail7(void) +VOID IrqlCallAlwaysMinAPC(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - if (oldIRQL <= PASSIVE_LEVEL) - { - KeLowerIrql(APC_LEVEL); - } - else if (oldIRQL <= APC_LEVEL) - { - KeLowerIrql(PASSIVE_LEVEL); - } - else - { - KeLowerIrql(DISPATCH_LEVEL); - } + KeRaiseIrql(APC_LEVEL, &oldIRQL); + IrqlAlwaysMinAPC_fail(&oldIRQL); // oldIRQL should be PASSIVE_LEVEL } -/* -Function must enter and exit at the same IRQL, but raises and does not lower the IRQL -*/ _IRQL_requires_same_ VOID - IrqlRequiresSame_notsupported(void) + IrqlReqSame_pass(void) { KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(oldIRQL + 2, &oldIRQL); - KeLowerIrql(oldIRQL + 1); + KeRaiseIrql(APC_LEVEL, &oldIRQL); + KeLowerIrql(oldIRQL); } /* -Funciton must enter and exit at the same IRQL. IRQL is set higher but then set lower before exiting. +Requires same but lowers IRQL */ _IRQL_requires_same_ VOID - IrqlRequiresSame_pass(void) -{ - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - KeLowerIrql(oldIRQL); -} - -/* -Function that calls another function by reference which correctly lowers the IRQL. -This should pass since IrqlInderectCall_pass0 is not annotated for min IRQL. -*/ -VOID IrqlInderectCall_pass0(void) + IrqlReqSame_fail(KIRQL *oldIRQL) { - void (*funcPtr)(void); - KIRQL oldIRQL; - oldIRQL = KeGetCurrentIrql(); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); - funcPtr = &IrqlSetLowerFromDispatch_pass0; - funcPtr(); + KeLowerIrql(*oldIRQL); } -/* -Function that calls another function by reference which correctly lowers the IRQL. -This should pass since IrqlInderectCall_pass0 is annotated for min PASSIVE_LEVEL. -*/ -_IRQL_always_function_min_(PASSIVE_LEVEL) - VOID IrqlInderectCall_pass1(void) +VOID IrqlCallReqSame(void) { - void (*funcPtr)(void); - funcPtr = &IrqlSetLowerFromDispatch_pass0; - funcPtr(); + KIRQL oldIRQL; + KeRaiseIrql(APC_LEVEL, &oldIRQL); + IrqlReqSame_fail(&oldIRQL); // oldIRQL should be APC_LEVEL } - -/* -Function that calls another function by reference which incorrectly lowers the IRQL. -This should fail because the function pointer points to a function that should fail. -*/ -VOID IrqlInderectCall_fail0(void) -{ - void (*funcPtr)(void); - funcPtr = &IrqlLowerLevelExplicit_fail1; - funcPtr(); -} -/* -Function that calls another function by reference which incorrectly raises the IRQL. -This should fail because the function pointer points to a function that that raises the IRQL above PASSIVE_LEVEL. -*/ -_IRQL_always_function_min_(PASSIVE_LEVEL) - VOID IrqlInderectCall_fail1(void) -{ - void (*funcPtr)(void); - funcPtr = &IrqlSetLowerFromDispatch_pass0; - funcPtr(); -} - -// TODO multi-threaded tests -// function has max IRQL requirement, creates two threads where one is above that requirement and one is below diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index dd3e5cd3..8dd6ebd1 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -3,33 +3,33 @@ rd /s /q TestDB >NUL 2>&1 rd /s /q AnalysisFiles >NUL 2>&1 -@REM call :test PendingStatusError WDMTestTemplate wdm queries -@REM call :test ExaminedValue WDMTestTemplate wdm queries -@REM call :test StrSafe KMDFTestTemplate kmdf queries -@REM call :test MultiplePagedCode WDMTestTemplate wdm queries -@REM call :test NoPagedCode WDMTestTemplate wdm queries -@REM call :test NoPagingSegment WDMTestTemplate wdm queries -@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries -@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries -@REM call :test KeWaitLocal WDMTestTemplate wdm queries -@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental -@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental -@REM call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental +call :test PendingStatusError WDMTestTemplate wdm queries +call :test ExaminedValue WDMTestTemplate wdm queries +call :test StrSafe KMDFTestTemplate kmdf queries +call :test MultiplePagedCode WDMTestTemplate wdm queries +call :test NoPagedCode WDMTestTemplate wdm queries +call :test NoPagingSegment WDMTestTemplate wdm queries +call :test OpaqueMdlUse WDMTestTemplate wdm queries +call :test OpaqueMdlWrite WDMTestTemplate wdm queries +call :test KeWaitLocal WDMTestTemplate wdm queries +call :test IrqlTooHigh WDMTestTemplate general queries\experimental +call :test IrqlTooLow WDMTestTemplate general queries\experimental +call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental call :test IrqlSetTooLow WDMTestTemplate general queries\experimental -@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries -@REM call :test WdkDeprecatedApis WDMTestTemplate general queries -@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries -@REM call :test PoolTagIntegral WDMTestTemplate general queries -@REM call :test ObReferenceMode WDMTestTemplate wdm queries -@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -@REM call :test DefaultPoolTag WDMTestTemplate general queries -@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -@REM call :test InitNotCleared WDMTestTemplate wdm queries -@REM call :test IrqlNotUsed WDMTestTemplate general queries -@REM call :test IrqlNotSaved WDMTestTemplate general queries -@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries -@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +call :test ExtendedDeprecatedApis WDMTestTemplate general queries +call :test WdkDeprecatedApis WDMTestTemplate general queries +call :test IllegalFieldAccess WDMTestTemplate wdm queries +call :test PoolTagIntegral WDMTestTemplate general queries +call :test ObReferenceMode WDMTestTemplate wdm queries +call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +call :test DefaultPoolTag WDMTestTemplate general queries +call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +call :test InitNotCleared WDMTestTemplate wdm queries +call :test IrqlNotUsed WDMTestTemplate general queries +call :test IrqlNotSaved WDMTestTemplate general queries +call :test IllegalFieldWrite WDMTestTemplate wdm queries +call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 From 4250f6fc52347bbde5e71a9b76a35d6d137e76e1 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Thu, 12 Oct 2023 15:21:59 -0700 Subject: [PATCH 33/54] update tests. line 90 should be a failling test but isnt --- .../IrqlSetTooLow/driver_snippet.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c index b1c449ef..ec8b6a12 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -47,12 +47,29 @@ VOID IrqlLowerWithFunctionCall(void) { KIRQL oldIRQL; KeRaiseIrql(APC_LEVEL, &oldIRQL); - KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL IrqlMinDispatchLowerIrql_fail(&oldIRQL); } +// /* +// Call a function which should always be min DISPATCH_LEVEL but takes in an argument set to APC_LEVEL +// */ +// _IRQL_always_function_min_(DISPATCH_LEVEL) +// VOID IrqlMinDispatchLowerIrql_fail1(KIRQL *oldIRQL) +// { +// KeLowerIrql(*oldIRQL); +// } + +// VOID IrqlLowerWithFunctionCall1(void) +// { +// KIRQL oldIRQL; +// KeRaiseIrql(APC_LEVEL, &oldIRQL); +// KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL +// IrqlMinDispatchLowerIrql_fail(&oldIRQL); +// } + + /* -Call a function which should always be min APC_LEVEL but takes in an argument set to DISPATCH_LEVEL +Call a function which should always be min APC_LEVEL that takes in an argument set to DISPATCH_LEVEL */ _IRQL_always_function_min_(APC_LEVEL) VOID IrqlMinAPCLowerIrql(KIRQL *oldIRQL) From fd9084b7f74133647044a813a79fe668c8ee8f6b Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Fri, 13 Oct 2023 10:39:24 -0700 Subject: [PATCH 34/54] fix IrqlLowerWithFunctionCall1 to call IrqlMinDispatchLowerIrql_fail1 --- .../test/build_create_analyze_test.cmd | 52 +++++++++---------- src/drivers/test/diff/IrqlSetTooLow.sarif | 27 ++++++++-- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index 8dd6ebd1..dd3e5cd3 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -3,33 +3,33 @@ rd /s /q TestDB >NUL 2>&1 rd /s /q AnalysisFiles >NUL 2>&1 -call :test PendingStatusError WDMTestTemplate wdm queries -call :test ExaminedValue WDMTestTemplate wdm queries -call :test StrSafe KMDFTestTemplate kmdf queries -call :test MultiplePagedCode WDMTestTemplate wdm queries -call :test NoPagedCode WDMTestTemplate wdm queries -call :test NoPagingSegment WDMTestTemplate wdm queries -call :test OpaqueMdlUse WDMTestTemplate wdm queries -call :test OpaqueMdlWrite WDMTestTemplate wdm queries -call :test KeWaitLocal WDMTestTemplate wdm queries -call :test IrqlTooHigh WDMTestTemplate general queries\experimental -call :test IrqlTooLow WDMTestTemplate general queries\experimental -call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental +@REM call :test PendingStatusError WDMTestTemplate wdm queries +@REM call :test ExaminedValue WDMTestTemplate wdm queries +@REM call :test StrSafe KMDFTestTemplate kmdf queries +@REM call :test MultiplePagedCode WDMTestTemplate wdm queries +@REM call :test NoPagedCode WDMTestTemplate wdm queries +@REM call :test NoPagingSegment WDMTestTemplate wdm queries +@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries +@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries +@REM call :test KeWaitLocal WDMTestTemplate wdm queries +@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental +@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental +@REM call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental call :test IrqlSetTooLow WDMTestTemplate general queries\experimental -call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -call :test ExtendedDeprecatedApis WDMTestTemplate general queries -call :test WdkDeprecatedApis WDMTestTemplate general queries -call :test IllegalFieldAccess WDMTestTemplate wdm queries -call :test PoolTagIntegral WDMTestTemplate general queries -call :test ObReferenceMode WDMTestTemplate wdm queries -call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -call :test DefaultPoolTag WDMTestTemplate general queries -call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -call :test InitNotCleared WDMTestTemplate wdm queries -call :test IrqlNotUsed WDMTestTemplate general queries -call :test IrqlNotSaved WDMTestTemplate general queries -call :test IllegalFieldWrite WDMTestTemplate wdm queries -call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries +@REM call :test WdkDeprecatedApis WDMTestTemplate general queries +@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries +@REM call :test PoolTagIntegral WDMTestTemplate general queries +@REM call :test ObReferenceMode WDMTestTemplate wdm queries +@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +@REM call :test DefaultPoolTag WDMTestTemplate general queries +@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +@REM call :test InitNotCleared WDMTestTemplate wdm queries +@REM call :test IrqlNotUsed WDMTestTemplate general queries +@REM call :test IrqlNotSaved WDMTestTemplate general queries +@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries +@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 diff --git a/src/drivers/test/diff/IrqlSetTooLow.sarif b/src/drivers/test/diff/IrqlSetTooLow.sarif index 8d5a80f9..7ffecd46 100644 --- a/src/drivers/test/diff/IrqlSetTooLow.sarif +++ b/src/drivers/test/diff/IrqlSetTooLow.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 0, + "+": 4, "-": 0 }, "error": { @@ -9,9 +9,30 @@ "codes": [] }, "warning": { - "+": 0, + "+": 4, "-": 0, - "codes": [] + "codes": [ + [ + "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: IrqlMinDispatchLowerIrql_fail\nfuncIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: {{ ... }}", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: * ...", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: call to KeLowerIrql", + 0, + 1 + ], + [ + "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: IrqlMinDispatchLowerIrql_fail", + 0, + 1 + ] + ] }, "note": { "+": 0, From f0fe56ef72ab87f682db58d7df5c21f8b40fdf52 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Fri, 13 Oct 2023 10:40:26 -0700 Subject: [PATCH 35/54] Revert"fix IrqlLowerWithFunctionCall1 to call IrqlMinDispatchLowerIrql_fail1" This reverts commit fd9084b7f74133647044a813a79fe668c8ee8f6b. --- .../test/build_create_analyze_test.cmd | 52 +++++++++---------- src/drivers/test/diff/IrqlSetTooLow.sarif | 27 ++-------- 2 files changed, 29 insertions(+), 50 deletions(-) diff --git a/src/drivers/test/build_create_analyze_test.cmd b/src/drivers/test/build_create_analyze_test.cmd index dd3e5cd3..8dd6ebd1 100644 --- a/src/drivers/test/build_create_analyze_test.cmd +++ b/src/drivers/test/build_create_analyze_test.cmd @@ -3,33 +3,33 @@ rd /s /q TestDB >NUL 2>&1 rd /s /q AnalysisFiles >NUL 2>&1 -@REM call :test PendingStatusError WDMTestTemplate wdm queries -@REM call :test ExaminedValue WDMTestTemplate wdm queries -@REM call :test StrSafe KMDFTestTemplate kmdf queries -@REM call :test MultiplePagedCode WDMTestTemplate wdm queries -@REM call :test NoPagedCode WDMTestTemplate wdm queries -@REM call :test NoPagingSegment WDMTestTemplate wdm queries -@REM call :test OpaqueMdlUse WDMTestTemplate wdm queries -@REM call :test OpaqueMdlWrite WDMTestTemplate wdm queries -@REM call :test KeWaitLocal WDMTestTemplate wdm queries -@REM call :test IrqlTooHigh WDMTestTemplate general queries\experimental -@REM call :test IrqlTooLow WDMTestTemplate general queries\experimental -@REM call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental +call :test PendingStatusError WDMTestTemplate wdm queries +call :test ExaminedValue WDMTestTemplate wdm queries +call :test StrSafe KMDFTestTemplate kmdf queries +call :test MultiplePagedCode WDMTestTemplate wdm queries +call :test NoPagedCode WDMTestTemplate wdm queries +call :test NoPagingSegment WDMTestTemplate wdm queries +call :test OpaqueMdlUse WDMTestTemplate wdm queries +call :test OpaqueMdlWrite WDMTestTemplate wdm queries +call :test KeWaitLocal WDMTestTemplate wdm queries +call :test IrqlTooHigh WDMTestTemplate general queries\experimental +call :test IrqlTooLow WDMTestTemplate general queries\experimental +call :test IrqlSetTooHigh WDMTestTemplate general queries\experimental call :test IrqlSetTooLow WDMTestTemplate general queries\experimental -@REM call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries -@REM call :test ExtendedDeprecatedApis WDMTestTemplate general queries -@REM call :test WdkDeprecatedApis WDMTestTemplate general queries -@REM call :test IllegalFieldAccess WDMTestTemplate wdm queries -@REM call :test PoolTagIntegral WDMTestTemplate general queries -@REM call :test ObReferenceMode WDMTestTemplate wdm queries -@REM call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental -@REM call :test DefaultPoolTag WDMTestTemplate general queries -@REM call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental -@REM call :test InitNotCleared WDMTestTemplate wdm queries -@REM call :test IrqlNotUsed WDMTestTemplate general queries -@REM call :test IrqlNotSaved WDMTestTemplate general queries -@REM call :test IllegalFieldWrite WDMTestTemplate wdm queries -@REM call :test IllegalFieldAccess2 WDMTestTemplate wdm queries +call :test WrongDispatchTableAssignment WDMTestTemplate wdm queries +call :test ExtendedDeprecatedApis WDMTestTemplate general queries +call :test WdkDeprecatedApis WDMTestTemplate general queries +call :test IllegalFieldAccess WDMTestTemplate wdm queries +call :test PoolTagIntegral WDMTestTemplate general queries +call :test ObReferenceMode WDMTestTemplate wdm queries +call :test DeviceInitApi KMDFTestTemplate kmdf queries\experimental +call :test DefaultPoolTag WDMTestTemplate general queries +call :test DefaultPoolTagExtended WDMTestTemplate general queries\experimental +call :test InitNotCleared WDMTestTemplate wdm queries +call :test IrqlNotUsed WDMTestTemplate general queries +call :test IrqlNotSaved WDMTestTemplate general queries +call :test IllegalFieldWrite WDMTestTemplate wdm queries +call :test IllegalFieldAccess2 WDMTestTemplate wdm queries exit /b 0 diff --git a/src/drivers/test/diff/IrqlSetTooLow.sarif b/src/drivers/test/diff/IrqlSetTooLow.sarif index 7ffecd46..8d5a80f9 100644 --- a/src/drivers/test/diff/IrqlSetTooLow.sarif +++ b/src/drivers/test/diff/IrqlSetTooLow.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 4, + "+": 0, "-": 0 }, "error": { @@ -9,30 +9,9 @@ "codes": [] }, "warning": { - "+": 4, + "+": 0, "-": 0, - "codes": [ - [ - "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: IrqlMinDispatchLowerIrql_fail\nfuncIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: {{ ... }}", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: * ...", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: call to KeLowerIrql", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-low funcIRQL 2 getPotentialExitIrqlAtCfn 1 irqlFunc IrqlMinDispatchLowerIrql_fail getQualifiedName IrqlMinDispatchLowerIrql_fail statement: IrqlMinDispatchLowerIrql_fail", - 0, - 1 - ] - ] + "codes": [] }, "note": { "+": 0, From a35c1c2e65847d69059bb912a23f54e1f3c17f20 Mon Sep 17 00:00:00 2001 From: jacob-ronstadt Date: Fri, 13 Oct 2023 10:42:23 -0700 Subject: [PATCH 36/54] fix IrqlLowerWithFunctionCall1 to call IrqlMinDispatchLowerIrql_fail1 --- .../IrqlSetTooLow/driver_snippet.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c index ec8b6a12..04e388c2 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/driver_snippet.c @@ -50,22 +50,22 @@ VOID IrqlLowerWithFunctionCall(void) IrqlMinDispatchLowerIrql_fail(&oldIRQL); } -// /* -// Call a function which should always be min DISPATCH_LEVEL but takes in an argument set to APC_LEVEL -// */ -// _IRQL_always_function_min_(DISPATCH_LEVEL) -// VOID IrqlMinDispatchLowerIrql_fail1(KIRQL *oldIRQL) -// { -// KeLowerIrql(*oldIRQL); -// } - -// VOID IrqlLowerWithFunctionCall1(void) -// { -// KIRQL oldIRQL; -// KeRaiseIrql(APC_LEVEL, &oldIRQL); -// KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL -// IrqlMinDispatchLowerIrql_fail(&oldIRQL); -// } +/* +Call a function which should always be min DISPATCH_LEVEL but takes in an argument set to APC_LEVEL +*/ +_IRQL_always_function_min_(DISPATCH_LEVEL) + VOID IrqlMinDispatchLowerIrql_fail1(KIRQL *oldIRQL) +{ + KeLowerIrql(*oldIRQL); +} + +VOID IrqlLowerWithFunctionCall1(void) +{ + KIRQL oldIRQL; + KeRaiseIrql(APC_LEVEL, &oldIRQL); + KeRaiseIrql(DISPATCH_LEVEL, &oldIRQL); // oldIRQL should be APC_LEVEL + IrqlMinDispatchLowerIrql_fail1(&oldIRQL); +} /* From dd23682396daac3e25f7495a9cfd687ca7166664 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:33:55 -0700 Subject: [PATCH 37/54] Add some interprocedural IRQL analysis + comments --- .../IrqlSetTooHigh/IrqlSetTooHigh.ql | 20 +++++-- .../IrqlSetTooLow/IrqlSetTooLow.ql | 18 +++++- src/drivers/libraries/Irql.qll | 60 +++++++++++++++---- src/drivers/libraries/IrqlDataFlow.qll | 43 +++++++++++++ 4 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 src/drivers/libraries/IrqlDataFlow.qll diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql index b726f1b7..4f0d0d16 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -17,16 +17,23 @@ * @tags correctness * wddst * @scope domainspecific - * @query-version v2 + * @query-version v1 */ import cpp import drivers.libraries.Irql +predicate tooHighForFunc( + IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +) { + statement.getControlFlowScope() = irqlFunc and + irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement and + irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) and + irqlRequirement != -1 +} from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement where - statement.getControlFlowScope() = irqlFunc and ( irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement or @@ -35,8 +42,13 @@ where not irqlFunc instanceof IrqlAlwaysMaxFunction and irqlFunc.(IrqlRaisesAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and - irqlRequirement != -1 and - irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) + tooHighForFunc(irqlFunc, statement, irqlRequirement) and + // Only get the first node which is set too low + not exists(ControlFlowNode otherNode | + otherNode.getControlFlowScope() = irqlFunc and + otherNode = statement.getAPredecessor() and + tooHighForFunc(irqlFunc, otherNode, irqlRequirement) + ) select statement, "$@: IRQL potentially set too high at $@. Maximum IRQL for this function: " + irqlRequirement + ", IRQL at statement: " + min(getPotentialExitIrqlAtCfn(statement)), irqlFunc, diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql index 09c3a91b..51e6466e 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql @@ -17,18 +17,30 @@ * @tags correctness * wddst * @scope domainspecific - * @query-version v2 + * @query-version v1 */ import cpp import drivers.libraries.Irql -from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement -where +predicate tooLowForFunc( + IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +) { statement.getControlFlowScope() = irqlFunc and irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and irqlRequirement > max(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 +} + +from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +where + tooLowForFunc(irqlFunc, statement, irqlRequirement) and + // Only get the first node which is set too low + not exists(ControlFlowNode otherNode | + otherNode.getControlFlowScope() = irqlFunc and + otherNode = statement.getAPredecessor() and + tooLowForFunc(irqlFunc, otherNode, irqlRequirement) + ) select statement, "$@: IRQL potentially set too low at $@. Minimum IRQL for this function: " + irqlRequirement + ", IRQL at statement: " + max(getPotentialExitIrqlAtCfn(statement)), irqlFunc, diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 5f8c85c0..a9106463 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -1,8 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +/** + * Provides classes related to calculating and estimating the IRQL in a Windows device driver. + * + * For best results, this library expects to be used in tandem with IRQL annotations. A limited + * amount of functionality is still present even when no annotations are present, primarily around + * measuring direct calls to KeRaiseIrql and KeLowerIrql. + * + * Much of this library's analysis is intraprocedural or limited interprocedural, using a simple + * analysis based on call sites to a given function. Full interprocedural analysis that relies on the + * implicit behaviors of the WDM driver model, etc. is not yet supported. + */ + import cpp import drivers.libraries.SAL import drivers.wdm.libraries.WdmDrivers +import drivers.libraries.IrqlDataFlow /** * A macro in wdm.h that represents an IRQL level, @@ -457,11 +470,16 @@ class KeLowerIrqlCall extends FunctionCall { * "the IRQL before the most recent KeRaiseIrql call". */ int getIrqlLevel() { - result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + result = + any(getPotentialExitIrqlAtCfn(this.getMostRecentRaiseInterprocedural().getAPredecessor())) } /** - * Get the most recent call before this call that explicitly raised the IRQL. + * Get the most recent KeRaiseIrql call before this call. + * + * This performs a local (intraprocedural) analysis only. It is unused in the library today, + * but can be inserted in place of the interprocedural analysis by modifying the getIrqlLevel() + * function above. */ KeRaiseIrqlCall getMostRecentRaise() { result = @@ -470,6 +488,20 @@ class KeLowerIrqlCall extends FunctionCall { not exists(KeRaiseIrqlCall kric2 | kric2 != sgic and kric2.getAPredecessor*() = sgic) ) } + + /** + * Get the corresponding KeRaiseIrql call that preceded this KeLowerIrql call. + * + * This performs an interprocedural analysis using CodeQL's DataFlow classes. + */ + KeRaiseIrqlCall getMostRecentRaiseInterprocedural() { + result = + any(KeRaiseIrqlCall kric | + exists(IrqlRaiseLowerFlow irlf | + irlf.hasFlow(DataFlow::exprNode(kric), DataFlow::exprNode(this.getAnArgument())) + ) + ) + } } /** A call to a function that restores the IRQL from a specified state. */ @@ -489,7 +521,11 @@ class RestoresGlobalIrqlCall extends FunctionCall { result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) } - /** Returns the matching call to a function that saved the IRQL to a global state. */ + /** + * Returns the matching call to a function that saved the IRQL to a global state. + * + * This is a strictly intraprocedural analysis. + */ SavesGlobalIrqlCall getMostRecentRaise() { result = any(SavesGlobalIrqlCall sgic | @@ -546,9 +582,9 @@ private predicate exprsMatchText(Expr e1, Expr e2) { * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN. * - If this node is calling a function with no annotations, the result is the IRQL that function exits at. * - If there is a prior CFN in the CFG, the result is the result for that prior CFN. - * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function. - * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. - * - If there is nothing else, then IRQL is 0. + * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function (a lazy interprocedural analysis.) + * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function. + * - Failing all this, we set the IRQL to 0. * * Not implemented: _IRQL_limited_to_ */ @@ -620,6 +656,8 @@ private ControlFlowNode getExitPointsOfFunction(Function f) { /** * Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function. + * + * Note: we implicitly apply DISPATCH_LEVEL as the max when a max is not specified. */ cached int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { @@ -640,12 +678,8 @@ int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { then result = any([0 .. irqlFunc.(IrqlMaxAnnotatedFunction).getIrqlLevel()]) else if irqlFunc instanceof IrqlMinAnnotatedFunction - then - result = - any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. any(IrqlMacro im) - .getGlobalMaxIrqlLevel()] - ) + then result = any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. 2]) else - // No known restriction - result = any([0 .. any(IrqlMacro im).getGlobalMaxIrqlLevel()]) + // No known restriction. Default to between PASSIVE and DISPATCH. + result = any([0 .. 2]) } diff --git a/src/drivers/libraries/IrqlDataFlow.qll b/src/drivers/libraries/IrqlDataFlow.qll new file mode 100644 index 00000000..c866c76d --- /dev/null +++ b/src/drivers/libraries/IrqlDataFlow.qll @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * Provides cata-flow analyses used in calculating the IRQL in a Windwos driver. + */ + + +import cpp +import drivers.libraries.Irql +import semmle.code.cpp.dataflow.new.DataFlow + +/** + * A data-flow configuration describing flow from a + * KeRaiseIrqlCall to a KeLowerIrqlCall. + */ +class IrqlRaiseLowerFlow extends DataFlow::Configuration { + IrqlRaiseLowerFlow() { this = "IrqlRaiseLowerFlow" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof KeRaiseIrqlCall } + + override predicate isSink(DataFlow::Node sink) { + exists(KeLowerIrqlCall firf | + sink.asExpr() = firf.getArgument(firf.getTarget().(IrqlRestoreFunction).getIrqlIndex()) + ) + } +} + +/** + * A function that has at least one parameter annotated with "\_IRQL\_restores\_". + */ +class IrqlRestoreFunction extends Function { + Parameter p; + int irqlIndex; + + IrqlRestoreFunction() { + p = this.getParameter(irqlIndex) and + p instanceof IrqlRestoreParameter + } + + Parameter getRestoreParameter() { result = p } + + int getIrqlIndex() { result = irqlIndex } +} \ No newline at end of file From dfae1fb4212d2f97a6be1caa622cd3bdc484b542 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:33:55 -0700 Subject: [PATCH 38/54] Add some interprocedural IRQL analysis + comments --- .../IrqlSetTooHigh/IrqlSetTooHigh.ql | 21 +++++-- .../IrqlSetTooLow/IrqlSetTooLow.ql | 18 +++++- src/drivers/libraries/Irql.qll | 60 +++++++++++++++---- src/drivers/libraries/IrqlDataFlow.qll | 43 +++++++++++++ 4 files changed, 122 insertions(+), 20 deletions(-) create mode 100644 src/drivers/libraries/IrqlDataFlow.qll diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql index 1a26247e..4f0d0d16 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -17,15 +17,23 @@ * @tags correctness * wddst * @scope domainspecific - * @query-version v2 + * @query-version v1 */ import cpp import drivers.libraries.Irql +predicate tooHighForFunc( + IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +) { + statement.getControlFlowScope() = irqlFunc and + irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement and + irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) and + irqlRequirement != -1 +} + from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement where - statement.getControlFlowScope() = irqlFunc and ( irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement or @@ -34,8 +42,13 @@ where not irqlFunc instanceof IrqlAlwaysMaxFunction and irqlFunc.(IrqlRaisesAnnotatedFunction).getIrqlLevel() = irqlRequirement ) and - irqlRequirement != -1 and - irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) + tooHighForFunc(irqlFunc, statement, irqlRequirement) and + // Only get the first node which is set too low + not exists(ControlFlowNode otherNode | + otherNode.getControlFlowScope() = irqlFunc and + otherNode = statement.getAPredecessor() and + tooHighForFunc(irqlFunc, otherNode, irqlRequirement) + ) select statement, "$@: IRQL potentially set too high at $@. Maximum IRQL for this function: " + irqlRequirement + ", IRQL at statement: " + min(getPotentialExitIrqlAtCfn(statement)), irqlFunc, diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql index 09c3a91b..51e6466e 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql @@ -17,18 +17,30 @@ * @tags correctness * wddst * @scope domainspecific - * @query-version v2 + * @query-version v1 */ import cpp import drivers.libraries.Irql -from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement -where +predicate tooLowForFunc( + IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +) { statement.getControlFlowScope() = irqlFunc and irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and irqlRequirement > max(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 +} + +from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement +where + tooLowForFunc(irqlFunc, statement, irqlRequirement) and + // Only get the first node which is set too low + not exists(ControlFlowNode otherNode | + otherNode.getControlFlowScope() = irqlFunc and + otherNode = statement.getAPredecessor() and + tooLowForFunc(irqlFunc, otherNode, irqlRequirement) + ) select statement, "$@: IRQL potentially set too low at $@. Minimum IRQL for this function: " + irqlRequirement + ", IRQL at statement: " + max(getPotentialExitIrqlAtCfn(statement)), irqlFunc, diff --git a/src/drivers/libraries/Irql.qll b/src/drivers/libraries/Irql.qll index 5f8c85c0..a9106463 100644 --- a/src/drivers/libraries/Irql.qll +++ b/src/drivers/libraries/Irql.qll @@ -1,8 +1,21 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +/** + * Provides classes related to calculating and estimating the IRQL in a Windows device driver. + * + * For best results, this library expects to be used in tandem with IRQL annotations. A limited + * amount of functionality is still present even when no annotations are present, primarily around + * measuring direct calls to KeRaiseIrql and KeLowerIrql. + * + * Much of this library's analysis is intraprocedural or limited interprocedural, using a simple + * analysis based on call sites to a given function. Full interprocedural analysis that relies on the + * implicit behaviors of the WDM driver model, etc. is not yet supported. + */ + import cpp import drivers.libraries.SAL import drivers.wdm.libraries.WdmDrivers +import drivers.libraries.IrqlDataFlow /** * A macro in wdm.h that represents an IRQL level, @@ -457,11 +470,16 @@ class KeLowerIrqlCall extends FunctionCall { * "the IRQL before the most recent KeRaiseIrql call". */ int getIrqlLevel() { - result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) + result = + any(getPotentialExitIrqlAtCfn(this.getMostRecentRaiseInterprocedural().getAPredecessor())) } /** - * Get the most recent call before this call that explicitly raised the IRQL. + * Get the most recent KeRaiseIrql call before this call. + * + * This performs a local (intraprocedural) analysis only. It is unused in the library today, + * but can be inserted in place of the interprocedural analysis by modifying the getIrqlLevel() + * function above. */ KeRaiseIrqlCall getMostRecentRaise() { result = @@ -470,6 +488,20 @@ class KeLowerIrqlCall extends FunctionCall { not exists(KeRaiseIrqlCall kric2 | kric2 != sgic and kric2.getAPredecessor*() = sgic) ) } + + /** + * Get the corresponding KeRaiseIrql call that preceded this KeLowerIrql call. + * + * This performs an interprocedural analysis using CodeQL's DataFlow classes. + */ + KeRaiseIrqlCall getMostRecentRaiseInterprocedural() { + result = + any(KeRaiseIrqlCall kric | + exists(IrqlRaiseLowerFlow irlf | + irlf.hasFlow(DataFlow::exprNode(kric), DataFlow::exprNode(this.getAnArgument())) + ) + ) + } } /** A call to a function that restores the IRQL from a specified state. */ @@ -489,7 +521,11 @@ class RestoresGlobalIrqlCall extends FunctionCall { result = any(getPotentialExitIrqlAtCfn(this.getMostRecentRaise().getAPredecessor())) } - /** Returns the matching call to a function that saved the IRQL to a global state. */ + /** + * Returns the matching call to a function that saved the IRQL to a global state. + * + * This is a strictly intraprocedural analysis. + */ SavesGlobalIrqlCall getMostRecentRaise() { result = any(SavesGlobalIrqlCall sgic | @@ -546,9 +582,9 @@ private predicate exprsMatchText(Expr e1, Expr e2) { * - If calling a function annotated to maintain the same IRQL, then the result is the IRQL at the previous CFN. * - If this node is calling a function with no annotations, the result is the IRQL that function exits at. * - If there is a prior CFN in the CFG, the result is the result for that prior CFN. - * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function. - * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations. - * - If there is nothing else, then IRQL is 0. + * - If there is no prior CFN, then the result is whatever the IRQL was at a statement prior to a function call to this function (a lazy interprocedural analysis.) + * - If there are no prior CFNs and no calls to this function, then the IRQL is determined by annotations applied to this function. + * - Failing all this, we set the IRQL to 0. * * Not implemented: _IRQL_limited_to_ */ @@ -620,6 +656,8 @@ private ControlFlowNode getExitPointsOfFunction(Function f) { /** * Attempt to find the range of valid IRQL values when **entering** a given IRQL-annotated function. + * + * Note: we implicitly apply DISPATCH_LEVEL as the max when a max is not specified. */ cached int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { @@ -640,12 +678,8 @@ int getAllowableIrqlLevel(IrqlRestrictsFunction irqlFunc) { then result = any([0 .. irqlFunc.(IrqlMaxAnnotatedFunction).getIrqlLevel()]) else if irqlFunc instanceof IrqlMinAnnotatedFunction - then - result = - any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. any(IrqlMacro im) - .getGlobalMaxIrqlLevel()] - ) + then result = any([irqlFunc.(IrqlMinAnnotatedFunction).getIrqlLevel() .. 2]) else - // No known restriction - result = any([0 .. any(IrqlMacro im).getGlobalMaxIrqlLevel()]) + // No known restriction. Default to between PASSIVE and DISPATCH. + result = any([0 .. 2]) } diff --git a/src/drivers/libraries/IrqlDataFlow.qll b/src/drivers/libraries/IrqlDataFlow.qll new file mode 100644 index 00000000..c866c76d --- /dev/null +++ b/src/drivers/libraries/IrqlDataFlow.qll @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +/** + * Provides cata-flow analyses used in calculating the IRQL in a Windwos driver. + */ + + +import cpp +import drivers.libraries.Irql +import semmle.code.cpp.dataflow.new.DataFlow + +/** + * A data-flow configuration describing flow from a + * KeRaiseIrqlCall to a KeLowerIrqlCall. + */ +class IrqlRaiseLowerFlow extends DataFlow::Configuration { + IrqlRaiseLowerFlow() { this = "IrqlRaiseLowerFlow" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof KeRaiseIrqlCall } + + override predicate isSink(DataFlow::Node sink) { + exists(KeLowerIrqlCall firf | + sink.asExpr() = firf.getArgument(firf.getTarget().(IrqlRestoreFunction).getIrqlIndex()) + ) + } +} + +/** + * A function that has at least one parameter annotated with "\_IRQL\_restores\_". + */ +class IrqlRestoreFunction extends Function { + Parameter p; + int irqlIndex; + + IrqlRestoreFunction() { + p = this.getParameter(irqlIndex) and + p instanceof IrqlRestoreParameter + } + + Parameter getRestoreParameter() { result = p } + + int getIrqlIndex() { result = irqlIndex } +} \ No newline at end of file From 4c8be483fee38b9fefc768e8a27e7d8849209df5 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:47:48 -0700 Subject: [PATCH 39/54] Fix typos --- src/drivers/libraries/IrqlDataFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/libraries/IrqlDataFlow.qll b/src/drivers/libraries/IrqlDataFlow.qll index c866c76d..bf32d1bf 100644 --- a/src/drivers/libraries/IrqlDataFlow.qll +++ b/src/drivers/libraries/IrqlDataFlow.qll @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** - * Provides cata-flow analyses used in calculating the IRQL in a Windwos driver. + * Provides data-flow analyses used in calculating the IRQL in a Windows driver. */ From b0ad4a4a577b6cb8494cf452e1c202c4dca131ef Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:07:20 -0700 Subject: [PATCH 40/54] Restore non-IRQL test results --- src/drivers/test/diff/ExaminedValue.sarif | 12 +++------ .../test/diff/IllegalFieldAccess.sarif | 17 +++--------- .../test/diff/IllegalFieldAccess2.sarif | 27 +++---------------- src/drivers/test/diff/IllegalFieldWrite.sarif | 27 +++---------------- src/drivers/test/diff/MultiplePagedCode.sarif | 12 +++------ src/drivers/test/diff/NoPagedCode.sarif | 12 +++------ src/drivers/test/diff/NoPagingSegment.sarif | 12 +++------ src/drivers/test/diff/OpaqueMdlWrite.sarif | 12 +++------ src/drivers/test/diff/StrSafe.sarif | 12 +++------ .../diff/WrongDispatchTableAssignment.sarif | 22 +++------------ 10 files changed, 30 insertions(+), 135 deletions(-) diff --git a/src/drivers/test/diff/ExaminedValue.sarif b/src/drivers/test/diff/ExaminedValue.sarif index 3c23aa49..8d5a80f9 100644 --- a/src/drivers/test/diff/ExaminedValue.sarif +++ b/src/drivers/test/diff/ExaminedValue.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/examined-value Result of call to func2 is ignored; 77% of calls to this function have their result checked. Checked return values = 7 total calls = 9", - 2, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IllegalFieldAccess.sarif b/src/drivers/test/diff/IllegalFieldAccess.sarif index 8c5dc8d0..8d5a80f9 100644 --- a/src/drivers/test/diff/IllegalFieldAccess.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 2 + "-": 0 }, "error": { "+": 0, @@ -10,19 +10,8 @@ }, "warning": { "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/illegal-field-access An assignment to an IO DPC or one of its fields has been made directly. It should be made by IoInitializeDpcRequest.", - 2, - 0 - ], - [ - "cpp/drivers/illegal-field-access An assignment to an IRP CancelRoutine field was made directly. It should be made by IoSetCancelRoutine.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IllegalFieldAccess2.sarif b/src/drivers/test/diff/IllegalFieldAccess2.sarif index 5649b882..8d5a80f9 100644 --- a/src/drivers/test/diff/IllegalFieldAccess2.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess2.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 4 + "-": 0 }, "error": { "+": 0, @@ -10,29 +10,8 @@ }, "warning": { "+": 0, - "-": 4, - "codes": [ - [ - "cpp/drivers/illegal-field-access-2 The 'Flags' field of the DriverObject struct cannot be accessed by a driver.", - 2, - 0 - ], - [ - "cpp/drivers/illegal-field-access-2 The 'NextDevice' field of the DeviceObject struct can only be accessed in DriverEntry or DriverUnload.", - 1, - 0 - ], - [ - "cpp/drivers/illegal-field-access-2 The 'Dpc' field of the DeviceObject struct cannot be accessed by a driver.", - 1, - 0 - ], - [ - "cpp/drivers/illegal-field-access-2 The 'DriverExtension' field of the DriverObject struct can only be accessed in a DriverEntry routine.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IllegalFieldWrite.sarif b/src/drivers/test/diff/IllegalFieldWrite.sarif index e7aea252..8d5a80f9 100644 --- a/src/drivers/test/diff/IllegalFieldWrite.sarif +++ b/src/drivers/test/diff/IllegalFieldWrite.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 4 + "-": 0 }, "error": { "+": 0, @@ -10,29 +10,8 @@ }, "warning": { "+": 0, - "-": 4, - "codes": [ - [ - "cpp/drivers/illegal-field-write The 'DeviceObject' field of the DriverObject struct is read-only.", - 2, - 0 - ], - [ - "cpp/drivers/illegal-field-write The 'DriverObject' field of the DeviceObject struct is read-only.", - 2, - 0 - ], - [ - "cpp/drivers/illegal-field-write The 'NextDevice' field of the DeviceObject struct is read-only.", - 1, - 0 - ], - [ - "cpp/drivers/illegal-field-write The 'SecurityDescriptor' field of the DeviceObject struct is read-only.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/MultiplePagedCode.sarif b/src/drivers/test/diff/MultiplePagedCode.sarif index d84a3a59..8d5a80f9 100644 --- a/src/drivers/test/diff/MultiplePagedCode.sarif +++ b/src/drivers/test/diff/MultiplePagedCode.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/multiple-paged-code Functions in a paged section must have exactly one instance of the PAGED_CODE or PAGED_CODE_LOCKED macro", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/NoPagedCode.sarif b/src/drivers/test/diff/NoPagedCode.sarif index e317c641..8d5a80f9 100644 --- a/src/drivers/test/diff/NoPagedCode.sarif +++ b/src/drivers/test/diff/NoPagedCode.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/no-paged-code The function has been declared to be in a paged segment, but neither PAGED_CODE nor PAGED_CODE_LOCKED was found.", - 3, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/NoPagingSegment.sarif b/src/drivers/test/diff/NoPagingSegment.sarif index 6ef2c1d4..8d5a80f9 100644 --- a/src/drivers/test/diff/NoPagingSegment.sarif +++ b/src/drivers/test/diff/NoPagingSegment.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/no-paged-code The function has PAGED_CODE or PAGED_CODE_LOCKED but is not declared to be in a paged segment", - 2, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/OpaqueMdlWrite.sarif b/src/drivers/test/diff/OpaqueMdlWrite.sarif index acae8d46..8d5a80f9 100644 --- a/src/drivers/test/diff/OpaqueMdlWrite.sarif +++ b/src/drivers/test/diff/OpaqueMdlWrite.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/opaque-mdl-write The driver is writing to an opaque MDL field (ByteCount). MDLs are semi-opaque and opaque fields should not be modified.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/StrSafe.sarif b/src/drivers/test/diff/StrSafe.sarif index 08ebd237..8d5a80f9 100644 --- a/src/drivers/test/diff/StrSafe.sarif +++ b/src/drivers/test/diff/StrSafe.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 1 + "-": 0 }, "error": { "+": 0, @@ -10,14 +10,8 @@ }, "warning": { "+": 0, - "-": 1, - "codes": [ - [ - "cpp/drivers/str-safe Kernel Mode drivers should use ntstrsafe.h, not strsafe.h. Found in source file", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif index 7b0d7fc4..8d5a80f9 100644 --- a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif +++ b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 3 + "-": 0 }, "error": { "+": 0, @@ -10,24 +10,8 @@ }, "warning": { "+": 0, - "-": 3, - "codes": [ - [ - "cpp/drivers/wrong-dispatch-table-assignment The dispatch function does not have a dispatch type annotation matching this dispatch table entry.", - 1, - 0 - ], - [ - "cpp/drivers/wrong-dispatch-table-assignment Dispatch table assignment should have a DRIVER_DISPATCH type routine as its right-hand side value.", - 1, - 0 - ], - [ - "cpp/drivers/wrong-dispatch-table-assignment The dispatch function does not have a dispatch type annotation.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, From a8be8d06ce5e2704d122d4e4060809145a2a102f Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:20:48 -0700 Subject: [PATCH 41/54] Fix bug in driver_snippet.c that stopped compilation. --- .../queries/experimental/IrqlSetTooHigh/driver_snippet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 6a38792a..1cb39b61 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -170,7 +170,7 @@ _IRQL_requires_same_ VOID IrqlRequiresSame_notsupported(void) { - KIRQL oldIRQL; + KIRQL oldIRQL = PASSIVE_LEVEL; KeRaiseIrql(oldIRQL+1, &oldIRQL); } From 9e5ae32394a3e411584e20e992a697add48b30b5 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:28:58 -0700 Subject: [PATCH 42/54] Fix bug in IrqlSetTooHigh Also refactor IrqlSetTooLow to match --- .../queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql | 2 +- .../queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql index 4f0d0d16..11cbc3b0 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -23,11 +23,11 @@ import cpp import drivers.libraries.Irql +bindingset[irqlRequirement] predicate tooHighForFunc( IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement ) { statement.getControlFlowScope() = irqlFunc and - irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement and irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 } diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql index 51e6466e..1a894fa4 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql @@ -23,17 +23,18 @@ import cpp import drivers.libraries.Irql +bindingset[irqlRequirement] predicate tooLowForFunc( IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement ) { statement.getControlFlowScope() = irqlFunc and - irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and irqlRequirement > max(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 } from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement where + irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and tooLowForFunc(irqlFunc, statement, irqlRequirement) and // Only get the first node which is set too low not exists(ControlFlowNode otherNode | From ad31f7a3787d4472b1f8bde0b8aa5ccf1833fc64 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:55:20 -0700 Subject: [PATCH 43/54] Fix up test results for IRQL queries --- .../IrqlSetTooHigh/IrqlSetTooHigh.sarif | 548 +++++++++++++----- .../IrqlSetTooLow/IrqlSetTooLow.sarif | 375 +++++++++++- src/drivers/test/diff/IrqlSetTooHigh.sarif | 92 +-- src/drivers/test/diff/IrqlTooHigh.sarif | 22 +- src/drivers/test/diff/IrqlTooLow.sarif | 17 +- 5 files changed, 767 insertions(+), 287 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif index 5e46fa5e..35ad3d14 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.sarif @@ -1,173 +1,425 @@ { - "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", - "version" : "2.1.0", - "runs" : [ { - "tool" : { - "driver" : { - "name" : "CodeQL", - "organization" : "GitHub", - "semanticVersion" : "2.14.6", - "notifications" : [ { - "id" : "cpp/baseline/expected-extracted-files", - "name" : "cpp/baseline/expected-extracted-files", - "shortDescription" : { - "text" : "Expected extracted files" - }, - "fullDescription" : { - "text" : "Files appearing in the source archive that are expected to be extracted." - }, - "defaultConfiguration" : { - "enabled" : true - }, - "properties" : { - "tags" : [ "expected-extracted-files", "telemetry" ] - } - } ], - "rules" : [ { + "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", + "version" : "2.1.0", + "runs" : [ { + "tool" : { + "driver" : { + "name" : "CodeQL", + "organization" : "GitHub", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], + "rules" : [ { + "id" : "cpp/drivers/irql-set-too-high", + "name" : "cpp/drivers/irql-set-too-high", + "shortDescription" : { + "text" : "IRQL set too high (C28150)" + }, + "fullDescription" : { + "text" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "properties" : { + "tags" : [ "correctness", "wddst" ], + "description" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount.", + "feature.area" : "Multiple", "id" : "cpp/drivers/irql-set-too-high", - "name" : "cpp/drivers/irql-set-too-high", - "shortDescription" : { - "text" : "IRQL set too high (C28150)" - }, - "fullDescription" : { - "text" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount." - }, - "defaultConfiguration" : { - "enabled" : true, - "level" : "warning" - }, - "properties" : { - "tags" : [ "correctness", "wddst" ], - "description" : "A function annotated with a maximum IRQL for execution raises the IRQL above that amount.", - "feature.area" : "Multiple", - "id" : "cpp/drivers/irql-set-too-high", - "impact" : "Exploitable Design", - "kind" : "problem", - "name" : "IRQL set too high (C28150)", - "opaqueid" : "CQLD-C28150", - "owner.email" : "sdat@microsoft.com", - "platform" : "Desktop", - "precision" : "medium", - "problem.severity" : "warning", - "query-version" : "v2", - "repro.text" : "The following statement exits at an IRQL too high for the function it is contained in.", - "scope" : "domainspecific", - "security.severity" : "Low" - } - } ] - }, - "extensions" : [ { - "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.2.0+bb06b891b948b1c3e773bdaaf23a43895efe761c", - "locations" : [ { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", - "description" : { - "text" : "The QL pack root directory." - } - }, { - "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." - } - } ] + "impact" : "Exploitable Design", + "kind" : "problem", + "name" : "IRQL set too high (C28150)", + "opaqueid" : "CQLD-C28150", + "owner.email" : "sdat@microsoft.com", + "platform" : "Desktop", + "precision" : "medium", + "problem.severity" : "warning", + "query-version" : "v1", + "repro.text" : "The following statement exits at an IRQL too high for the function it is contained in.", + "scope" : "domainspecific", + "security.severity" : "Low" + } } ] }, - "invocations" : [ { - "toolExecutionNotifications" : [ { - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/fail_driver1.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - } + "extensions" : [ { + "name" : "microsoft/windows-drivers", + "semanticVersion" : "0.2.0+9e5ae32394a3e411584e20e992a697add48b30b5", + "locations" : [ { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", + "description" : { + "text" : "The QL pack root directory." + } + }, { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", + "description" : { + "text" : "The QL pack definition file." + } + } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 } - } ], - "message" : { + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { "text" : "" - }, - "level" : "none", - "descriptor" : { - "id" : "cpp/baseline/expected-extracted-files", - "index" : 0 - }, - "properties" : { - "formattedMessage" : { - "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 } } - }, { - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 1 - } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 } - } ], - "message" : { + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], + "artifacts" : [ { + "location" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } ], + "results" : [ { + "ruleId" : "cpp/drivers/irql-set-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-high", + "index" : 0 + }, + "message" : { + "text" : "[CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [call to IrqlSetHigherFromPassive_pass0](2). Maximum IRQL for this function: 0, IRQL at statement: 2" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 }, - "level" : "none", - "descriptor" : { - "id" : "cpp/baseline/expected-extracted-files", + "region" : { + "startLine" : 131, + "startColumn" : 5, + "endColumn" : 35 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "50d7736bf7d9212d:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", "index" : 0 }, - "properties" : { - "formattedMessage" : { - "text" : "" - } + "region" : { + "startLine" : 129, + "startColumn" : 10, + "endColumn" : 42 } - }, { - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/fail_driver1.h", - "uriBaseId" : "%SRCROOT%", - "index" : 2 - } - } - } ], - "message" : { - "text" : "" + }, + "message" : { + "text" : "CallFunctionThatRaisesIRQL_fail5" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 }, - "level" : "none", - "descriptor" : { - "id" : "cpp/baseline/expected-extracted-files", + "region" : { + "startLine" : 131, + "startColumn" : 5, + "endColumn" : 35 + } + }, + "message" : { + "text" : "call to IrqlSetHigherFromPassive_pass0" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-set-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-high", + "index" : 0 + }, + "message" : { + "text" : "[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [call to KfRaiseIrql](2). Maximum IRQL for this function: 0, IRQL at statement: 2" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", "index" : 0 }, - "properties" : { - "formattedMessage" : { - "text" : "" - } + "region" : { + "startLine" : 121, + "startColumn" : 5, + "endColumn" : 42 } - } ], - "executionSuccessful" : true + } } ], - "artifacts" : [ { - "location" : { - "uri" : "driver/fail_driver1.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 + "partialFingerprints" : { + "primaryLocationLineHash" : "b7bb153208f2004d:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 118, + "startColumn" : 10, + "endColumn" : 38 + } + }, + "message" : { + "text" : "IrqlRaiseLevelExplicit_fail4" } }, { - "location" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 1 + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 121, + "startColumn" : 5, + "endColumn" : 42 + } + }, + "message" : { + "text" : "call to KfRaiseIrql" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-set-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-high", + "index" : 0 + }, + "message" : { + "text" : "[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [call to KfRaiseIrql](2). Maximum IRQL for this function: 0, IRQL at statement: 2" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 112, + "startColumn" : 5, + "endColumn" : 42 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "988957c55591351a:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 109, + "startColumn" : 10, + "endColumn" : 38 + } + }, + "message" : { + "text" : "IrqlRaiseLevelExplicit_fail3" } }, { - "location" : { - "uri" : "driver/fail_driver1.h", - "uriBaseId" : "%SRCROOT%", - "index" : 2 + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 112, + "startColumn" : 5, + "endColumn" : 42 + } + }, + "message" : { + "text" : "call to KfRaiseIrql" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-set-too-high", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-high", + "index" : 0 + }, + "message" : { + "text" : "[IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [call to KfRaiseIrql](2). Maximum IRQL for this function: 1, IRQL at statement: 2" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 102, + "startColumn" : 5, + "endColumn" : 42 + } } } ], - "results" : [ ], - "columnKind" : "utf16CodeUnits", - "properties" : { - "semmle.formatSpecifier" : "sarifv2.1.0" - } - } ] - } \ No newline at end of file + "partialFingerprints" : { + "primaryLocationLineHash" : "71b218a9127ea6cb:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 99, + "startColumn" : 10, + "endColumn" : 38 + } + }, + "message" : { + "text" : "IrqlRaiseLevelExplicit_fail0" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 102, + "startColumn" : 5, + "endColumn" : 42 + } + }, + "message" : { + "text" : "call to KfRaiseIrql" + } + } ] + } ], + "columnKind" : "utf16CodeUnits", + "properties" : { + "semmle.formatSpecifier" : "sarifv2.1.0" + } + } ] +} \ No newline at end of file diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif index 8d5a80f9..bc06b3b7 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.sarif @@ -1,21 +1,362 @@ { - "all": { - "+": 0, - "-": 0 + "$schema" : "https://json.schemastore.org/sarif-2.1.0.json", + "version" : "2.1.0", + "runs" : [ { + "tool" : { + "driver" : { + "name" : "CodeQL", + "organization" : "GitHub", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], + "rules" : [ { + "id" : "cpp/drivers/irql-set-too-low", + "name" : "cpp/drivers/irql-set-too-low", + "shortDescription" : { + "text" : "IRQL set too low (C28124)" + }, + "fullDescription" : { + "text" : "A function annotated with a minimum IRQL for execution lowers the IRQL below that amount." + }, + "defaultConfiguration" : { + "enabled" : true, + "level" : "warning" + }, + "properties" : { + "tags" : [ "correctness", "wddst" ], + "description" : "A function annotated with a minimum IRQL for execution lowers the IRQL below that amount.", + "feature.area" : "Multiple", + "id" : "cpp/drivers/irql-set-too-low", + "impact" : "Exploitable Design", + "kind" : "problem", + "name" : "IRQL set too low (C28124)", + "opaqueid" : "CQLD-C28124", + "owner.email" : "sdat@microsoft.com", + "platform" : "Desktop", + "precision" : "medium", + "problem.severity" : "warning", + "query-version" : "v1", + "repro.text" : "The following statement exits at an IRQL too low for the function it is contained in.", + "scope" : "domainspecific", + "security.severity" : "Low" + } + } ] + }, + "extensions" : [ { + "name" : "microsoft/windows-drivers", + "semanticVersion" : "0.2.0+9e5ae32394a3e411584e20e992a697add48b30b5", + "locations" : [ { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", + "description" : { + "text" : "The QL pack root directory." + } + }, { + "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/qlpack.yml", + "description" : { + "text" : "The QL pack definition file." + } + } ] + } ] }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], + "artifacts" : [ { + "location" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } ], + "results" : [ { + "ruleId" : "cpp/drivers/irql-set-too-low", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-low", + "index" : 0 + }, + "message" : { + "text" : "[IrqlAlwaysMinAPC_fail](1): IRQL potentially set too low at [call to KeLowerIrql](2). Minimum IRQL for this function: 1, IRQL at statement: 0" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 92, + "startColumn" : 5, + "endColumn" : 16 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "8a19ae2477ed23d3:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 90, + "startColumn" : 10, + "endColumn" : 31 + } + }, + "message" : { + "text" : "IrqlAlwaysMinAPC_fail" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 92, + "startColumn" : 5, + "endColumn" : 16 + } + }, + "message" : { + "text" : "call to KeLowerIrql" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-set-too-low", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-low", + "index" : 0 + }, + "message" : { + "text" : "[IrqlMinDispatchLowerIrql_fail1](1): IRQL potentially set too low at [call to KeLowerIrql](2). Minimum IRQL for this function: 2, IRQL at statement: 1" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 59, + "startColumn" : 5, + "endColumn" : 16 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "c6798a9b4760c05b:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 57, + "startColumn" : 10, + "endColumn" : 40 + } + }, + "message" : { + "text" : "IrqlMinDispatchLowerIrql_fail1" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 59, + "startColumn" : 5, + "endColumn" : 16 + } + }, + "message" : { + "text" : "call to KeLowerIrql" + } + } ] + }, { + "ruleId" : "cpp/drivers/irql-set-too-low", + "ruleIndex" : 0, + "rule" : { + "id" : "cpp/drivers/irql-set-too-low", + "index" : 0 + }, + "message" : { + "text" : "[IrqlMinDispatchLowerIrql_fail](1): IRQL potentially set too low at [{{ ... }}](2). Minimum IRQL for this function: 2, IRQL at statement: 1" + }, + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "endLine" : 44, + "endColumn" : 2 + } + } + } ], + "partialFingerprints" : { + "primaryLocationLineHash" : "83574f45ab0b5d97:1", + "primaryLocationStartColumnFingerprint" : "0" + }, + "relatedLocations" : [ { + "id" : 1, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 41, + "startColumn" : 10, + "endColumn" : 39 + } + }, + "message" : { + "text" : "IrqlMinDispatchLowerIrql_fail" + } + }, { + "id" : 2, + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + }, + "region" : { + "startLine" : 42, + "endLine" : 44, + "endColumn" : 2 + } + }, + "message" : { + "text" : "{{ ... }}" + } + } ] + } ], + "columnKind" : "utf16CodeUnits", + "properties" : { + "semmle.formatSpecifier" : "sarifv2.1.0" } + } ] } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index c724da45..8d5a80f9 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,6 +1,6 @@ { "all": { - "+": 17, + "+": 0, "-": 0 }, "error": { @@ -9,95 +9,9 @@ "codes": [] }, "warning": { - "+": 17, + "+": 0, "-": 0, - "codes": [ - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 2 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail0](1). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [CallFunctionThatRaisesIRQL_fail5](1). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [call to IrqlSetHigherFromPassive_pass0](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [CallFunctionThatRaisesIRQL_fail5](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail4](1): IRQL potentially set too high at [ExprStmt](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [IrqlRaiseLevelExplicit_fail3](1). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 0, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail3](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 0, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [oldIRQL](2). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [& ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [* ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [call to KfRaiseIrql](3). Maximum IRQL for this function: 1, IRQL at statement: 2\n[IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [... = ...](4). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ], - [ - "cpp/drivers/irql-set-too-high [IrqlRaiseLevelExplicit_fail0](1): IRQL potentially set too high at [return ...](2). Maximum IRQL for this function: 1, IRQL at statement: 2", - 0, - 1 - ] - ] + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IrqlTooHigh.sarif b/src/drivers/test/diff/IrqlTooHigh.sarif index d26ced59..8d5a80f9 100644 --- a/src/drivers/test/diff/IrqlTooHigh.sarif +++ b/src/drivers/test/diff/IrqlTooHigh.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 3 + "-": 0 }, "error": { "+": 0, @@ -10,24 +10,8 @@ }, "warning": { "+": 0, - "-": 3, - "codes": [ - [ - "cpp/drivers/irql-too-high IRQL potentially too high at this call ([TestInner2](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)", - 1, - 0 - ], - [ - "cpp/drivers/irql-too-high IRQL potentially too high at this call ([TestInner4](1)). Maximum irql level of this call: [0](2), Irql level at preceding node: [2](3)", - 1, - 0 - ], - [ - "cpp/drivers/irql-too-high IRQL potentially too high at this call ([IoGetInitialStack](1)). Maximum irql level of this call: [1](2), Irql level at preceding node: [2](3)", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IrqlTooLow.sarif b/src/drivers/test/diff/IrqlTooLow.sarif index 1e452b32..8d5a80f9 100644 --- a/src/drivers/test/diff/IrqlTooLow.sarif +++ b/src/drivers/test/diff/IrqlTooLow.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 2 + "-": 0 }, "error": { "+": 0, @@ -10,19 +10,8 @@ }, "warning": { "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/irql-too-low IRQL potentially too low at this call ([TestInner2](1)). Minimum irql level of this call: [1](2), Irql level at preceding node: [0](3)", - 1, - 0 - ], - [ - "cpp/drivers/irql-too-low IRQL potentially too low at this call ([TestInner3](1)). Minimum irql level of this call: [2](2), Irql level at preceding node: [0](3)", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, From d60f7bfc7b0eebaa8db03cd6e1954fa963c8e00f Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:47:48 -0700 Subject: [PATCH 44/54] Fix typos --- src/drivers/libraries/IrqlDataFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/libraries/IrqlDataFlow.qll b/src/drivers/libraries/IrqlDataFlow.qll index c866c76d..bf32d1bf 100644 --- a/src/drivers/libraries/IrqlDataFlow.qll +++ b/src/drivers/libraries/IrqlDataFlow.qll @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** - * Provides cata-flow analyses used in calculating the IRQL in a Windwos driver. + * Provides data-flow analyses used in calculating the IRQL in a Windows driver. */ From 17345f1f7746e14a5832db09097b20aa4f799242 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:28:58 -0700 Subject: [PATCH 45/54] Fix bug in IrqlSetTooHigh Also refactor IrqlSetTooLow to match --- .../queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql | 2 +- .../queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql index 4f0d0d16..11cbc3b0 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql @@ -23,11 +23,11 @@ import cpp import drivers.libraries.Irql +bindingset[irqlRequirement] predicate tooHighForFunc( IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement ) { statement.getControlFlowScope() = irqlFunc and - irqlFunc.(IrqlAlwaysMaxFunction).getIrqlLevel() = irqlRequirement and irqlRequirement < min(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 } diff --git a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql index 51e6466e..1a894fa4 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql +++ b/src/drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql @@ -23,17 +23,18 @@ import cpp import drivers.libraries.Irql +bindingset[irqlRequirement] predicate tooLowForFunc( IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement ) { statement.getControlFlowScope() = irqlFunc and - irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and irqlRequirement > max(getPotentialExitIrqlAtCfn(statement)) and irqlRequirement != -1 } from IrqlRestrictsFunction irqlFunc, ControlFlowNode statement, int irqlRequirement where + irqlFunc.(IrqlAlwaysMinFunction).getIrqlLevel() = irqlRequirement and tooLowForFunc(irqlFunc, statement, irqlRequirement) and // Only get the first node which is set too low not exists(ControlFlowNode otherNode | From b210ca99ce42d97222b404697ae11861f64530d9 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:21:35 -0700 Subject: [PATCH 46/54] Fix line endings in diffs --- src/drivers/test/diff/ExaminedValue.sarif | 40 ++++++------ .../test/diff/IllegalFieldAccess.sarif | 40 ++++++------ .../test/diff/IllegalFieldAccess2.sarif | 40 ++++++------ src/drivers/test/diff/IllegalFieldWrite.sarif | 40 ++++++------ src/drivers/test/diff/IrqlNotSaved.sarif | 62 +++++++++---------- src/drivers/test/diff/IrqlNotUsed.sarif | 62 +++++++++---------- src/drivers/test/diff/IrqlSetTooHigh.sarif | 40 ++++++------ src/drivers/test/diff/IrqlSetTooLow.sarif | 40 ++++++------ src/drivers/test/diff/IrqlTooHigh.sarif | 40 ++++++------ src/drivers/test/diff/IrqlTooLow.sarif | 40 ++++++------ src/drivers/test/diff/KeWaitLocal.sarif | 62 +++++++++---------- src/drivers/test/diff/MultiplePagedCode.sarif | 40 ++++++------ src/drivers/test/diff/NoPagedCode.sarif | 40 ++++++------ src/drivers/test/diff/NoPagingSegment.sarif | 40 ++++++------ src/drivers/test/diff/OpaqueMdlUse.sarif | 40 ++++++------ src/drivers/test/diff/OpaqueMdlWrite.sarif | 40 ++++++------ .../test/diff/PendingStatusError.sarif | 40 ++++++------ src/drivers/test/diff/StrSafe.sarif | 40 ++++++------ .../diff/WrongDispatchTableAssignment.sarif | 40 ++++++------ 19 files changed, 413 insertions(+), 413 deletions(-) diff --git a/src/drivers/test/diff/ExaminedValue.sarif b/src/drivers/test/diff/ExaminedValue.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/ExaminedValue.sarif +++ b/src/drivers/test/diff/ExaminedValue.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldAccess.sarif b/src/drivers/test/diff/IllegalFieldAccess.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IllegalFieldAccess.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldAccess2.sarif b/src/drivers/test/diff/IllegalFieldAccess2.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IllegalFieldAccess2.sarif +++ b/src/drivers/test/diff/IllegalFieldAccess2.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IllegalFieldWrite.sarif b/src/drivers/test/diff/IllegalFieldWrite.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IllegalFieldWrite.sarif +++ b/src/drivers/test/diff/IllegalFieldWrite.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlNotSaved.sarif b/src/drivers/test/diff/IrqlNotSaved.sarif index 4b88bd8d..9084d2e5 100644 --- a/src/drivers/test/diff/IrqlNotSaved.sarif +++ b/src/drivers/test/diff/IrqlNotSaved.sarif @@ -1,32 +1,32 @@ -{ - "all": { - "+": 0, - "-": 2 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/irql-not-saved The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", - 1, - 0 - ], - [ - "cpp/drivers/irql-not-saved The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", - 1, - 0 - ] - ] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-saved The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-saved The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlNotUsed.sarif b/src/drivers/test/diff/IrqlNotUsed.sarif index e54b351e..6b40083a 100644 --- a/src/drivers/test/diff/IrqlNotUsed.sarif +++ b/src/drivers/test/diff/IrqlNotUsed.sarif @@ -1,32 +1,32 @@ -{ - "all": { - "+": 0, - "-": 2 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/irql-not-used This function has annotated the parameter [inIrql](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", - 1, - 0 - ], - [ - "cpp/drivers/irql-not-used This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", - 1, - 0 - ] - ] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 2 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [inIrql](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooHigh.sarif b/src/drivers/test/diff/IrqlSetTooHigh.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IrqlSetTooHigh.sarif +++ b/src/drivers/test/diff/IrqlSetTooHigh.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlSetTooLow.sarif b/src/drivers/test/diff/IrqlSetTooLow.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IrqlSetTooLow.sarif +++ b/src/drivers/test/diff/IrqlSetTooLow.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlTooHigh.sarif b/src/drivers/test/diff/IrqlTooHigh.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IrqlTooHigh.sarif +++ b/src/drivers/test/diff/IrqlTooHigh.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlTooLow.sarif b/src/drivers/test/diff/IrqlTooLow.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/IrqlTooLow.sarif +++ b/src/drivers/test/diff/IrqlTooLow.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/KeWaitLocal.sarif b/src/drivers/test/diff/KeWaitLocal.sarif index b0674846..4ac852d9 100644 --- a/src/drivers/test/diff/KeWaitLocal.sarif +++ b/src/drivers/test/diff/KeWaitLocal.sarif @@ -1,32 +1,32 @@ -{ - "all": { - "+": 1, - "-": 1 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 1, - "-": 1, - "codes": [ - [ - "cpp/drivers/kewaitlocal-requires-kernel-mode [good_use](1): KeWaitForSingleObject should have a KernelMode AccessMode when the [first argument](2) is local", - 0, - 1 - ], - [ - "cpp/drivers/kewaitlocal-requires-kernel-mode KeWaitForSingleObject should have a KernelMode AccessMode when the first argument is local", - 1, - 0 - ] - ] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 1, + "-": 1 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 1, + "-": 1, + "codes": [ + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode [good_use](1): KeWaitForSingleObject should have a KernelMode AccessMode when the [first argument](2) is local", + 0, + 1 + ], + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode KeWaitForSingleObject should have a KernelMode AccessMode when the first argument is local", + 1, + 0 + ] + ] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/MultiplePagedCode.sarif b/src/drivers/test/diff/MultiplePagedCode.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/MultiplePagedCode.sarif +++ b/src/drivers/test/diff/MultiplePagedCode.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/NoPagedCode.sarif b/src/drivers/test/diff/NoPagedCode.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/NoPagedCode.sarif +++ b/src/drivers/test/diff/NoPagedCode.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/NoPagingSegment.sarif b/src/drivers/test/diff/NoPagingSegment.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/NoPagingSegment.sarif +++ b/src/drivers/test/diff/NoPagingSegment.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/OpaqueMdlUse.sarif b/src/drivers/test/diff/OpaqueMdlUse.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/OpaqueMdlUse.sarif +++ b/src/drivers/test/diff/OpaqueMdlUse.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/OpaqueMdlWrite.sarif b/src/drivers/test/diff/OpaqueMdlWrite.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/OpaqueMdlWrite.sarif +++ b/src/drivers/test/diff/OpaqueMdlWrite.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/PendingStatusError.sarif b/src/drivers/test/diff/PendingStatusError.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/PendingStatusError.sarif +++ b/src/drivers/test/diff/PendingStatusError.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/StrSafe.sarif b/src/drivers/test/diff/StrSafe.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/StrSafe.sarif +++ b/src/drivers/test/diff/StrSafe.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file diff --git a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif index 8d5a80f9..dea8275e 100644 --- a/src/drivers/test/diff/WrongDispatchTableAssignment.sarif +++ b/src/drivers/test/diff/WrongDispatchTableAssignment.sarif @@ -1,21 +1,21 @@ -{ - "all": { - "+": 0, - "-": 0 - }, - "error": { - "+": 0, - "-": 0, - "codes": [] - }, - "warning": { - "+": 0, - "-": 0, - "codes": [] - }, - "note": { - "+": 0, - "-": 0, - "codes": [] - } +{ + "all": { + "+": 0, + "-": 0 + }, + "error": { + "+": 0, + "-": 0, + "codes": [] + }, + "warning": { + "+": 0, + "-": 0, + "codes": [] + }, + "note": { + "+": 0, + "-": 0, + "codes": [] + } } \ No newline at end of file From 0cd51fb47ef10b95f7d5156d781d36a74b6725c7 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:44:05 -0700 Subject: [PATCH 47/54] Regressions due to IRQL changes (+1 benign change) --- src/drivers/test/diff/IrqlNotSaved.sarif | 17 ++++++++++++++--- src/drivers/test/diff/IrqlNotUsed.sarif | 17 ++++++++++++++--- src/drivers/test/diff/KeWaitLocal.sarif | 21 ++++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/drivers/test/diff/IrqlNotSaved.sarif b/src/drivers/test/diff/IrqlNotSaved.sarif index dea8275e..9084d2e5 100644 --- a/src/drivers/test/diff/IrqlNotSaved.sarif +++ b/src/drivers/test/diff/IrqlNotSaved.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 0 + "-": 2 }, "error": { "+": 0, @@ -10,8 +10,19 @@ }, "warning": { "+": 0, - "-": 0, - "codes": [] + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-saved The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-saved The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", + 1, + 0 + ] + ] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/IrqlNotUsed.sarif b/src/drivers/test/diff/IrqlNotUsed.sarif index dea8275e..6b40083a 100644 --- a/src/drivers/test/diff/IrqlNotUsed.sarif +++ b/src/drivers/test/diff/IrqlNotUsed.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 0 + "-": 2 }, "error": { "+": 0, @@ -10,8 +10,19 @@ }, "warning": { "+": 0, - "-": 0, - "codes": [] + "-": 2, + "codes": [ + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [inIrql](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ], + [ + "cpp/drivers/irql-not-used This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", + 1, + 0 + ] + ] }, "note": { "+": 0, diff --git a/src/drivers/test/diff/KeWaitLocal.sarif b/src/drivers/test/diff/KeWaitLocal.sarif index dea8275e..4ac852d9 100644 --- a/src/drivers/test/diff/KeWaitLocal.sarif +++ b/src/drivers/test/diff/KeWaitLocal.sarif @@ -1,7 +1,7 @@ { "all": { - "+": 0, - "-": 0 + "+": 1, + "-": 1 }, "error": { "+": 0, @@ -9,9 +9,20 @@ "codes": [] }, "warning": { - "+": 0, - "-": 0, - "codes": [] + "+": 1, + "-": 1, + "codes": [ + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode [good_use](1): KeWaitForSingleObject should have a KernelMode AccessMode when the [first argument](2) is local", + 0, + 1 + ], + [ + "cpp/drivers/kewaitlocal-requires-kernel-mode KeWaitForSingleObject should have a KernelMode AccessMode when the first argument is local", + 1, + 0 + ] + ] }, "note": { "+": 0, From 5d1f42e00a0c89f92350847502b4c33e25dc7eaf Mon Sep 17 00:00:00 2001 From: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:39:14 -0700 Subject: [PATCH 48/54] Update src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Signed-off-by: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> --- .../queries/experimental/IrqlSetTooHigh/driver_snippet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 1cb39b61..0d632b47 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -192,7 +192,8 @@ _IRQL_requires_same_ Function that calls another function by reference which correctly raises the IRQL. This should pass since IrqlInderectCall_pass0 is not annotated for max IRQL. */ -VOID IrqlInderectCall_pass0(void) +VOID IrqlIndirectCall_pass0(void) + { void (*funcPtr)(void); funcPtr = &IrqlSetHigherFromPassive_pass0; From b43719f27d119fa9d6acfcb91787e9762beb83c4 Mon Sep 17 00:00:00 2001 From: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:39:23 -0700 Subject: [PATCH 49/54] Update src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Signed-off-by: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> --- .../queries/experimental/IrqlSetTooHigh/driver_snippet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 0d632b47..6619722a 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -204,7 +204,8 @@ Function that calls another function by reference which correctly raises the IRQ This should pass since IrqlInderectCall_pass0 is annotated for max DISPATCH_LEVEL. */ _IRQL_always_function_max_(DISPATCH_LEVEL) -VOID IrqlInderectCall_pass1(void) +VOID IrqlIndirectCall_pass1(void) + { void (*funcPtr)(void); funcPtr = &IrqlSetHigherFromPassive_pass0; From 1d5253638c70f21be361c048a878952c0934fb8f Mon Sep 17 00:00:00 2001 From: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:39:36 -0700 Subject: [PATCH 50/54] Update src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Signed-off-by: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> --- .../queries/experimental/IrqlSetTooHigh/driver_snippet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 6619722a..8623b22e 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -216,7 +216,8 @@ VOID IrqlIndirectCall_pass1(void) Function that calls another function by reference which incorrectly raises the IRQL. This should fail because the function pointer points to a function that should fail. */ -VOID IrqlInderectCall_fail0(void) +VOID IrqlIndirectCall_fail0(void) + { void (*funcPtr)(void); funcPtr = &IrqlRaiseLevelExplicit_fail0; From 6f065ac89e942da3d187a7c7d0b75ac43b061f82 Mon Sep 17 00:00:00 2001 From: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:39:42 -0700 Subject: [PATCH 51/54] Update src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c Co-authored-by: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Signed-off-by: Jacob Ronstadt <147542405+jacob-ronstadt@users.noreply.github.com> --- .../queries/experimental/IrqlSetTooHigh/driver_snippet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c index 8623b22e..2dc1afc3 100644 --- a/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c +++ b/src/drivers/general/queries/experimental/IrqlSetTooHigh/driver_snippet.c @@ -228,7 +228,8 @@ Function that calls another function by reference which incorrectly raises the I This should fail because the function pointer points to a function that that raises the IRQL above PASSIVE_LEVEL. */ _IRQL_always_function_max_(PASSIVE_LEVEL) -VOID IrqlInderectCall_fail1(void) +VOID IrqlIndirectCall_fail1(void) + { void (*funcPtr)(void); funcPtr = &IrqlSetHigherFromPassive_pass0; From 079028b57055ccd2fea3bae5a9ecc283d9ee56bb Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:45:54 -0700 Subject: [PATCH 52/54] Fix IrqlNotSaved with the new library. --- .../queries/IrqlNotSaved/IrqlNotSaved.ql | 104 +++++------ .../queries/IrqlNotSaved/IrqlNotSaved.sarif | 171 +++++++++++------- .../queries/IrqlNotSaved/driver_snippet.c | 18 +- src/drivers/test/diff/IrqlNotSaved.sarif | 17 +- 4 files changed, 160 insertions(+), 150 deletions(-) diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql index ecfcfdb2..709faec2 100644 --- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql +++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.ql @@ -22,23 +22,8 @@ import cpp import drivers.libraries.Irql -import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.dataflow.DataFlow2 - -/** - * A function that has at least one parameter annotated with "\_IRQL\_save\_". - */ -class IrqlSaveFunction extends Function { - Parameter p; - int irqlIndex; - - IrqlSaveFunction() { - p = this.getParameter(irqlIndex) and - p instanceof IrqlSaveParameter - } - - int getIrqlIndex() { result = irqlIndex } -} +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.DataFlow2 /** * A data-flow configuration describing flow from an @@ -55,7 +40,12 @@ class IrqlFlowConfiguration extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { exists(FunctionCall fc, FundamentalIrqlSaveFunction fisf | fc.getTarget() = fisf and - sink.asExpr() = fc.getArgument(fisf.getIrqlIndex()) + ( + sink.asExpr() = + fc.getArgument(fisf.(IrqlSavesGlobalAnnotatedFunction).getIrqlParameterSlot()) + or + sink.asExpr() = fc.getArgument(fisf.(IrqlSavesToParameterFunction).getIrqlParameterSlot()) + ) ) } } @@ -65,17 +55,25 @@ class IrqlFlowConfiguration extends DataFlow::Configuration { * by the Windows OS itself. This is in general in a Windows Kits header. For * extra clarity and internal use, we also list the exact header files. */ -class FundamentalIrqlSaveFunction extends IrqlSaveFunction { +class FundamentalIrqlSaveFunction extends IrqlSavesFunction { FundamentalIrqlSaveFunction() { - this.getFile().getAbsolutePath().matches("%Windows Kits%.h") or - this.getFile() - .getBaseName() - .matches(["wdm.h", "wdfsync.h", "ntifs.h", "ndis.h", "video.h", "wdfinterrupt.h"]) + ( + this.getFile().getAbsolutePath().matches("%Windows Kits%.h") + or + this.getFile() + .getBaseName() + .matches(["wdm.h", "wdfsync.h", "ntifs.h", "ndis.h", "video.h", "wdfinterrupt.h"]) + ) and + ( + this instanceof IrqlSavesToParameterFunction or + this instanceof IrqlSavesViaReturnFunction or + this instanceof IrqlSavesGlobalAnnotatedFunction + ) } } /** - * A simple data flow from any IrqlSaveParameter to another variable. + * A simple data flow from any IrqlSaveParameter. */ class IrqlSaveParameterFlowConfiguration extends DataFlow2::Configuration { IrqlSaveParameterFlowConfiguration() { this = "IrqlSaveParameterFlowConfiguration" } @@ -84,7 +82,7 @@ class IrqlSaveParameterFlowConfiguration extends DataFlow2::Configuration { source.asParameter() instanceof IrqlSaveParameter } - override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof VariableAccess } + override predicate isSink(DataFlow::Node sink) { sink instanceof DataFlow::Node } } /** @@ -97,29 +95,15 @@ class IrqlAssignmentFlowConfiguration extends DataFlow::Configuration { override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof FunctionCall and - source - .asExpr() - .(FunctionCall) - .getTarget() - .getName() - .matches([ - "KeRaiseIrqlToDpcLevel", "KfRaiseIrql", "KfAcquireSpinLock", - "KeAcquireSpinLockAtDpcLevel", "KeAcquireSpinLock", "KeAcquireSpinLockRaiseToDpc" - ]) + source.asExpr().(FunctionCall).getTarget() instanceof FundamentalIrqlSaveFunction and + source.asExpr().(FunctionCall).getTarget() instanceof IrqlSavesViaReturnFunction } override predicate isSink(DataFlow::Node sink) { - // Either we're sinking to a direct reference of a parameter, or... - sink.asExpr().(VariableAccess).getTarget() instanceof IrqlSaveParameter - or - // We a dereferenced pointer to the variable. - sink.asPartialDefinition() - .(PointerDereferenceExpr) - .getOperand() - .(AddressOfExpr) - .getOperand() - .(VariableAccess) - .getTarget() instanceof IrqlSaveVariableFlowedTo + exists(Assignment a | + a.getLValue().getAChild*().(VariableAccess).getTarget() instanceof IrqlSaveVariableFlowedTo and + a.getRValue() = sink.asExpr() + ) } } @@ -132,11 +116,14 @@ class IrqlSaveVariableFlowedTo extends Variable { IrqlSaveVariableFlowedTo() { exists( - IrqlSaveParameterFlowConfiguration difca, DataFlow::Node parameter, DataFlow::Node access + IrqlSaveParameterFlowConfiguration ispfc, DataFlow::Node parameter, DataFlow::Node assignment | - access.asExpr().(VariableAccess).getTarget() = this and + ( + this.getAnAssignedValue() = assignment.asExpr() or + this = assignment.asParameter() + ) and parameter.asParameter() = isp and - difca.hasFlow(parameter, access) + ispfc.hasFlow(parameter, assignment) ) or this = isp @@ -150,26 +137,19 @@ where // Exclude OS functions not isp.getFunction() instanceof FundamentalIrqlSaveFunction and /* - * Case one: does the IrqlSaveParameter (or an alias of it) have the IRQL assigned to it - * directly by calling, for example, KeRaiseIrql? + * Case one: does the IrqlSaveParameter (or an alias of it) have the IRQL assigned to it + * directly by calling, for example, KeRaiseIrql? */ not exists( - DataFlow::Node node, IrqlSaveVariableFlowedTo isvft, IrqlAssignmentFlowConfiguration difc + DataFlow::Node node, IrqlSaveVariableFlowedTo isvft, IrqlAssignmentFlowConfiguration iafc | isvft.getSaveParameter() = isp and - ( - node.asExpr().(VariableAccess).getTarget() = isvft - or - node.asPartialDefinition() - .(PointerDereferenceExpr) - .getOperand() - .(AddressOfExpr) - .getOperand() - .(VariableAccess) - .getTarget() = isvft + exists(Assignment a | + a.getLValue().getAChild*().(VariableAccess).getTarget() = isvft and + a.getRValue() = node.asExpr() ) and - difc.hasFlow(_, node) + iafc.hasFlow(_, node) ) and // Case two: is the IrqlSaveParameter passed into an OS function that will save a value to it? not exists(DataFlow::Node node, IrqlFlowConfiguration ifc | diff --git a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif index e945eee7..ebd33304 100644 --- a/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif +++ b/src/drivers/general/queries/IrqlNotSaved/IrqlNotSaved.sarif @@ -6,7 +6,23 @@ "driver" : { "name" : "CodeQL", "organization" : "GitHub", - "semanticVersion" : "2.11.5", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], "rules" : [ { "id" : "cpp/drivers/irql-not-saved", "name" : "cpp/drivers/irql-not-saved", @@ -42,7 +58,7 @@ }, "extensions" : [ { "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.1.0+933e876f096a70922173e4d5ad604d99d4481af4", + "semanticVersion" : "0.2.0+be14ce4fcaa9006e7636d8605fc53ea7c422a561", "locations" : [ { "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", "description" : { @@ -54,28 +70,99 @@ "text" : "The QL pack definition file." } } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } }, { - "name" : "legacy-upgrades", - "semanticVersion" : "0.0.0", "locations" : [ { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/", - "description" : { - "text" : "The QL pack root directory." + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } } - }, { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" } - } ] - } ] - }, + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], "artifacts" : [ { "location" : { "uri" : "driver/driver_snippet.c", "uriBaseId" : "%SRCROOT%", "index" : 0 } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } } ], "results" : [ { "ruleId" : "cpp/drivers/irql-not-saved", @@ -85,7 +172,7 @@ "index" : 0 }, "message" : { - "text" : "The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it." + "text" : "The parameter [outIrqlFail](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it." }, "locations" : [ { "physicalLocation" : { @@ -97,12 +184,12 @@ "region" : { "startLine" : 51, "startColumn" : 44, - "endColumn" : 51 + "endColumn" : 55 } } } ], "partialFingerprints" : { - "primaryLocationLineHash" : "6276e1ac4864af21:1", + "primaryLocationLineHash" : "e054bbd9d7acc717:1", "primaryLocationStartColumnFingerprint" : "43" }, "relatedLocations" : [ { @@ -116,57 +203,11 @@ "region" : { "startLine" : 51, "startColumn" : 44, - "endColumn" : 51 - } - }, - "message" : { - "text" : "outIrql" - } - } ] - }, { - "ruleId" : "cpp/drivers/irql-not-saved", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/drivers/irql-not-saved", - "index" : 0 - }, - "message" : { - "text" : "The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 43, - "startColumn" : 48, - "endColumn" : 54 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "342705500599b584:1", - "primaryLocationStartColumnFingerprint" : "47" - }, - "relatedLocations" : [ { - "id" : 1, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 43, - "startColumn" : 48, - "endColumn" : 54 + "endColumn" : 55 } }, "message" : { - "text" : "myLock" + "text" : "outIrqlFail" } } ] } ], diff --git a/src/drivers/general/queries/IrqlNotSaved/driver_snippet.c b/src/drivers/general/queries/IrqlNotSaved/driver_snippet.c index 95508dd0..449039b1 100644 --- a/src/drivers/general/queries/IrqlNotSaved/driver_snippet.c +++ b/src/drivers/general/queries/IrqlNotSaved/driver_snippet.c @@ -17,24 +17,24 @@ void top_level_call() {} /* Auxillary function used in passing. Note that even though this function doesn't annotate KIRQL, it restores the IRQL correctly. */ -VOID IrqlNotSaved_passAux(KIRQL outIrql) { +VOID IrqlNotSaved_passAux(KIRQL outIrqlPassAux) { - KeRaiseIrql(KeGetCurrentIrql(), &outIrql); + KeRaiseIrql(KeGetCurrentIrql(), &outIrqlPassAux); } /* Passing case one. Function directly calls a function that saves IRQL. */ -VOID IrqlNotSaved_pass(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) { +VOID IrqlNotSaved_pass(_IRQL_saves_ KIRQL outIrqlPass, PKSPIN_LOCK myLock) { - KeAcquireSpinLock(myLock, &outIrql); + KeAcquireSpinLock(myLock, &outIrqlPass); } /* Passing case two. Function indirectly calls a function that saves IRQL. */ -VOID IrqlNotSaved_pass2(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) { +VOID IrqlNotSaved_pass2(_IRQL_saves_ KIRQL outIrqlPass2, PKSPIN_LOCK myLock) { - IrqlNotSaved_passAux(outIrql); + IrqlNotSaved_passAux(outIrqlPass2); } @@ -48,16 +48,16 @@ VOID IrqlNotSaved_pass3(_IRQL_saves_ PTestLock myLock) { /* Failing case one. Function does nothing with IRQL. */ -VOID IrqlNotSaved_fail1(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock) { +VOID IrqlNotSaved_fail1(_IRQL_saves_ KIRQL outIrqlFail, PKSPIN_LOCK myLock) { } /* Failing case two. Function has a path where the IRQL is not saved. This requires must-flow analysis. */ -VOID IrqlNotSaved_fail2(_IRQL_saves_ KIRQL outIrql, PKSPIN_LOCK myLock, int testValue) { +VOID IrqlNotSaved_fail2(_IRQL_saves_ KIRQL outIrqlFail2, PKSPIN_LOCK myLock, int testValue) { - if (testValue > 15) {KeRaiseIrql(KeGetCurrentIrql(), &outIrql); } + if (testValue > 15) {KeRaiseIrql(KeGetCurrentIrql(), &outIrqlFail2); } else { } } \ No newline at end of file diff --git a/src/drivers/test/diff/IrqlNotSaved.sarif b/src/drivers/test/diff/IrqlNotSaved.sarif index 9084d2e5..dea8275e 100644 --- a/src/drivers/test/diff/IrqlNotSaved.sarif +++ b/src/drivers/test/diff/IrqlNotSaved.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 2 + "-": 0 }, "error": { "+": 0, @@ -10,19 +10,8 @@ }, "warning": { "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/irql-not-saved The parameter [outIrql](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", - 1, - 0 - ], - [ - "cpp/drivers/irql-not-saved The parameter [myLock](1) is annotated \"_IRQL_saves_\" but never has the IRQL saved to it.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, From 51234e2b97dc2cad9a4c3e0b5348e6c1324e90f6 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:04:29 -0700 Subject: [PATCH 53/54] Update InitNotUsed with new DataFlow and a fix. Removes a false positive in our unit tests. --- .../queries/IrqlNotUsed/IrqlNotUsed.ql | 9 +- .../queries/IrqlNotUsed/IrqlNotUsed.sarif | 161 +++++++++++------- src/drivers/test/diff/IrqlNotUsed.sarif | 17 +- 3 files changed, 111 insertions(+), 76 deletions(-) diff --git a/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.ql b/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.ql index cca628b5..da32c0bf 100644 --- a/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.ql +++ b/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.ql @@ -22,7 +22,8 @@ import cpp import drivers.libraries.Irql -import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.DataFlow2 /** * A function that has at least one parameter annotated with "\_IRQL\_restores\_". @@ -70,7 +71,11 @@ class IrqlFlowConfiguration extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { exists(FunctionCall fc, FundamentalIrqlRestoreFunction firf | fc.getTarget() = firf and - sink.asExpr() = fc.getArgument(firf.getIrqlIndex()) + ( + sink.asExpr() = fc.getArgument(firf.getIrqlIndex()) + or + sink.asExpr() = fc.getArgument(firf.getIrqlIndex()).getAChild*() + ) ) } } diff --git a/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.sarif b/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.sarif index 2009fa39..782cdfe8 100644 --- a/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.sarif +++ b/src/drivers/general/queries/IrqlNotUsed/IrqlNotUsed.sarif @@ -6,7 +6,23 @@ "driver" : { "name" : "CodeQL", "organization" : "GitHub", - "semanticVersion" : "2.11.5", + "semanticVersion" : "2.14.4", + "notifications" : [ { + "id" : "cpp/baseline/expected-extracted-files", + "name" : "cpp/baseline/expected-extracted-files", + "shortDescription" : { + "text" : "Expected extracted files" + }, + "fullDescription" : { + "text" : "Files appearing in the source archive that are expected to be extracted." + }, + "defaultConfiguration" : { + "enabled" : true + }, + "properties" : { + "tags" : [ "expected-extracted-files", "telemetry" ] + } + } ], "rules" : [ { "id" : "cpp/drivers/irql-not-used", "name" : "cpp/drivers/irql-not-used", @@ -42,7 +58,7 @@ }, "extensions" : [ { "name" : "microsoft/windows-drivers", - "semanticVersion" : "0.1.0+933e876f096a70922173e4d5ad604d99d4481af4", + "semanticVersion" : "0.2.0+079028b57055ccd2fea3bae5a9ecc283d9ee56bb", "locations" : [ { "uri" : "file:///C:/codeql-home/Windows-Driver-Developer-Supplemental-Tools/src/", "description" : { @@ -54,28 +70,99 @@ "text" : "The QL pack definition file." } } ] + } ] + }, + "invocations" : [ { + "toolExecutionNotifications" : [ { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/driver_snippet.c", + "uriBaseId" : "%SRCROOT%", + "index" : 0 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } }, { - "name" : "legacy-upgrades", - "semanticVersion" : "0.0.0", "locations" : [ { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/", - "description" : { - "text" : "The QL pack root directory." + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } } - }, { - "uri" : "file:///C:/codeql-home/codeql/legacy-upgrades/qlpack.yml", - "description" : { - "text" : "The QL pack definition file." + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" } - } ] - } ] - }, + } + }, { + "locations" : [ { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } + } + } ], + "message" : { + "text" : "" + }, + "level" : "none", + "descriptor" : { + "id" : "cpp/baseline/expected-extracted-files", + "index" : 0 + }, + "properties" : { + "formattedMessage" : { + "text" : "" + } + } + } ], + "executionSuccessful" : true + } ], "artifacts" : [ { "location" : { "uri" : "driver/driver_snippet.c", "uriBaseId" : "%SRCROOT%", "index" : 0 } + }, { + "location" : { + "uri" : "driver/fail_driver1.c", + "uriBaseId" : "%SRCROOT%", + "index" : 1 + } + }, { + "location" : { + "uri" : "driver/fail_driver1.h", + "uriBaseId" : "%SRCROOT%", + "index" : 2 + } } ], "results" : [ { "ruleId" : "cpp/drivers/irql-not-used", @@ -123,52 +210,6 @@ "text" : "inIrql" } } ] - }, { - "ruleId" : "cpp/drivers/irql-not-used", - "ruleIndex" : 0, - "rule" : { - "id" : "cpp/drivers/irql-not-used", - "index" : 0 - }, - "message" : { - "text" : "This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL." - }, - "locations" : [ { - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 43, - "startColumn" : 6, - "endColumn" : 23 - } - } - } ], - "partialFingerprints" : { - "primaryLocationLineHash" : "41c0a3dc1c9cab79:1", - "primaryLocationStartColumnFingerprint" : "5" - }, - "relatedLocations" : [ { - "id" : 1, - "physicalLocation" : { - "artifactLocation" : { - "uri" : "driver/driver_snippet.c", - "uriBaseId" : "%SRCROOT%", - "index" : 0 - }, - "region" : { - "startLine" : 43, - "startColumn" : 50, - "endColumn" : 56 - } - }, - "message" : { - "text" : "myLock" - } - } ] } ], "columnKind" : "utf16CodeUnits", "properties" : { diff --git a/src/drivers/test/diff/IrqlNotUsed.sarif b/src/drivers/test/diff/IrqlNotUsed.sarif index 6b40083a..dea8275e 100644 --- a/src/drivers/test/diff/IrqlNotUsed.sarif +++ b/src/drivers/test/diff/IrqlNotUsed.sarif @@ -1,7 +1,7 @@ { "all": { "+": 0, - "-": 2 + "-": 0 }, "error": { "+": 0, @@ -10,19 +10,8 @@ }, "warning": { "+": 0, - "-": 2, - "codes": [ - [ - "cpp/drivers/irql-not-used This function has annotated the parameter [inIrql](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", - 1, - 0 - ], - [ - "cpp/drivers/irql-not-used This function has annotated the parameter [myLock](1) with \"_IRQL_restores_\" but does not use it to restore the IRQL.", - 1, - 0 - ] - ] + "-": 0, + "codes": [] }, "note": { "+": 0, From 47edb0e76712e65e33604f1abc68a9c450152189 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Wed, 25 Oct 2023 18:39:35 -0700 Subject: [PATCH 54/54] Update ported_driver_ca_checks.qls --- src/suites/ported_driver_ca_checks.qls | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/suites/ported_driver_ca_checks.qls b/src/suites/ported_driver_ca_checks.qls index c4a43c99..1a9058b4 100644 --- a/src/suites/ported_driver_ca_checks.qls +++ b/src/suites/ported_driver_ca_checks.qls @@ -15,6 +15,8 @@ - drivers/kmdf/queries/StrSafe/StrSafe.ql - drivers/general/queries/experimental/IrqlTooHigh/IrqlTooHigh.ql - drivers/general/queries/experimental/IrqlTooLow/IrqlTooLow.ql + - drivers/general/queries/experimental/IrqlSetTooHigh/IrqlSetTooHigh.ql + - drivers/general/queries/experimental/IrqlSetTooLow/IrqlSetTooLow.ql - drivers/wdm/queries/ExaminedValue/ExaminedValue.ql - drivers/wdm/queries/IllegalFieldAccess/IllegalFieldAccess.ql - drivers/wdm/queries/IllegalFieldAccess2/IllegalFieldAccess2.ql