Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CPP: Add query for CVE-2022-37454: Integer addition may overflow inside if statement #12036

Merged
merged 15 commits into from Jun 5, 2023
Merged

Conversation

nmouha
Copy link
Contributor

@nmouha nmouha commented Jan 30, 2023

The query detects "if (a+b>c) a=c-b", which is incorrect if a+b overflows. This code should be replaced by "if (a>c-b) a=c-b", which avoids the overflow and is much easier to understand. (It becomes much clearer that it implements "a = min(a,c-b)".)

This pattern is the root cause of CVE-2022-37454, a buffer overflow vulnerability in the "official" SHA-3 implementation that has been fixed in the latest versions of some large projects (including PHP and Python). More info: https://mouha.be/sha-3-buffer-overflow/

@MathiasVP
Copy link
Contributor

Hi @nmouha!

Thanks for your contribution. Since this PR is part of a bounty process the Security Lab team will do an initial review the query, and once they're happy with the intention of the query and its results the CodeQL C/C++ team will review the query.

@JarLob
Copy link
Contributor

JarLob commented Feb 17, 2023

Hi @nmouha, your query is looking for integer overflow, but there are no constraints that a, b and c are actually integers. One of the false positives patterns I have noticed is that it flags int comparison with double, however in this case it is implicitly converted to double.

@nmouha
Copy link
Contributor Author

nmouha commented Feb 19, 2023

Thank you @JarLob for your feedback! Sorry to overlook this obvious false positive.

I've updated the query to make sure that it involves an integral type, and I've also incorporated all previous feedback of @rdmarsh2 in #codeql-writing.

If there are further improvements to consider, I'd be happy to follow up!

@JarLob
Copy link
Contributor

JarLob commented Feb 21, 2023

The latest query still flags double and int comparison, which is IMHO wrong as int is implicitly converted to double.
Also the query started flagging expressions like if (a + b > c) return; producing much more results. My concern is that it may overlap with already existing integer overflows queries. I liked it more when it was finding exactly the if (a>c-b) a=c-b pattern.

@nmouha
Copy link
Contributor Author

nmouha commented Feb 21, 2023

Thanks again @JarLob! I just updated the query to address your feedback.

The previous query detected if (a+b>d) a = d-b; where a and b are int and d is double. I'm assuming this is what you meant by int and double comparison. The addition overflow happens before the conversion to double, so there may be a bug if the intention was if (a>d-b) a = d-b;. Still, maybe it's better to ensure that we're not dealing with any floating point variables at all, so I updated the query.

The controlflow.Guards query found matches in six instead of two lines related to the CVE-2022-37454 patch (GHSA-6w4m-2xhg-2658). So it was my intention to also match if (a+b>c) return; if the code later uses c-b, because it's maybe part of a similar pattern (but with early function returns to avoid nested if-functions). However, if it leads to more false positives, it's better not consider this. So I reverted to the earlier query.

Regarding potential overlap with other queries, the previous query had an overlap with SignedOverflowCheck.ql if the code is if (a+b>a) a = a-b;. I've added an extra condition to exclude this case. I'm not aware of potential overlap with other queries.

Looking forward to hear your thoughts!

@JarLob
Copy link
Contributor

JarLob commented Feb 23, 2023

Hi @nmouha!

The previous query detected if (a+b>d) a = d-b; where a and b are int and d is double. I'm assuming this is what you meant by int and double comparison. The addition overflow happens before the conversion to double, so there may be a bug if the intention was if (a>d-b) a = d-b;. Still, maybe it's better to ensure that we're not dealing with any floating point variables at all, so I updated the query.

The second version was detecting int + double > int patterns. I agree that in case of int + int > double the overflow may happen. Feel free to exclude only the first example pattern or leave query in the current state.

The controlflow.Guards query found matches in six instead of two lines related to the CVE-2022-37454 patch (GHSA-6w4m-2xhg-2658). So it was my intention to also match if (a+b>c) return; if the code later uses c-b, because it's maybe part of a similar pattern (but with early function returns to avoid nested if-functions). However, if it leads to more false positives, it's better not consider this. So I reverted to the earlier query.

To give you some insights, the first version of the query returned 129 results when run on a 1000 projects, the v2 - 6315 on the same projects. v3 - 997. Technically any int + int may overflow and it is possible to write a query for this, but that would return a huge number or results. I think the pattern of:

int size;
int capacity;
int newElements;

if (size + newElements > capacity)
    newElements = capacity - size;

is good, because its newElements = capacity - size; makes it obvious which argument of the size + newElements equation may need adjustment (or considered untrusted) by programmer.

Regarding potential overlap with other queries, the previous query had an overlap with SignedOverflowCheck.ql if the code is if (a+b>a) a = a-b;. I've added an extra condition to exclude this case. I'm not aware of potential overlap with other queries.

What I meant is that if the query is going to diverge from the a = min(a,c-b) pattern, the overlap with the queries we already have may be too big. However some overlap is ok. Feel free to revert any special conditions to exclude overlapping parts. I can run a scan to compare the number of results again.

Looking forward to hear your thoughts!

I think you have enough information in the query to show how the code should be rewritten? I think that would be valuable. Many developers may not understand immediately what is wrong with the code. If that is too complicated, I think at least a message like "if (a+b>c) a=c-b" was detected where "a + b" may potentially overflow/wraparound. The code can be rewritten to "if (a>c-b) a=c-b" which avoids the overflow can be displayed.

@nmouha
Copy link
Contributor Author

nmouha commented Feb 23, 2023

Thanks again @JarLob! I really appreciate that you're guiding me through this.

I've updated the query and I'm including test cases below.

If I misunderstood something or if certain patterns should be added/removed, just let me know and I'll adjust the query!

void test(int a, int b, int c, int x, int y, double d, unsigned short a1, unsigned short b1, unsigned short c1) {
  // match all below
  if (a+b>c) a = c-b;
  if (a+b>c) { a = c-b; }
  if (b+a>c) a = c-b;
  if (b+a>c) { a = c-b; }
  if (c>a+b) a = c-b;
  if (c>a+b) { a = c-b; }
  if (c>b+a) a = c-b;
  if (c>b+a) { a = c-b; }
  
  if (a+b>=c) a = c-b;
  if (a+b>=c) { a = c-b; }
  if (b+a>=c) a = c-b;
  if (b+a>=c) { a = c-b; }
  if (c>=a+b) a = c-b;
  if (c>=a+b) { a = c-b; }
  if (c>=b+a) a = c-b;
  if (c>=b+a) { a = c-b; }

  if (a+b<c) a = c-b;
  if (a+b<c) { a = c-b; }
  if (b+a<c) a = c-b;
  if (b+a<c) { a = c-b; }
  if (c<a+b) a = c-b;
  if (c<a+b) { a = c-b; }
  if (c<b+a) a = c-b;
  if (c<b+a) { a = c-b; }
  
  if (a+b<=c) a = c-b;
  if (a+b<=c) { a = c-b; }
  if (b+a<=c) a = c-b;
  if (b+a<=c) { a = c-b; }
  if (c<=a+b) a = c-b;
  if (c<=a+b) { a = c-b; }
  if (c<=b+a) a = c-b;
  if (c<=b+a) { a = c-b; }

  // allow overlap with SignedOverflowCheck.ql
  if (a+b>a) a = a-b;
  
  // allow int + int > double
  if (a+b>d) a = d-b;
  
  // avoid these false positives
  if (a+(-x)>c) a = c-(-y);
  if (a+b>c) { b++; a = c-b; }
  if (a+d>c) a = c-d;
  if (a1+b1>c1) a1 = c1-b1;
}

@JarLob
Copy link
Contributor

JarLob commented Mar 8, 2023

Hi @nmouha, sorry for the delay.

The query looks good. However to clarify, what I suggested is not modifying the description of the query (it is not visible in alerts), but the select ifstmt, "Integer addition may overflow inside if statement." part of the query. The text doesn't have to be static and may contain dynamic parts. Take a look for example at

select sink, source, sink,
"Potentially overflowing value from $@ is used in the size of this allocation.", source,
"multiplication"
By using dynamic parameters you can format the query "if (a+b>c) a=c-b" was detected where "a + b" may potentially overflow/wraparound. The code can be rewritten to "if (a>c-b) a=c-b" which avoids the overflow for each alert with actual a, b and c.

We definitely would like you to put the test from your comment into a test like in https://github.com/github/codeql/tree/main/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-190/AllocMultiplicationOverflow, but this is what I think @MathiasVP will comment on.

One comment I have on the test though is these lines:

  // allow overlap with SignedOverflowCheck.ql
  if (a+b>a) a = a-b;

Wouldn't an attempt to detect overflow look like if (a+b<a) { /* panic */ }?
The if (a+b>a) a = a-b; doesn't make sense to me as a + b assuming b is positive, will be always greater than a (if no overflow). Do I miss anything?

@nmouha
Copy link
Contributor Author

nmouha commented Mar 12, 2023

Thank you @JarLob!

I've reverted the description and I've updated the alert to look more similar to AllocMultiplicationOverflow.ql (but with "addition" instead of "multiplication").

If we want the variable names corresponding to a, b, and c, then maybe the text becomes more difficult to read, and it may also be less clear that only the addition needs to be replaced:

"if (partialBlock+byteIOIndex>rateInBytes) partialBlock=rateInBytes-byteIOIndex" was detected where "partialBlock + byteIOIndex" may potentially overflow/wraparound. The code can be rewritten as "if (partialBlock>rateInBytes-byteIOIndex) partialBlock=rateInBytes-byteIOIndex" which avoids the overflow.

However, if you want, I can make this change with a select statement along these lines:

select ifstmt, "\"if ($@+$@>$@) $@=$@-$@\" was detected where \"$@ + $@\" may potentially overflow/wraparound. The code can be rewritten to \"if ($@>$@-$@) $@=$@-$@\" which avoids the overflow.",
addexpr.getLeftOperand(),  addexpr.getLeftOperand().toString(),
addexpr.getRightOperand(), addexpr.getRightOperand().toString(),
subexpr.getLeftOperand(),  subexpr.getLeftOperand().toString(),
addexpr.getLeftOperand(),  addexpr.getLeftOperand().toString(),
subexpr.getLeftOperand(),  subexpr.getLeftOperand().toString(),
addexpr.getRightOperand(), addexpr.getRightOperand().toString(),
addexpr.getLeftOperand(),  addexpr.getLeftOperand().toString(),
addexpr.getRightOperand(), addexpr.getRightOperand().toString(),
addexpr.getLeftOperand(),  addexpr.getLeftOperand().toString(),
subexpr.getLeftOperand(),  subexpr.getLeftOperand().toString(),
addexpr.getRightOperand(), addexpr.getRightOperand().toString(),
addexpr.getLeftOperand(),  addexpr.getLeftOperand().toString(),
subexpr.getLeftOperand(),  subexpr.getLeftOperand().toString(),
addexpr.getRightOperand(), addexpr.getRightOperand().toString()

I've also added a test.cpp file. I agree that the last tests are artificial and unlikely to occur in practice. They are just to help understand the impact of improvements to the query (e.g., toString -> hashCons -> globalValueNumber) and potential overlap with existing queries (e.g., SignedOverflowCheck.ql), there is no relation to code used in practice. (I agree that if (a+b>a) a = a-b; makes no sense.)

It would be helpful to extend the tests with some false positives that occur in practice, and maybe even improve the query to avoid them. I'm not sure how to approach this; as you mentioned the query returns results for some existing projects, but I don't which of those results are potential false positives that can be added to the tests.

@JarLob
Copy link
Contributor

JarLob commented Mar 13, 2023

"if (partialBlock+byteIOIndex>rateInBytes) partialBlock=rateInBytes-byteIOIndex" was detected where "partialBlock + byteIOIndex" may potentially overflow/wraparound. The code can be rewritten as "if (partialBlock>rateInBytes-byteIOIndex) partialBlock=rateInBytes-byteIOIndex" which avoids the overflow.

I see your point. I defer this to the CodeQL team to decide which is the best way to report.

It would be helpful to extend the tests with some false positives that occur in practice, and maybe even improve the query to avoid them. I'm not sure how to approach this; as you mentioned the query returns results for some existing projects, but I don't which of those results are potential false positives that can be added to the tests.

I mentioned false positives because of floating point types, but I think they are gone now. There could be an additional test: if (a+(double)b>c) a = c-b; // GOOD

Here is an example of current FP because n cannot be bigger than 255, but I don't think it is easy to prevent or the query would become overcomplex.

The submission is now in CodeQL review stage, they may have comments.

@nmouha
Copy link
Contributor Author

nmouha commented Mar 16, 2023

That's exactly the type of false positive example that I was looking for. Thank you @JarLob!

It seems that the false positive is due to an inherent limitation of exprMightOverflowPositively of SimpleRangeAnalysis.qll:

predicate exprMightOverflowPositively(Expr expr) {
getUpperBoundsImpl(expr) > exprMaxVal(expr)

which returns true after a few iterations due to getUpperBoundsImpl(expr) > exprMaxVal(expr).

A more precise analysis (e.g., using a symbolic execution tool) shows that addition here can never overflow. But such tools have a risk of path explosion, which CodeQL wants to avoid.

So rather than looking for any a+b and calculate whether the addition can overflow, the approach of CodeQL seems to be to look for a+b that might overflow in an code pattern that is likely incorrect.

OpenSSL has the same code pattern but with a ternary conditional operator instead. (I can write the query to include this result, however I confirmed that it is also a false positive.)

I personally think the following code is a much more readable way to ensure that todo is at most out_len - done:

if (todo > out_len - done) {
  todo = out_len - done;
}

But if (done + todo > out_len) is of course also correct (because it can be confirmed that this addition cannot overflow). It will be interesting to see what the BoringSSL and OpenSSL teams think of this.

PS: I added the additional test case if (a+(double)b>c) a = c-b; // GOOD, as you suggested.

Copy link
Contributor

@MathiasVP MathiasVP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @nmouha,

Thanks for your query. This looks great! I have a couple of comments and suggestions. Let me know if something isn't clear in my explanations, and I'll do my best to expand on it. Also, it looks like your code isn't formatted according to our contribution guidelines (see Section 3 of https://github.com/github/codeql/blob/main/CONTRIBUTING.md#submitting-a-new-experimental-query)

Comment on lines 3 to 10
* @description Detects "if (a+b>c) a=c-b", which incorrectly implements
* a = min(a,c-b) if a+b overflows. Should be replaced by
* "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b"
* (swapped terms in addition), if (a+b>c) { a=c-b }"
* (assignment inside block), "c<a+b" (swapped operands) and
* ">=", "<", "<=" instead of ">" (all operators). This
* integer overflow is the root cause of the buffer overflow
* in the SHA-3 reference implementation (CVE-2022-37454).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep the description short, and just off-load some of these other patterns to the qhelp file. How about this suggestion instead?

Suggested change
* @description Detects "if (a+b>c) a=c-b", which incorrectly implements
* a = min(a,c-b) if a+b overflows. Should be replaced by
* "if (a>c-b) a=c-b". Also detects "if (b+a>c) a=c-b"
* (swapped terms in addition), if (a+b>c) { a=c-b }"
* (assignment inside block), "c<a+b" (swapped operands) and
* ">=", "<", "<=" instead of ">" (all operators). This
* integer overflow is the root cause of the buffer overflow
* in the SHA-3 reference implementation (CVE-2022-37454).
* @description Writing 'if (a+b>c) a=c-b' incorrectly implements
* 'a = min(a,c-b)' if 'a+b' overflows. This integer
* overflow is the root cause of the buffer overflow
* in the SHA-3 reference implementation (CVE-2022-37454).

blockstmt.getAStmt() = exprstmt)) and
exprstmt.getExpr() = assignexpr and
assignexpr.getRValue() = subexpr and
((hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I see why you need hashCons here: Does addexpr.getLeftOperand() not have the same value number as assignexpr.getLValue()? So you're forced to use hashCons instead?

Comment on lines 33 to 34
(ifstmt.getThen() = blockstmt and
blockstmt.getAStmt() = exprstmt)) and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a subtle issue here that the missing auto-formatting is hiding really well 😅. You're only providing a value for blockstmt in the ifstmt.getThen() = blockstmt and blockstmt.getAStmt() = exprstmt case, but not in the ifstmt.getThen() = exprstmt case. If we're not rescued by the CodeQL optimizer this will generate a cartesian product between all the IfStmt ifstmt, RelationalOperation relop, ExprStmt exprstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr values considered by the query, and all BlockStmts in the program. To avoid this, you can wrap the ifstmt.getThen() = blockstmt and blockstmt.getAStmt() = exprstmt case in an exists like this.

Suggested change
(ifstmt.getThen() = blockstmt and
blockstmt.getAStmt() = exprstmt)) and
exists(BlockStmt blockstmt | ifstmt.getThen() = blockstmt and blockstmt.getAStmt() = exprstmt) and

This limits the scope of the blockstmt and avoids the possibility of a cartesian product (which will hurt performance a lot on large databases).

import semmle.code.cpp.commons.Exclusions

from IfStmt ifstmt, RelationalOperation relop, ExprStmt exprstmt, BlockStmt blockstmt, AssignExpr assignexpr, AddExpr addexpr, SubExpr subexpr
where ifstmt.getCondition() = relop and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could increase the true-positive rate of this query a lot if you used our semmle.code.cpp.controlflow.Guards library. This would allow you to detect more patterns such as this one completely automagically:

if (a+b <= c) {
  /* ... */
} else { a=c-b; }

To use semmle.code.cpp.controlflow.Guards, the only changes I think you need to make is:

  • Import semmle.code.cpp.controlflow.Guards
  • Replace from IfStmt ifstmt with from GuardCondition guard
  • Replace ifstmt.getCondition() = relop with (guard.ensuresLt(_, addexpr, _, block, true) or guard.ensuresLt(addexpr, _, _, block, true)). This says that addexpr must be an operand that is on either side of a comparison. Now admittedly, this isn't as pretty as before. But you can factor this out into a predicate to make it look like the code you had before 🙂.

This would also allow you to get rid of the blockstmt variable, and get rid of the two explicit cases for:

(ifstmt.getThen() = exprstmt or(ifstmt.getThen() = blockstmt and blockstmt.getAStmt() = exprstmt))

and instead replace them with a single condition: block.getANode() = exprstmt.

@nmouha
Copy link
Contributor Author

nmouha commented May 17, 2023

Hi @MathiasVP,

Thank you very much for the detailed explanations!

I was wondering why so many queries are written using exists()... Thanks for taking the time to explain this problem with the old query, rather than just skipping over this to suggest semmle.code.cpp.controlflow.Guards (which makes the exists() unnecessary). And sorry for the delay and for not following the formatting guidelines!

I've updated the pull request according to your suggestions. Below are some explanations:

Indeed, addexpr.getLeftOperand() does not have the same value number as assignexpr.getLValue(). The reason is that the assignment operator = changes the value number of the lvalue of the assignment. I found the CodeQL documentation to be very helpful here, as it has a very similar example of an expression with different value numbers but the same hash cons: https://codeql.github.com/docs/codeql-language-guides/hash-consing-and-value-numbering/

I'm suggesting to change (guard.ensuresLt(_, addexpr, _, block, true) or guard.ensuresLt(addexpr, _, _, block, true)) to (guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) for the following reasons:

  • In a+b>c, I want to make sure that the same c is reused in a=c-b, so I've added expr to fix the other side of the inequality.
  • In ensuresLt(), the third argument is the k in the guard condition left < right + k. It wasn't immediately obvious to me that not binding k is a way to consider both < and <=. It seems more straightforward to me to bind k to zero, but to allow the fifth argument (boolean isLessThan) to be both true and false. If this makes it more obvious that all cases are considered, then factoring this out into a predicate is maybe not needed.

Thanks again and don't hesitate to let me know if you have additional feedback!

Copy link
Contributor

@MathiasVP MathiasVP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with the exception of one small question.

GuardCondition guard, Expr expr, ExprStmt exprstmt, BasicBlock block, AssignExpr assignexpr,
AddExpr addexpr, SubExpr subexpr
where
(guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you lost your not isFromMacroDefinition(relop) and condition in 5c6fc2f. Was that intentional?

openssl-machine pushed a commit to openssl/openssl that referenced this pull request May 19, 2023
The expression "if (a+b>c) a=c-b" is incorrect if "a+b" overflows.
It should be replaced by "if (a>c-b) a=c-b", which avoids the
potential overflow and is much easier to understand.

This pattern is the root cause of CVE-2022-37454, a buffer overflow
vulnerability in the "official" SHA-3 implementation.

It has been confirmed that the addition in
https://github.com/openssl/openssl/blob/master/providers/implementations/kdfs/hkdf.c#L534
cannot overflow. So this is only a minor change proposal to avoid
a potentially vulnerable code pattern and to improve readability.
More information: github/codeql#12036 (comment)

CLA: trivial

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #20990)

(cherry picked from commit 56a51b5)
openssl-machine pushed a commit to openssl/openssl that referenced this pull request May 19, 2023
The expression "if (a+b>c) a=c-b" is incorrect if "a+b" overflows.
It should be replaced by "if (a>c-b) a=c-b", which avoids the
potential overflow and is much easier to understand.

This pattern is the root cause of CVE-2022-37454, a buffer overflow
vulnerability in the "official" SHA-3 implementation.

It has been confirmed that the addition in
https://github.com/openssl/openssl/blob/master/providers/implementations/kdfs/hkdf.c#L534
cannot overflow. So this is only a minor change proposal to avoid
a potentially vulnerable code pattern and to improve readability.
More information: github/codeql#12036 (comment)

CLA: trivial

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #20990)

(cherry picked from commit 56a51b5)
openssl-machine pushed a commit to openssl/openssl that referenced this pull request May 19, 2023
The expression "if (a+b>c) a=c-b" is incorrect if "a+b" overflows.
It should be replaced by "if (a>c-b) a=c-b", which avoids the
potential overflow and is much easier to understand.

This pattern is the root cause of CVE-2022-37454, a buffer overflow
vulnerability in the "official" SHA-3 implementation.

It has been confirmed that the addition in
https://github.com/openssl/openssl/blob/master/providers/implementations/kdfs/hkdf.c#L534
cannot overflow. So this is only a minor change proposal to avoid
a potentially vulnerable code pattern and to improve readability.
More information: github/codeql#12036 (comment)

CLA: trivial

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #20990)
@nmouha
Copy link
Contributor Author

nmouha commented May 19, 2023

Hi @MathiasVP,

The not isFromMacroDefinition(relop) was copied over from SignedOverflowCheck.ql. Perhaps it was necessary there to avoid some false positives. I left it out as it may make sense to detect if (a+b>c) a=c-b in code from macro definitions as well.

Just FYI: the false positive found by @JarLob resulted in changes to both OpenSSL and
BoringSSL.

@github-actions
Copy link
Contributor

github-actions bot commented Jun 5, 2023

QHelp previews:

cpp/ql/src/experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.qhelp

Integer addition may overflow inside if statement

Detects if (a+b>c) a=c-b, which incorrectly implements a = min(a,c-b) if a+b overflows.

Also detects variants such as if (b+a>c) a=c-b (swapped terms in addition), if (a+b>c) { a=c-b } (assignment inside block), c<a+b (swapped operands), and >=, <, <= instead of > (all operators).

This integer overflow is the root cause of the buffer overflow in the SHA-3 reference implementation (CVE-2022-37454).

Recommendation

Replace by if (a>c-b) a=c-b. This avoids the overflow and makes it easy to see that a = min(a,c-b).

References

Copy link
Contributor

@MathiasVP MathiasVP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. This LGTM now!

@MathiasVP MathiasVP merged commit 52fb00c into github:main Jun 5, 2023
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants