C++: Prototype SSL result conflation query.

This commit is contained in:
Geoffrey White
2021-11-19 11:08:57 +00:00
parent 1f3f7e9ccc
commit 6afcbce421
4 changed files with 209 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
/**
* @name TODO
* @description TODO
* @kind problem
* @problem.severity TODO
* @security-severity TODO
* @precision TODO
* @id TODO
* @tags TODO
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.dataflow.DataFlow
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() {
getTarget().getName() = "SSL_get_verify_result"
}
}
class VerifyResultConfig extends DataFlow::Configuration {
VerifyResultConfig() { this = "VerifyResultConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SSLGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard |
guard.getAChild*() = sink.asExpr()
)
}
}
// TODO: use GVN on *both* sinks to get more results!?
from
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
where
config.hasFlow(source, sink1) and
globalValueNumber(sink1.asExpr()) = globalValueNumber(sink2.asExpr()) and
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
c1.getValue().toInt() = 0 and
c2.getValue().toInt() != 0
select
guard, "This expression conflates OK and non-OK results from $@.", source, source.toString()

View File

@@ -0,0 +1,8 @@
| test.cpp:18:9:18:38 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:100:18:100:38 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:38:7:38:36 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:36:16:36:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:54:7:54:47 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:52:16:52:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:62:7:62:36 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:60:16:60:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:70:7:70:36 | ... && ... | This expression conflates OK and non-OK results from $@. | test.cpp:68:16:68:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:83:7:83:40 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:78:16:78:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:87:7:87:38 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:7:57:7:77 | call to SSL_get_verify_result | call to SSL_get_verify_result |
| test.cpp:107:13:107:42 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:105:16:105:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-295/SSLResultConflation.ql

View File

@@ -0,0 +1,149 @@
struct SSL {
// ...
};
int SSL_get_verify_result(const SSL *ssl);
int get_verify_result_indirect(const SSL *ssl) { return SSL_get_verify_result(ssl); }
int something_else(const SSL *ssl);
bool is_ok(int result)
{
return (result == 0); // GOOD
}
bool is_maybe_ok(int result)
{
return (result == 0) || (result == 1); // BAD (conflates OK and a non-OK codes)
}
void test1_1(SSL *ssl)
{
{
int result = SSL_get_verify_result(ssl);
if (result == 0) // GOOD
{
}
if (result == 1) // GOOD
{
}
}
{
int result = SSL_get_verify_result(ssl);
if ((result == 0) || (result == 1)) // BAD (conflates OK and a non-OK codes)
{
}
}
{
int result = SSL_get_verify_result(ssl);
if ((result == 1) || (result == 2)) // GOOD (both results are non-OK)
{
}
}
{
int result = SSL_get_verify_result(ssl);
if ((result == 0) || (false) || (result == 2)) // BAD (conflates OK and a non-OK codes)
{
}
}
{
int result = SSL_get_verify_result(ssl);
if ((0 == result) || (1 == result)) // BAD (conflates OK and a non-OK codes)
{
}
}
{
int result = SSL_get_verify_result(ssl);
if ((result != 0) && (result != 1)) // BAD (conflates OK and a non-OK codes)
{
} else {
// conflation occurs here
}
}
{
int result = SSL_get_verify_result(ssl);
int result_cpy = result;
int result2 = get_verify_result_indirect(ssl);
int result3 = something_else(ssl);
if ((result == 0) || (result_cpy == 1)) // BAD (conflates OK and a non-OK codes)
{
}
if ((result2 == 0) || (result2 == 1)) // BAD (conflates OK and a non-OK codes)
{
}
if ((result3 == 0) || (result3 == 1)) // GOOD (not an SSL result)
{
}
}
if (is_ok(SSL_get_verify_result(ssl)))
{
}
if (is_maybe_ok(SSL_get_verify_result(ssl)))
{
}
{
int result = SSL_get_verify_result(ssl);
bool ok = (result == 0) || (result == 1); // BAD (conflates OK and a non-OK codes)
if (ok) {
}
}
{
int result = SSL_get_verify_result(ssl);
if (result == 1) // BAD (conflates OK and a non-OK codes in `else`) [NOT DETECTED]
{
} else {
}
}
}
void do_good();
void test1_2(SSL *ssl)
{
int result = SSL_get_verify_result(ssl);
if (result == 0) { // GOOD
do_good();
} else if (result == 1) {
throw 1;
} else {
throw 1;
}
}
void test1_3(SSL *ssl)
{
int result = SSL_get_verify_result(ssl);
if (result == 0) { // BAD (error code 1 is treated as OK, not as non-OK) [NOT DETECTED]
do_good();
} else if (result == 1) {
do_good();
} else {
throw 1;
}
}