codeql icon indicating copy to clipboard operation
codeql copied to clipboard

To get the expression from SwitchCase

Open KeuntaeShin opened this issue 2 years ago • 9 comments


#define ABC XVY(1)

{
    int cmd = 1;
    int ABC=1;

    switch(cmd) {
        case ABC:
            printf("hello!\n);
    }
}

How to get a "ABC" from a SwitchCase class? (Not a value using (SwitchCase).getExpr().getFullyConverted().getValue() )

Thanks in advance,

KeuntaeShin avatar Jul 18 '22 02:07 KeuntaeShin

Hello! Thanks for reaching out with this question. Would something like this get what you're after?

from SwitchCase s, MacroInvocation m
where exists(Expr e | e = s.getExpr() and e = m.getExpr())
select s, m

edoardopirovano avatar Jul 18 '22 09:07 edoardopirovano

@edoardopirovano , I'm using a control flow node:

result = cfn.(SwitchCase).getExpr()

cfn -> "case ...:". cfn.(SwitchCase).getExpr() -> unsigned int

Can i get the "ABC" based on the control flow node?

cfn.(SwitchCase).????? -> "ABC"

Thanks,

KeuntaeShin avatar Jul 18 '22 09:07 KeuntaeShin

I see. Would something like this do what you need:

exists(Expr e | e = cfn.(SwitchCase).getExpr() and e = result.getExpr())

The result will now be of type MacroInvocation rather than Expr, so other parts of your code may need changing. If you can share more of your code, I'd be happy to help out with that.

edoardopirovano avatar Jul 18 '22 10:07 edoardopirovano

@edoardopirovano,

Even though i can get the value of case via:

cfn.(SwitchCase).getExpr().getFullyConverted().getValue()

If i can replace "Here i'd like to ..." with "cfn.???" (which returns "ABC") , it's the best. The query i'm using:

string getCase(ControlFlowNode cfn) { 
    cfn.getAQlClass().toString().matches("SwitchCase")  and result = cfn.toString() +"Here i'd like to be the ABC"  + "_" + cfn.getAQlClass() 
    or
    result = getCase(cfn.getAPredecessor())
}

from FunctionCall fc, string where_case
where
  where_case = getCase(fc.getAPredecessor())
select fc.getLocation(), fc, where_case as THE_CASE, fc.getControlFlowScope()

KeuntaeShin avatar Jul 18 '22 10:07 KeuntaeShin

I see. I think fitting in the above snippet into your code gives:

string getCase(ControlFlowNode cfn) { 
    cfn.getAQlClass().toString().matches("SwitchCase")  and exists(MacroInvocation m, Expr e | e = cfn.(SwitchCase).getExpr() and e = m.getExpr() and result = m.toString()) 
    or
    result = getCase(cfn.getAPredecessor())
}

from FunctionCall fc, string where_case
where
  where_case = getCase(fc.getAPredecessor())
select fc.getLocation(), fc, where_case as THE_CASE, fc.getControlFlowScope()

Hoping that is what you need?

edoardopirovano avatar Jul 18 '22 10:07 edoardopirovano

@edoardopirovano , The query you shared is working well.

One more question, is there any way to get the "[XXXX]" of "case [XXXX]:" regardless of type?

KeuntaeShin avatar Jul 18 '22 10:07 KeuntaeShin

One more question, is there any way to get the "[XXXX]" of "case [XXXX]:" regardless of type?

Unfortunately, I think the macros do need to be handled separately with a different branch like the one we came up with above. This is because some of the pre-processing has happened already by the time the code is imported into the CodeQL database, so to CodeQL the macros look like they have already been expanded and to restore what the user actually wrote we need a distinct case that does what we did above.

edoardopirovano avatar Jul 18 '22 12:07 edoardopirovano

@edoardopirovano,

Occasionally, the strings of conditions for switch-case provide useful clues for security analysis. It would be useful if the conditions can be obtained. For example:

// case ABCDE:
cfn.(SwitchCase).getConditions().toString()
// ABCDE expected 
// case 1:
cfn.(SwitchCase).getConditions().toString()
// 1 expected 
// case add(a+b):
cfn.(SwitchCase).getConditions().toString()
// add(a+b) expected 

KeuntaeShin avatar Jul 19 '22 01:07 KeuntaeShin

Thanks, we'll certainly consider this, but unfortunately keeping all the raw strings as they appeared in the source code will probably be fairly prohibitive in terms of how much information would have to end up in the CodeQL database. I'll note we also have MacroInvocation.getUnexpandedArgument which could help in your use case.

Out of interest, what are you hoping to achieve that requires the raw strings of the conditions? I would've thought for most analysis, the final expression after macro expansion is what you would want since that is what the compiler actually uses.

edoardopirovano avatar Jul 19 '22 11:07 edoardopirovano