Merge remote-tracking branch 'upstream/master' into mergeback-20181130

This commit is contained in:
Jonas Jensen
2018-11-30 10:13:33 +01:00
233 changed files with 7209 additions and 1359 deletions

View File

@@ -0,0 +1 @@
| test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-022/TaintedPath.ql

View File

@@ -0,0 +1,13 @@
// Semmle test case for rule TaintedPath.ql (User-controlled data in path expression)
// Associated with CWE-022: Improper Limitation of a Pathname to a Restricted Directory. http://cwe.mitre.org/data/definitions/22.html
///// Library routines /////
typedef struct {} FILE;
#define FILENAME_MAX 1000
typedef unsigned long size_t;
FILE *fopen(const char *filename, const char *mode);
int sprintf(char *s, const char *format, ...);
size_t strlen(const char *s);
char *strncat(char *s1, const char *s2, size_t n);

View File

@@ -0,0 +1,30 @@
// Semmle test case for rule TaintedPath.ql (User-controlled data in path expression)
// Associated with CWE-022: Improper Limitation of a Pathname to a Restricted Directory. http://cwe.mitre.org/data/definitions/22.html
#include "stdlib.h"
///// Test code /////
int main(int argc, char** argv) {
char *userAndFile = argv[2];
{
char fileBuffer[FILENAME_MAX] = "/home/";
char *fileName = fileBuffer;
size_t len = strlen(fileName);
strncat(fileName+len, userAndFile, FILENAME_MAX-len-1);
// BAD: a string from the user is used in a filename
fopen(fileName, "wb+");
}
{
char fileBuffer[FILENAME_MAX] = "/home/";
char *fileName = fileBuffer;
size_t len = strlen(fileName);
// GOOD: use a fixed file
char* fixed = "file.txt";
strncat(fileName+len, fixed, FILENAME_MAX-len-1);
fopen(fileName, "wb+");
}
}

View File

@@ -0,0 +1 @@
| test.c:21:12:21:19 | command1 | This argument to an OS command is derived from $@ and then passed to system(string) | test.c:14:20:14:23 | argv | user input (argv) |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-078/ExecTainted.ql

View File

@@ -0,0 +1,33 @@
// Semmle test case for rule ExecTainted.ql (Uncontrolled data used in OS command)
// Associated with CWE-078: OS Command Injection. http://cwe.mitre.org/data/definitions/78.html
///// Library routines /////
int sprintf(char *s, const char *format, ...);
int system(const char *string);
extern void encodeShellString(char *shellStr, int maxChars, const char* cStr);
///// Test code /////
int main(int argc, char** argv) {
char *userName = argv[2];
{
// BAD: a string from the user is injected directly into
// a command.
char command1[1000] = {0};
sprintf(command1, "userinfo -v \"%s\"", userName);
system(command1);
}
{
// GOOD: the user string is encoded by a library routine.
char userNameQuoted[1000] = {0};
encodeShellString(userNameQuoted, 1000, userName);
char command2[1000] = {0};
sprintf(command2, "userinfo -v %s", userNameQuoted);
system(command2);
}
}

View File

@@ -0,0 +1,2 @@
| search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data |
| search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-079/CgiXss.ql

View File

@@ -0,0 +1,50 @@
// Semmle test case for rule CgiXss.ql (CGI script vulnerable to cross-site scripting)
// Associated with CWE-079: Cross-site Scripting. http://cwe.mitre.org/data/definitions/79.html
// Standard library routines
void free(void *ptr);
char *getenv(const char *name);
int printf(const char *format, ...);
int puts(const char *s);
// External routines
char* do_search(char* query);
char* escape_html(char* raw);
void bad_server1(char* query) {
puts("<p>Query results for ");
// BAD: Printing out an HTTP parameter with no escaping
puts(query);
puts("\n<p>\n");
puts(do_search(query));
}
void bad_server2(char* query) {
printf("<p>Query results for %s\n", query);
// BAD: Printing out an HTTP parameter with no escaping
puts("\n<p>");
puts(do_search(query));
}
void good_server(char* query) {
puts("<p>Query results for ");
// GOOD: Escape HTML characters before adding to a page
char* query_escaped = escape_html(query);
puts(query_escaped);
free(query_escaped);
puts("\n<p>\n");
puts(do_search(query));
}
int main(int argc, char** argv) {
char* raw_query = getenv("QUERY_STRING");
if (strcmp("good", argv[0]) == 0) {
good_server(raw_query);
} else if (strcmp("bad1", argv[0]) == 0) {
bad_server1(raw_query);
} else {
bad_server2(raw_query);
}
}

View File

@@ -0,0 +1,2 @@
| test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:42:18:42:23 | call to getenv | call to getenv |
| test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system | test.cpp:43:18:43:23 | call to getenv | call to getenv |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-114/UncontrolledProcessOperation.ql

View File

@@ -0,0 +1,44 @@
// Semmle test cases for CWE-114
int system(const char *string);
char *getenv(const char* name);
// ---
class MyBase
{
public:
virtual void doCommand1(const char *command) = 0;
virtual void doCommand2(const char *command) = 0;
virtual void doCommand3(const char *command) = 0;
};
class MyDerived : public MyBase
{
public:
void doCommand1(const char *command)
{
system(command); // GOOD
}
void doCommand2(const char *command)
{
system(command); // BAD (externally controlled string)
}
void doCommand3(const char *command)
{
system(command); // BAD (externally controlled string)
}
};
void testMyDerived()
{
MyDerived *md1 = new MyDerived;
MyDerived *md2 = new MyDerived;
MyBase *md3 = new MyDerived; // MyBase pointer to a MyDerived
md1->doCommand1("fixed");
md2->doCommand2(getenv("varname"));
md3->doCommand3(getenv("varname"));
}

View File

@@ -0,0 +1,7 @@
| test.c:28:19:28:20 | 41 | Potential buffer-overflow: 'buffer' has size 40 not 41. |
| test.c:29:26:29:27 | 43 | Potential buffer-overflow: 'buffer' has size 40 not 43. |
| test.c:31:26:31:27 | 44 | Potential buffer-overflow: 'buffer' has size 40 not 44. |
| test.c:32:25:32:26 | 45 | Potential buffer-overflow: 'buffer' has size 40 not 45. |
| test.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
| test.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
| test.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |

View File

@@ -0,0 +1 @@
Critical/OverflowStatic.ql

View File

@@ -0,0 +1,50 @@
/* Semmle test case for OverflowStatic.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef struct {} FILE;
typedef unsigned long size_t;
typedef void *va_list;
int sprintf(char *s, const char *format, ...);
int snprintf(char *s, size_t n, const char *format, ...);
char *fgets(char *s, int n, FILE *stream);
char *strncpy(char *s1, const char *s2, size_t n);
char *strncat(char *s1, const char *s2, size_t n);
void *memcpy(void *s1, const void *s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//// Test code /////
void bad0(char *src, FILE *f, va_list ap) {
char buffer[40];
fgets(buffer, 41, f); // BAD: Too many characters read
strncpy(buffer, src, 43); // BAD: Too many characters copied
buffer[0] = 0;
strncat(buffer, src, 44); // BAD: Too many characters copied
memcpy(buffer, src, 45); // BAD: Too many characters copied
memmove(buffer, src, 46); // BAD: Too many characters copied
snprintf(buffer, 47, "%s", src); // BAD: Too many characters copied
vsnprintf(buffer, 48, "%s", ap); // BAD: Too many characters copied
}
void good0(char *src, FILE *f, va_list ap) {
char buffer[60];
fread(buffer, sizeof(char), 51, f); // GOOD
fgets(buffer, 52, f); // GOOD
strncpy(buffer, src, 53); // GOOD
buffer[0] = 0;
strncat(buffer, src, 54); // GOOD
memcpy(buffer, src, 55); // GOOD
memmove(buffer, src, 56); // GOOD
snprintf(buffer, 57, "%s", src); // GOOD
vsnprintf(buffer, 58, "%s", ap); // GOOD
}

View File

@@ -0,0 +1,2 @@
| test.c:22:2:22:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| test.c:33:2:33:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |

View File

@@ -0,0 +1,2 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql

View File

@@ -0,0 +1,35 @@
/* Semmle test case for StrncpyFlippedArgs.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
extern char *strncpy(char *dest, const char *src, unsigned int sz);
extern unsigned int strlen(const char *s);
//// Test code /////
void good0(char *arg) {
char buf[80];
// GOOD: Checks size of destination
strncpy(buf, arg, sizeof(buf));
}
void bad0(char *arg) {
char buf[80];
// BAD: Checks size of source
strncpy(buf, arg, strlen(arg));
}
void good1(const char *buf, char *arg) {
// GOOD: Checks size of destination
strncpy(buf, arg, sizeof(buf));
}
void bad1(const char *buf, char *arg) {
// BAD: Checks size of source
strncpy(buf, arg, strlen(arg));
}

View File

@@ -0,0 +1 @@
| test.c:24:2:24:8 | call to strncat | Potentially unsafe call to strncat. |

View File

@@ -0,0 +1 @@
Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql

View File

@@ -0,0 +1,41 @@
/* Semmle test case for SuspiciousCallToStrncat.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
char *strcpy(char *s1, const char *s2);
char *strncat(char *s1, const char *s2, size_t n);
size_t strlen(const char *s);
//// Test code /////
void good0(char *s) {
char buf[80];
strcpy(buf, "s = ");
strncat(buf, s, sizeof(buf)-5); // GOOD
strncat(buf, ".", 1); // BAD [NOT DETECTED] -- there might not be even 1 character of space
}
void bad0(char *s) {
char buf[80];
strcpy(buf, "s = ");
strncat(buf, s, sizeof(buf)); // BAD -- Forgot to allow for "s = "
strncat(buf, ".", 1); // BAD [NOT DETECTED] -- there might not be even 1 character of space
}
void good1(char *s) {
char buf[80];
strcpy(buf, "s = ");
strncat(buf, s, sizeof(buf)-strlen("s = ")); // GOOD
strncat(buf, ".", sizeof(buf)-strlen("s = ")-strlen(s)); // GOOD
}
void bad1(char *s) {
char buf[80];
strcpy(buf, "s = ");
strncat(buf, s, sizeof(buf)-strlen("s = ")); // GOOD
strncat(buf, ".", 1); // BAD [NOT DETECTED] -- Need to check if any space is left
}

View File

@@ -0,0 +1,2 @@
| var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'call to strncpy' operation is limited to 1025 bytes but the destination is only 1024 bytes. |
| var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'call to strncpy' operation is limited to 129 bytes but the destination is only 128 bytes. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/BadlyBoundedWrite.ql

View File

@@ -0,0 +1 @@
Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql

View File

@@ -0,0 +1,69 @@
| overflowdestination.cpp:46:2:46:7 | call to memcpy | This 'memcpy' operation accesses 128 bytes but the $@ is only 64 bytes. | overflowdestination.cpp:40:7:40:10 | dest | destination buffer |
| tests.cpp:23:2:23:7 | call to memcpy | This 'memcpy' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:19:7:19:17 | smallbuffer | source buffer |
| tests.cpp:25:2:25:7 | call to memcpy | This 'memcpy' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:19:7:19:17 | smallbuffer | destination buffer |
| tests.cpp:172:23:172:31 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:170:17:170:41 | {...} | array |
| tests.cpp:176:23:176:30 | access to array | This array indexing operation accesses byte offset 31 but the $@ is only 24 bytes. | tests.cpp:170:17:170:41 | {...} | array |
| tests.cpp:222:3:222:8 | call to memset | This 'memset' operation accesses 33 bytes but the $@ is only 32 bytes. | tests.cpp:214:8:214:14 | buffer1 | destination buffer |
| tests.cpp:224:3:224:8 | call to memset | This 'memset' operation accesses 33 bytes but the $@ is only 32 bytes. | tests.cpp:215:19:215:30 | new[] | destination buffer |
| tests.cpp:226:3:226:8 | call to memset | This 'memset' operation accesses 33 bytes but the $@ is only 32 bytes. | tests.cpp:218:13:218:18 | call to malloc | destination buffer |
| tests.cpp:228:3:228:8 | call to memset | This 'memset' operation accesses 33 bytes but the $@ is only 32 bytes. | tests.cpp:218:13:218:18 | call to malloc | destination buffer |
| tests.cpp:228:3:228:8 | call to memset | This 'memset' operation accesses 33 bytes but the $@ is only 32 bytes. | tests.cpp:219:13:219:19 | buffer3 | destination buffer |
| tests.cpp:231:3:231:8 | call to memcmp | This 'memcmp' operation may access 33 bytes but the $@ is only 32 bytes. | tests.cpp:214:8:214:14 | buffer1 | first buffer |
| tests.cpp:231:3:231:8 | call to memcmp | This 'memcmp' operation may access 33 bytes but the $@ is only 32 bytes. | tests.cpp:215:19:215:30 | new[] | second buffer |
| tests.cpp:244:2:244:8 | call to memmove | This 'memmove' operation accesses 6 bytes but the $@ is only 5 bytes. | tests.cpp:208:25:208:39 | {...} | source buffer |
| tests.cpp:245:2:245:8 | call to memmove | This 'memmove' operation accesses 6 bytes but the $@ is only 5 bytes. | tests.cpp:208:25:208:39 | {...} | destination buffer |
| tests.cpp:265:2:265:8 | call to wmemset | This 'wmemset' operation accesses 132 bytes but the $@ is only 128 bytes. | tests.cpp:260:10:260:16 | buffer1 | destination buffer |
| tests.cpp:266:2:266:8 | call to wmemset | This 'wmemset' operation accesses 128 bytes but the $@ is only 32 bytes. | tests.cpp:261:7:261:13 | buffer2 | destination buffer |
| tests.cpp:275:3:275:8 | call to memset | This 'memset' operation accesses 15 bytes but the $@ is only 14 bytes. | tests.cpp:272:18:272:32 | Hello, world! | destination buffer |
| tests.cpp:285:3:285:8 | call to memset | This 'memset' operation accesses 128 bytes but the $@ is only 64 bytes. | tests.cpp:283:12:283:23 | new[] | destination buffer |
| tests.cpp:292:3:292:8 | call to memset | This 'memset' operation accesses 11 bytes but the $@ is only 10 bytes. | tests.cpp:289:8:289:12 | array | destination buffer |
| tests.cpp:310:2:310:7 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer |
| tests.cpp:312:2:312:7 | call to memset | This 'memset' operation accesses 17 bytes but the $@ is only 16 bytes. | tests.cpp:298:7:298:12 | buffer | destination buffer |
| tests.cpp:314:2:314:7 | call to memset | This 'memset' operation accesses 8 bytes but the $@ is only 4 bytes. | tests.cpp:299:6:299:10 | field | destination buffer |
| tests.cpp:327:3:327:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer |
| tests.cpp:327:3:327:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:322:22:322:27 | & ... | destination buffer |
| tests.cpp:329:3:329:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer |
| tests.cpp:329:3:329:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:322:22:322:27 | & ... | destination buffer |
| tests.cpp:329:3:329:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:324:12:324:17 | myPtr1 | destination buffer |
| tests.cpp:336:3:336:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:301:10:301:14 | myVar | destination buffer |
| tests.cpp:336:3:336:8 | call to memset | This 'memset' operation accesses 21 bytes but the $@ is only 20 bytes. | tests.cpp:333:27:333:32 | & ... | destination buffer |
| tests.cpp:346:2:346:14 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:342:7:342:15 | charArray | array |
| tests.cpp:349:2:349:14 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array |
| tests.cpp:350:17:350:29 | access to array | This array indexing operation accesses byte offset 10 but the $@ is only 10 bytes. | tests.cpp:342:7:342:15 | charArray | array |
| tests.cpp:352:2:352:13 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:343:6:343:13 | intArray | array |
| tests.cpp:355:2:355:13 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array |
| tests.cpp:356:16:356:27 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array |
| tests.cpp:358:2:358:16 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:344:11:344:21 | structArray | array |
| tests.cpp:361:2:361:16 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array |
| tests.cpp:362:25:362:39 | access to array | This array indexing operation accesses byte offset 219 but the $@ is only 200 bytes. | tests.cpp:344:11:344:21 | structArray | array |
| tests.cpp:365:23:365:34 | access to array | This array indexing operation accesses byte offset 43 but the $@ is only 40 bytes. | tests.cpp:343:6:343:13 | intArray | array |
| tests.cpp:373:3:373:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 100 bytes. | tests.cpp:368:47:368:52 | call to malloc | array |
| tests.cpp:376:3:376:13 | access to array | This array indexing operation accesses byte offset 101 but the $@ is only 101 bytes. | tests.cpp:369:47:369:52 | call to malloc | array |
| tests.cpp:446:3:446:24 | access to array | This array indexing operation accesses a negative index -3 on the $@. | tests.cpp:444:7:444:14 | intArray | array |
| tests.cpp:454:3:454:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:450:7:450:11 | multi | array |
| tests.cpp:456:3:456:11 | access to array | This array indexing operation accesses a negative index -21 on the $@. | tests.cpp:450:7:450:11 | multi | array |
| tests.cpp:459:3:459:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:450:7:450:11 | multi | array |
| tests.cpp:461:3:461:11 | access to array | This array indexing operation accesses byte offset 639 but the $@ is only 400 bytes. | tests.cpp:450:7:450:11 | multi | array |
| tests.cpp:476:2:476:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
| tests.cpp:476:2:476:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:470:13:470:18 | buffer | array |
| tests.cpp:477:2:477:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
| tests.cpp:477:2:477:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:471:13:471:18 | buffer | array |
| tests.cpp:481:2:481:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:469:7:469:12 | buffer | array |
| tests.cpp:481:2:481:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:472:13:472:18 | buffer | array |
| tests.cpp:487:2:487:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:473:21:473:26 | call to malloc | array |
| tests.cpp:491:2:491:7 | access to array | This array indexing operation accesses a negative index -1 on the $@. | tests.cpp:474:21:474:26 | call to malloc | array |
| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:502:15:502:20 | call to malloc | destination buffer |
| tests.cpp:519:3:519:8 | call to memset | This 'memset' operation accesses 20 bytes but the $@ is only 10 bytes. | tests.cpp:510:16:510:21 | call to malloc | destination buffer |
| tests_restrict.c:12:2:12:7 | call to memcpy | This 'memcpy' operation accesses 2 bytes but the $@ is only 1 byte. | tests_restrict.c:7:6:7:13 | smallbuf | source buffer |
| unions.cpp:26:2:26:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:21:10:21:11 | mu | destination buffer |
| unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
| unions.cpp:34:2:34:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:16:7:16:11 | large | destination buffer |
| var_size_struct.cpp:54:5:54:14 | access to array | This array indexing operation accesses byte offset 1 but the $@ is only 1 byte. | var_size_struct.cpp:32:8:32:10 | str | array |
| var_size_struct.cpp:55:5:55:14 | access to array | This array indexing operation accesses byte offset 1 but the $@ is only 1 byte. | var_size_struct.cpp:38:8:38:10 | str | array |
| var_size_struct.cpp:71:3:71:8 | call to memset | This 'memset' operation accesses 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
| var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'strncpy' operation may access 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
| var_size_struct.cpp:87:3:87:19 | access to array | This array indexing operation accesses byte offset 67 but the $@ is only 64 bytes. | var_size_struct.cpp:78:7:78:14 | elements | array |
| var_size_struct.cpp:99:3:99:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
| var_size_struct.cpp:101:3:101:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
| var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'strncpy' operation may access 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
| var_size_struct.cpp:171:3:171:8 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 1 byte. | var_size_struct.cpp:125:17:125:19 | arr | destination buffer |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-119/OverflowBuffer.ql

View File

@@ -0,0 +1,4 @@
| overflowdestination.cpp:30:2:30:8 | call to strncpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |
| overflowdestination.cpp:46:2:46:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |
| overflowdestination.cpp:53:2:53:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |
| overflowdestination.cpp:64:2:64:7 | call to memcpy | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |

View File

@@ -0,0 +1 @@
Critical/OverflowDestination.ql

View File

@@ -0,0 +1,10 @@
| overflowdestination.cpp:46:20:46:30 | sizeof(<expr>) | Potential buffer-overflow: 'dest' has size 64 not 128. |
| tests.cpp:25:33:25:49 | sizeof(<expr>) | Potential buffer-overflow: 'smallbuffer' has size 10 not 20. |
| tests.cpp:163:3:163:11 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. |
| tests.cpp:164:8:164:16 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. |
| tests.cpp:245:42:245:42 | 6 | Potential buffer-overflow: 'global_array_5' has size 5 not 6. |
| tests.cpp:349:2:349:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' is accessed here. |
| tests.cpp:350:17:350:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' is accessed here. |
| var_size_struct.cpp:54:5:54:14 | access to array | Potential buffer-overflow: 'str' has size 1 but 'str[1]' is accessed here. |
| var_size_struct.cpp:55:5:55:14 | access to array | Potential buffer-overflow: 'str' has size 1 but 'str[1]' is accessed here. |
| var_size_struct.cpp:103:39:103:41 | 129 | Potential buffer-overflow: 'str' has size 128 not 129. |

View File

@@ -0,0 +1 @@
Critical/OverflowStatic.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWrite.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWriteFloat.ql

View File

@@ -0,0 +1,3 @@
| overflowdestination.cpp:30:2:30:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| tests.cpp:239:3:239:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
| tests.cpp:240:3:240:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |

View File

@@ -0,0 +1 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/UnboundedWrite.ql

View File

@@ -0,0 +1,104 @@
// Semmle test cases for rule CWE-119.
// --- library types, functions etc ---
typedef unsigned long size_t;
typedef size_t FILE;
void *malloc(size_t size);
char *strncpy(char *s1, const char *s2, size_t n);
size_t strlen(const char *s);
char *fgets(char *s, int n, FILE *stream);
void *memcpy(void *s1, const void *s2, size_t n);
// --- example from the qhelp ---
inline size_t min(size_t a, size_t b) {
if (a < b) {
return a;
} else {
return b;
}
}
int main(int argc, char* argv[]) {
char param[20];
char *arg1;
arg1 = argv[1];
//wrong: only uses the size of the source (argv[1]) when using strncpy
strncpy(param, arg1, strlen(arg1));
//correct: uses the size of the destination array as well
strncpy(param, arg1, min(strlen(arg1), sizeof(param) -1));
}
// --- test cases ---
void overflowdest_test1(FILE *f)
{
char dest[64];
char src[128];
fgets(src, 128, f); // GOOD (taints `src`)
memcpy(dest, src, sizeof(dest)); // GOOD
memcpy(dest, src, sizeof(src)); // BAD: size derived from the source buffer
memcpy(dest, dest, sizeof(dest)); // GOOD
}
void overflowdest_test2(FILE *f, char *dest, char *src)
{
memcpy(dest, src, strlen(dest) + 1); // GOOD
memcpy(dest, src, strlen(src) + 1); // BAD: size derived from the source buffer
memcpy(dest, dest, strlen(dest) + 1); // GOOD
}
void overflowdest_test3(FILE *f, char *dest, char *src)
{
char *dest2 = dest;
char *src2 = src;
char *src3 = src;
memcpy(dest2, src2, strlen(dest2) + 1); // GOOD
memcpy(dest2, src2, strlen(src2) + 1); // BAD: size derived from the source buffer
memcpy(dest2, dest2, strlen(dest2) + 1); // GOOD
}
void overflowdest_test23_caller(FILE *f)
{
char dest[64];
char src[128];
fgets(src, 128, f); // GOOD (taints `src`)
overflowdest_test2(f, dest, src);
overflowdest_test3(f, dest, src);
}
void overflowdest_test4(FILE *f, int destSize, int srcSize)
{
char *dest = (char *)malloc(destSize);
char *src = (char *)malloc(srcSize);
fgets(src, srcSize, f); // GOOD (taints `src`)
memcpy(dest, src, destSize); // GOOD
memcpy(dest, src, srcSize); // BAD: size derived from the source buffer [NOT DETECTED]
memcpy(dest, dest, destSize); // GOOD
}
class OverflowDestClass5 {
public:
unsigned int bufferSize;
char *buffer;
};
void overflowdest_test5(FILE *f, OverflowDestClass5 &dest, const OverflowDestClass5 &src)
{
fgets(src.buffer, src.bufferSize, f); // GOOD (taints `src`)
memcpy(dest.buffer, src.buffer, dest.bufferSize); // GOOD
memcpy(dest.buffer, src.buffer, src.bufferSize); // BAD: size derived from the source buffer [NOT DETECTED]
memcpy(dest.buffer, dest.buffer, dest.bufferSize); // GOOD
}

View File

@@ -0,0 +1,548 @@
//semmle-extractor-options: --edg --target --edg linux_x86_64
// Semmle test cases for rule CWE-119.
// library types, functions etc
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
void *memcpy(void *s1, const void *s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
void *memset(void *s, int c, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
int printf(const char *format, ...);
size_t strlen(const char *s);
char *strncpy(char *s1, const char *s2, size_t n);
void test1()
{
char smallbuffer[10];
char bigbuffer[20];
memcpy(bigbuffer, smallbuffer, sizeof(smallbuffer)); // GOOD
memcpy(bigbuffer, smallbuffer, sizeof(bigbuffer)); // BAD: over-read
memcpy(smallbuffer, bigbuffer, sizeof(smallbuffer)); // GOOD
memcpy(smallbuffer, bigbuffer, sizeof(bigbuffer)); // BAD: over-write
}
void test2()
{
char *smallbuffer = (char *)malloc(sizeof(char) * 10);
char *bigbuffer = (char *)malloc(sizeof(char) * 20);
memcpy(bigbuffer, smallbuffer, sizeof(smallbuffer)); // GOOD
memcpy(bigbuffer, smallbuffer, sizeof(bigbuffer)); // BAD: over-read [NOT DETECTED]
memcpy(smallbuffer, bigbuffer, sizeof(smallbuffer)); // GOOD
memcpy(smallbuffer, bigbuffer, sizeof(bigbuffer)); // BAD: over-write [NOT DETECTED]
free(bigbuffer);
free(smallbuffer);
}
void test3()
{
char *smallbuffer, *bigbuffer;
smallbuffer = new char[10];
bigbuffer = new char[20];
memcpy(bigbuffer, smallbuffer, sizeof(smallbuffer)); // GOOD
memcpy(bigbuffer, smallbuffer, sizeof(bigbuffer)); // BAD: over-read [NOT DETECTED]
memcpy(smallbuffer, bigbuffer, sizeof(smallbuffer)); // GOOD
memcpy(smallbuffer, bigbuffer, sizeof(bigbuffer)); // BAD: over-write [NOT DETECTED]
delete [] bigbuffer;
delete [] smallbuffer;
}
void test4(int unbounded)
{
int bounded = 100;
char buffer1[100], buffer2[100];
memmove(buffer1, buffer2, bounded); // GOOD
memmove(buffer1, buffer2, unbounded); // BAD: may over-write [NOT DETECTED]
}
void test5(int unbounded)
{
int a, b, c, d, e;
char buffer[100];
buffer[unbounded] = 'x'; // BAD: may under- or over-write [NOT DETECTED]
buffer[0] = buffer[unbounded]; // BAD: may under- or over-read [NOT DETECTED]
a = unbounded;
buffer[a] = 'x'; // BAD: may under- or over-write [NOT DETECTED]
buffer[0] = buffer[a]; // BAD: may under- or over-read [NOT DETECTED]
b = unbounded;
if (b < 0) {b = 0;}
buffer[b] = 'x'; // BAD: may over-write [NOT DETECTED]
buffer[0] = buffer[b]; // BAD: may over-read [NOT DETECTED]
c = unbounded;
if (c > 99) {c = 99;}
buffer[c] = 'x'; // BAD: may under-write [NOT DETECTED]
buffer[0] = buffer[c]; // BAD: may under-read [NOT DETECTED]
d = unbounded;
if (d < 0) {d = 0;}
if (d > 99) {d = 99;}
buffer[d] = 'x'; // GOOD
buffer[0] = buffer[d]; // GOOD
e = unbounded;
e = 50;
buffer[e] = 'x'; // GOOD
buffer[0] = buffer[e]; // GOOD
}
void test6(bool cond)
{
int a, b, c, d, e, f, g, h, i, j, k;
char buffer[100];
char ch;
a = -1;
buffer[a] = 'x'; // BAD: under-write [NOT DETECTED]
ch = buffer[a]; // BAD: under-read [NOT DETECTED]
b = 0;
buffer[b] = 'x'; // GOOD
ch = buffer[b]; // GOOD
c = 100;
buffer[c] = 'x'; // BAD: over-write [NOT DETECTED]
ch = buffer[c]; // BAD: under-read [NOT DETECTED]
d = 0;
d = 1000;
buffer[d] = 'x'; // BAD: over-write [NOT DETECTED]
ch = buffer[d]; // BAD: over-read [NOT DETECTED]
e = 1000;
e = 0;
buffer[e] = 'x'; // GOOD
ch = buffer[e]; // GOOD
f = 0;
if (cond) {f = 1000;}
buffer[f] = 'x'; // BAD: may over-write [NOT DETECTED]
ch = buffer[f]; // BAD: may over-read [NOT DETECTED]
g = 1000;
if (cond) {g = 0;}
buffer[g] = 'x'; // BAD: may over-write [NOT DETECTED]
ch = buffer[g]; // BAD: may over-read [NOT DETECTED]
h = 1000;
if (cond)
{
h = 10;
} else {
h = 20;
}
buffer[h] = 'x'; // GOOD
ch = buffer[h]; // GOOD
for (i = 0; i < 100; i++)
{
buffer[i] = 'x'; // GOOD
ch = buffer[i]; // GOOD
}
for (j = -1; j < 100; j++)
{
buffer[j] = 'x'; // BAD: under-write [NOT DETECTED]
ch = buffer[j]; // BAD: under-read [NOT DETECTED]
}
for (k = 0; k <= 100; k++)
{
buffer[k] = 'x'; // BAD: over-write
ch = buffer[k]; // BAD: over-read
}
}
void test7()
{
char *names[] = {"tom", "dick", "harry"};
printf("name: %s\n", names[-1]); // BAD: under-read
printf("name: %s\n", names[0]); // GOOD
printf("name: %s\n", names[1]); // GOOD
printf("name: %s\n", names[2]); // GOOD
printf("name: %s\n", names[3]); // BAD: over-read
}
void test8(int unbounded)
{
char buffer[128];
int v1 = 128;
int v2 = 256;
int i;
for (i = 0; i < v1; i++)
{
buffer[i] = 0; // GOOD
}
for (i = 0; i < v2; i++)
{
buffer[i] = 0; // BAD: over-write [NOT DETECTED]
}
for (i = 0; i < unbounded; i++)
{
buffer[i] = 0; // BAD: may over-write [NOT DETECTED]
}
unbounded = 128;
for (i = 0; i < unbounded; i++)
{
buffer[i] = 0; // GOOD
}
}
char global_array_5[] = {1, 2, 3, 4, 5};
char global_array_6[] = {1, 2, 3, 4, 5, 6};
void test9(int param)
{
{
char buffer1[32];
char *buffer2 = new char[32];
void *buffer3;
void *buffer4;
buffer3 = malloc(32);
buffer4 = buffer3;
memset(buffer1, 0, 32); // GOOD
memset(buffer1, 0, 33); // BAD: overrun write of buffer1
memset(buffer2, 0, 32); // GOOD
memset(buffer2, 0, 33); // BAD: overrun write of buffer2
memset(buffer3, 0, 32); // GOOD
memset(buffer3, 0, 33); // BAD: overrun write of buffer3
memset(buffer4, 0, 32); // GOOD
memset(buffer4, 0, 33); // BAD: overrun write of buffer4 (buffer3)
memcmp(buffer1, buffer2, 32); // GOOD
memcmp(buffer1, buffer2, 33); // BAD: overrun read of buffer1, buffer2
}
{
char *str1 = "1234567";
char *str2 = "abcdefgh";
strncpy(str1, str2, strlen(str1) + 1); // GOOD
strncpy(str1, str2, strlen(str2) + 1); // BAD: overrun write of str1
strncpy(str2, str1, strlen(str1) + 1); // DUBIOUS (detected)
strncpy(str2, str1, strlen(str2) + 1); // BAD: overrun read of str1 [NOT REPORTED]
}
memmove(global_array_6, global_array_5, 6); // BAD: overrun read of global_array_5
memmove(global_array_5, global_array_6, 6); // BAD: overrun write of global_array_5
if (param > 0)
{
void *buffer = malloc(param);
memset(buffer, 0xFF, param); // GOOD
memset(buffer, 0xFF, param * 2); // BAD: overrun write of buffer [NOT REPORTED]
}
}
wchar_t *wmemset(wchar_t *s, wchar_t c, size_t n);
void test10()
{
wchar_t buffer1[32];
char buffer2[32];
wmemset(buffer1, 0, 32); // GOOD
wmemset(buffer1, 0, 33); // BAD: overrun write of buffer1
wmemset((wchar_t *)buffer2, 0, 32); // BAD: overrun write of buffer2
}
void test11()
{
{
char *string = "Hello, world!";
memset(string, 0, 14); // GOOD
memset(string, 0, 15); // BAD: overrun write of string
}
{
char *buffer = new char[128];
memset(buffer, 0, 128);
buffer = new char[64];
memset(buffer, 0, 128); // BAD: overrun write of buffer
}
{
char array[10] = "123";
memset(array, 0, 10); // GOOD
memset(array, 0, 11); // BAD: overrun write of array
}
}
struct myStruct
{
char buffer[16];
int field;
};
myStruct myVar;
void test12()
{
char buf[16];
char *dbuf;
dbuf = new char[16];
memset(&myVar, 0, sizeof(myVar)); // GOOD
memset(&myVar, 0, sizeof(myVar) + 1); // BAD: overrun write of myVar
memset(myVar.buffer, 0, 16); // GOOD
memset(myVar.buffer, 0, 17); // BAD: overrun write of myVar.buffer
memset(&(myVar.field), 0, sizeof(int)); // GOOD
memset(&(myVar.field), 0, sizeof(int) * 2); // BAD: overrun write of myVar.field
memset(buf + 8, 0, 8); // GOOD
memset(buf + 8, 0, 9); // BAD: overrun write of buf [NOT DETECTED]
memset(dbuf + 8, 0, 8); // GOOD
memset(dbuf + 8, 0, 9); // BAD: overrun write of dbuf [NOT DETECTED]
{
myStruct *myPtr1 = &myVar;
myStruct *myPtr2;
myPtr2 = myPtr1;
memset(myPtr1, 0, sizeof(myStruct)); // GOOD
memset(myPtr1, 0, sizeof(myStruct) + 1); // BAD: overrun write of myVar
memset(myPtr2, 0, sizeof(myStruct)); // GOOD
memset(myPtr2, 0, sizeof(myStruct) + 1); // BAD: overrun write of myVar
}
{
void *myPtr3 = (void *)(&myVar);
memset(myPtr3, 0, sizeof(myStruct)); // GOOD
memset(myPtr3, 0, sizeof(myStruct) + 1); // BAD: overrun write of myVar
}
}
void test13()
{
char charArray[10];
int intArray[10];
myStruct structArray[10];
charArray[-1] = 1; // BAD: underrun write
charArray[0] = 1; // GOOD
charArray[9] = 1; // GOOD
charArray[10] = 1; // BAD: overrun write
charArray[5] = charArray[10]; // BAD: overrun read
intArray[-1] = 1; // BAD: underrun write
intArray[0] = 1; // GOOD
intArray[9] = 1; // GOOD
intArray[10] = 1; // BAD: overrun write
intArray[5] = intArray[10]; // BAD: overrun read
structArray[-1].field = 1; // BAD: underrun write
structArray[0].field = 1; // GOOD
structArray[9].field = 1; // GOOD
structArray[10].field = 1; // BAD: overrun write
structArray[5].field = structArray[10].field; // BAD: overrun read
charArray[9] = (char)intArray[9]; // GOOD
charArray[9] = (char)intArray[10]; // BAD: overrun read
{
unsigned short *buffer1 = (unsigned short *)malloc(sizeof(short) * 50);
unsigned short *buffer2 = (unsigned short *)malloc(101); // 50.5 shorts
buffer1[0] = 0xFFFF;
buffer1[49] = 0xFFFF;
buffer1[50] = 0xFFFF; // BAD: overrun write
buffer2[0] = 0xFFFF;
buffer2[49] = 0xFFFF;
buffer2[50] = 0xFFFF; // BAD: overrun write
}
}
int strncmp(const char *s1, const char *s2, size_t n);
const char *get_buffer();
void get_line(const char **ptr);
void test14()
{
const char *buf;
buf = get_buffer();
if (buf != 0 && memcmp(buf, "mydata", 6) == 0) // GOOD
{
// ...
}
}
void test15()
{
const char *ptr = get_buffer();
int i;
for (i = 0; ; i++)
{
get_line(&ptr);
if (strncmp(ptr, "token", 5) == 0)
{
if (ptr[5] == ' ') // GOOD
{
// ...
}
}
}
}
typedef struct mystruct16
{
int data;
struct mystruct16 *next;
};
void test16()
{
int arr1[10];
int *ptr1_1 = &arr1[9]; // GOOD
int *ptr1_2 = &arr1[10]; // GOOD: valid as long as we don't dereference it
int *ptr1_3 = &arr1[11]; // BAD: not guaranteed to be valid [NOT DETECTED - considered outside the scope of CWE-119]
int x = *--ptr1_2; // GOOD
mystruct16 arr2[10];
mystruct16 *ptr2_1 = &arr2[9]; // GOOD
mystruct16 *ptr2_2 = &arr2[10]; // GOOD: valid as long as we don't dereference it
mystruct16 *ptr2_3 = &arr2[11]; // BAD: not guaranteed to be valid [NOT DETECTED - considered outside the scope of CWE-119]
(--ptr2_2)->data = 1; // GOOD
}
void test17(long long *longArray)
{
longArray[-1] = -1; // BAD: underrun write [NOT DETECTED]
{
int intArray[5];
((char *)intArray)[-3] = 0; // BAD: underrun write
}
{
int multi[10][10];
multi[5][5] = 0; // GOOD
multi[-5][5] = 0; // BAD: underrun write [INCORRECT MESSAGE]
multi[5][-5] = 0; // DUBIOUS: underrun write (this one is still within the bounds of the whole array)
multi[-5][-5] = 0; // BAD: underrun write [INCORRECT MESSAGE]
multi[0][-5] = 0; // BAD: underrun write [NOT DETECTED]
multi[15][5] = 0; // BAD: overrun write
multi[5][15] = 0; // DUBIOUS: overrun write (this one is still within the bounds of the whole array)
multi[15][15] = 0; // BAD: overrun write
}
}
char *update(char *ptr);
void test18()
{
char buffer[128];
char *p1 = buffer;
char *p2 = buffer;
char *p3 = buffer;
char *p4 = (char *)malloc(128);
char *p5 = (char *)malloc(128);
p1[-1] = 0; // BAD: underrun write
p2[-1] = 0; // BAD: underrun write
p2++;
p2[-1] = 0; // GOOD
p3[-1] = 0; // BAD
while (*p3 != 0) {
p3 = update(p3);
}
p3[-1] = 0; // GOOD
p4[-1] = 0; // BAD: underrun write
p4++;
p4[-1] = 0; // GOOD
p5[-1] = 0; // BAD
while (*p5 != 0) {
p5 = update(p5);
}
p5[-1] = 0; // GOOD
}
void test19(bool b)
{
char *p1, *p2, *p3;
p1 = (char *)malloc(10);
p2 = (char *)malloc(10);
p3 = (char *)malloc(20);
// ...
if (b)
{
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
p3 = (char *)malloc(20);
}
// ...
if (b)
{
memset(p1, 0, 20); // BAD
memset(p2, 0, 20); // GOOD
memset(p3, 0, 20); // GOOD
}
}
int main(int argc, char *argv[])
{
long long arr17[19];
test1();
test2();
test3();
test4(argc);
test5(argc);
test6(argc == 0);
test7();
test8(argc);
test9(argc);
test10();
test11();
test12();
test15();
test16();
test17(arr17);
test18();
test19(argc == 0);
return 0;
}

View File

@@ -0,0 +1,20 @@
//semmle-extractor-options: --edg --target --edg linux_x86_64 -std=c99
// library types, functions etc
typedef unsigned long size_t;
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
char smallbuf[1], largebuf[2];
void test1()
{
memcpy(largebuf, smallbuf, 1); // GOOD
memcpy(largebuf, smallbuf, 2); // BAD: source over-read
}
int main(int argc, char *argv[])
{
test1();
return 0;
}

View File

@@ -0,0 +1,54 @@
//semmle-extractor-options: --edg --target --edg linux_x86_64
// Semmle test cases for rule CWE-119 involving unions.
// library types, functions etc
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
void *memset(void *s, int c, size_t n);
void *memcpy(void *s1, const void *s2, size_t n);
// --- unions ---
union myUnion {
char small[10];
char large[100];
};
void myUnionTest()
{
myUnion mu;
memset(&mu, 0, sizeof(mu));
memset(&mu, 0, sizeof(mu.small));
memset(&mu, 0, sizeof(mu.large));
memset(&mu, 0, 200); // BAD
memset(&(mu.small), 0, sizeof(mu));
memset(&(mu.small), 0, sizeof(mu.small));
memset(&(mu.small), 0, sizeof(mu.large)); // (dubious)
memset(&(mu.small), 0, 200); // BAD
memset(&(mu.large), 0, sizeof(mu));
memset(&(mu.large), 0, sizeof(mu.small)); // (dubious)
memset(&(mu.large), 0, sizeof(mu.large));
memset(&(mu.large), 0, 200); // BAD
}
// ---
struct Header {
int f1;
int f2;
int f3;
int f4;
};
union FileBuf {
char buf[0x10000];
struct Header header;
};
void fileBufTest(FileBuf *buf) {
Header* h = (Header *)malloc(sizeof(FileBuf));
memcpy(h, &(buf->header), sizeof(FileBuf)); // GOOD (h, buf are both the size of FileBuf)
}

View File

@@ -0,0 +1,201 @@
//semmle-extractor-options: --edg --target --edg linux_x86_64
// Semmle test cases for rule CWE-119 involving variable size structs.
// library types, functions etc
typedef unsigned long size_t;
void *malloc(size_t size);
void *memset(void *s, int c, size_t n);
char *strncpy(char *s1, const char *s2, size_t n);
// --- tests ---
struct VarString1 {
int length;
char str[1];
};
struct VarString2 {
int length;
char str[1];
void f(void) {return;};
};
struct VarString3 {
int length;
char str[1];
bool operator==(const struct VarString3 &other) const { return true; }
};
struct VarString4 {
int length;
char str[1];
int i;
};
struct VarString5 {
int length;
char str[1];
char str2[1];
};
void testVarString(int n) {
if (n >= 2)
{
VarString1* s1 = (VarString1*)malloc(sizeof(VarString1) + n);
VarString2* s2 = (VarString2*)malloc(sizeof(VarString2) + n);
VarString3* s3 = (VarString3*)malloc(sizeof(VarString3) + n);
VarString4* s4 = (VarString4*)malloc(sizeof(VarString4) + n);
VarString5* s5 = (VarString5*)malloc(sizeof(VarString5) + n);
s1->str[1] = '?'; // GOOD
s2->str[1] = '?'; // GOOD
s3->str[1] = '?'; // GOOD
s4->str[1] = '?'; // BAD
s5->str[1] = '?'; // BAD
}
}
// ---
struct varStruct1 {
int amount;
char data[0];
};
void testVarStruct1() {
varStruct1 *vs1 = (varStruct1 *)malloc(sizeof(varStruct1) + 1024);
vs1->amount = 1024;
memset(vs1->data, 0, 1024); // GOOD
memset(vs1->data, 0, 1025); // BAD: buffer overflow
strncpy(vs1->data, "Hello, world!", 1024); // GOOD
strncpy(vs1->data, "Hello, world!", 1025); // BAD
}
struct varStruct2 {
int size;
int elements[];
};
void testVarStruct2() {
varStruct2 *vs2 = (varStruct2 *)malloc(sizeof(varStruct2) + (16 * sizeof(int)));
int i;
vs2->size = 16;
vs2->elements[15] = 0; // GOOD
vs2->elements[16] = 0; // BAD: buffer overflow
}
struct notVarStruct1 {
int length;
char str[128];
};
void testNotVarStruct1() {
notVarStruct1 *nvs1 = (notVarStruct1 *)malloc(sizeof(notVarStruct1) * 2);
memset(nvs1->str, 0, 128); // GOOD
memset(nvs1->str, 0, 129); // BAD: buffer overflow
memset(nvs1[1].str, 0, 128); // GOOD
memset(nvs1[1].str, 0, 129); // BAD: buffer overflow
strncpy(nvs1->str, "Hello, world!", 128); // GOOD
strncpy(nvs1->str, "Hello, world!", 129); // BAD
}
struct notVarStruct2 {
char str[0];
int length;
};
void testNotVarStruct2() {
notVarStruct2 *nvs2 = (notVarStruct2 *)malloc(sizeof(notVarStruct2) + 128);
nvs2->length = 200;
nvs2->str[0] = '?'; // BAD: buffer overflow [NOT DETECTED]
nvs2->str[1] = '?'; // BAD: buffer overflow [NOT DETECTED]
}
struct varStruct3 {
int a, b, c, d;
unsigned char arr[1];
};
struct varStruct4 {
int a, b, c, d;
unsigned char arr[1];
};
struct varStruct5 {
int a, b, c, d;
unsigned char arr[1];
};
struct varStruct6 {
int a, b, c, d;
unsigned char arr[1];
};
struct varStruct7 {
int a, b, c, d;
unsigned char arr[1];
};
struct varStruct8 {
int a, b, c, d;
float arr[1];
};
struct varStruct9 {
int a, b, c, d;
unsigned char arr[1];
};
#define offsetof(type, memberdesignator) (size_t)(&((type*)0)->memberdesignator)
size_t sizeForVarStruct7(unsigned int array_size)
{
return sizeof(varStruct7) + (sizeof(unsigned char) * array_size) - sizeof(unsigned char);
}
void useVarStruct34(varStruct5 *vs5) {
varStruct3 *vs3a = (varStruct3 *)malloc(sizeof(varStruct3) + 9); // establish varStruct3 as variable size
varStruct3 *vs3b = (varStruct3 *)malloc(sizeof(varStruct3));
varStruct4 *vs4a = (varStruct4 *)malloc(sizeof(varStruct4));
varStruct4 *vs4b = (varStruct4 *)malloc(sizeof(varStruct4));
varStruct5 *vs5a = (varStruct5 *)malloc(sizeof(*vs5) + 9); // establish varStruct5 as variable size
varStruct5 *vs5b = (varStruct5 *)malloc(sizeof(*vs5));
varStruct6 *vs6 = (varStruct6 *)malloc(offsetof(varStruct6, arr) + 9); // establish varStruct6 as variable size
varStruct7 *vs7 = (varStruct7 *)malloc(sizeForVarStruct7(9)); // establish varStruct7 as variable size
varStruct8 *vs8a = (varStruct8 *)malloc(sizeof(varStruct8) + 9); // establish varStruct8 as variable size
varStruct8 *vs8b = (varStruct8 *)malloc(sizeof(varStruct8));
varStruct9 *vs9 = (varStruct9 *)malloc(__builtin_offsetof(varStruct9, arr) + 9); // establish varStruct9 as variable size
}
void testVarStruct34(varStruct3 *vs3, varStruct4 *vs4, varStruct5 *vs5, varStruct6 *vs6, varStruct7 *vs7, varStruct8 *vs8, varStruct9 *vs9) {
memset(vs3->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
memset(vs4->arr, 'x', 100); // BAD: it's not variable size, so this is a buffer overflow
memset(vs5->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
memset(vs6->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
memset(vs7->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
memset(vs8->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
memset(vs9->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
}
// ---
#define NUMINTS (10)
struct PseudoUnion {
unsigned int flags;
char data[0];
int vals[NUMINTS];
};
void usePseudoUnion(PseudoUnion *pu, char *data) {
// clear via pu->vals
memset(pu->vals, 0, sizeof(int) * NUMINTS); // GOOD
// fill via pu->data
strncpy((char *)(pu->vals), data, sizeof(int) * NUMINTS); // GOOD
// clear via pu->data
memset(pu->data, 0, sizeof(int) * NUMINTS); // GOOD
// fill via pu->data
strncpy(pu->data, data, sizeof(int) * NUMINTS); // GOOD
}

View File

@@ -0,0 +1,12 @@
| var_size_struct.cpp:13:8:13:17 | VarString1 | var_size_struct.cpp:15:8:15:10 | str |
| var_size_struct.cpp:18:8:18:17 | VarString2 | var_size_struct.cpp:20:8:20:10 | str |
| var_size_struct.cpp:24:8:24:17 | VarString3 | var_size_struct.cpp:26:8:26:10 | str |
| var_size_struct.cpp:36:8:36:17 | VarString5 | var_size_struct.cpp:39:8:39:11 | str2 |
| var_size_struct.cpp:61:8:61:17 | varStruct1 | var_size_struct.cpp:63:8:63:11 | data |
| var_size_struct.cpp:76:8:76:17 | varStruct2 | var_size_struct.cpp:78:7:78:14 | elements |
| var_size_struct.cpp:119:8:119:17 | varStruct3 | var_size_struct.cpp:121:17:121:19 | arr |
| var_size_struct.cpp:127:8:127:17 | varStruct5 | var_size_struct.cpp:129:17:129:19 | arr |
| var_size_struct.cpp:131:8:131:17 | varStruct6 | var_size_struct.cpp:133:17:133:19 | arr |
| var_size_struct.cpp:135:8:135:17 | varStruct7 | var_size_struct.cpp:137:17:137:19 | arr |
| var_size_struct.cpp:139:8:139:17 | varStruct8 | var_size_struct.cpp:141:9:141:11 | arr |
| var_size_struct.cpp:143:8:143:17 | varStruct9 | var_size_struct.cpp:145:17:145:19 | arr |

View File

@@ -0,0 +1,6 @@
import cpp
import semmle.code.cpp.commons.Buffer
from Class c, MemberVariable v
where memberMayBeVarSize(c, v)
select c, v

View File

@@ -0,0 +1,2 @@
| test.c:20:2:20:7 | call to strcat | Always check the size of the source buffer when using strcat. |
| test.c:33:5:33:10 | call to strcat | Always check the size of the source buffer when using strcat. |

View File

@@ -0,0 +1 @@
Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql

View File

@@ -0,0 +1,41 @@
/* Semmle test case for UnsafeUseOfStrcat.ql
Associated with CWE-120 http://cwe.mitre.org/data/definitions/120.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
char *strcpy(char *s1, const char *s2);
char *strcat(char *s1, const char *s2);
size_t strlen(const char *s);
void *malloc(size_t size);
void free(void *ptr);
//// Test code /////
static void bad0(char *s) {
char buf[80];
strcpy(buf, "s: ");
strcat(buf, s); // BAD -- s may be too long and overflow the buffer
}
static void good0(char *s) {
char buf[80];
strcpy(buf, "s: ");
if(strlen(s) < 77)
strcat(buf, s); // GOOD
}
static void bad1(char *s, int len) {
char *buf = malloc(len+4);
strcpy(buf, "s: ");
strcat(buf, s); // BAD -- s may be too long and overflow the buffer
}
static void good1(char *s, int len) {
char *buf = malloc(len+4);
strcpy(buf, "s: ");
if (strlen(s) <= len)
strcat(buf, s); // GOOD
}

View File

@@ -0,0 +1,2 @@
| tests.c:43:3:43:10 | call to snprintf | This 'call to snprintf' operation is limited to 111 bytes but the destination is only 110 bytes. |
| tests.c:46:3:46:10 | call to snprintf | This 'call to snprintf' operation is limited to 111 bytes but the destination is only 110 bytes. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/BadlyBoundedWrite.ql

View File

@@ -0,0 +1,13 @@
| tests.c:54:3:54:9 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 10 bytes. |
| tests.c:58:3:58:9 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 10 bytes. |
| tests.c:62:17:62:24 | buffer10 | This 'scanf string argument' operation requires 11 bytes but the destination is only 10 bytes. |
| tests.c:63:17:63:24 | buffer10 | This 'scanf string argument' operation requires 12 bytes but the destination is only 10 bytes. |
| tests.c:86:3:86:8 | call to strcpy | This 'call to strcpy' operation requires 6 bytes but the destination is only 5 bytes. |
| tests.c:93:3:93:8 | call to strcpy | This 'call to strcpy' operation requires 6 bytes but the destination is only 5 bytes. |
| tests.c:120:3:120:9 | call to sprintf | This 'call to sprintf' operation requires 17 bytes but the destination is only 1 bytes. |
| tests.c:121:3:121:9 | call to sprintf | This 'call to sprintf' operation requires 17 bytes but the destination is only 16 bytes. |
| tests.c:136:2:136:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 10 bytes. |
| unions.c:26:2:26:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. |
| unions.c:27:2:27:7 | call to strcpy | This 'call to strcpy' operation requires 21 bytes but the destination is only 16 bytes. |
| unions.c:32:2:32:7 | call to strcpy | This 'call to strcpy' operation requires 31 bytes but the destination is only 25 bytes. |
| var_size_struct.cpp:22:3:22:8 | call to strcpy | This 'call to strcpy' operation requires 10 bytes but the destination is only 9 bytes. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWrite.ql

View File

@@ -0,0 +1,2 @@
| tests.c:103:3:103:9 | call to sprintf | This 'call to sprintf' operation may require 318 bytes because of float conversions, but the target is only 256 bytes. |
| tests.c:105:3:105:9 | call to sprintf | This 'call to sprintf' operation may require 346 bytes because of float conversions, but the target is only 256 bytes. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWriteFloat.ql

View File

@@ -0,0 +1,5 @@
| tests.c:28:3:28:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
| tests.c:29:3:29:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 |
| tests.c:34:25:34:33 | buffer100 | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/UnboundedWrite.ql

View File

@@ -0,0 +1,171 @@
//semmle-extractor-options: --edg --target --edg win64
// Semmle test cases for UnboundedWrite.ql, BadlyBoundedWrite.ql, OverrunWrite.ql and OverrunWriteFloat.ql
// Associated with CWE-120 http://cwe.mitre.org/data/definitions/120.html
// Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
///// Library functions //////
typedef unsigned long long size_t;
int sprintf(char *s, const char *format, ...);
int snprintf(char *s, size_t n, const char *format, ...);
int scanf(const char *format, ...);
int sscanf(const char *s, const char *format, ...);
//// Test code /////
int main(int argc, char *argv[])
{
if (argc < 1)
{
return;
}
// Test cases for UnboundedWrite.ql
{
char buffer100[100];
int i;
sprintf(buffer100, argv[0]); // BAD: argv[0] could be more than 100 characters
sprintf(buffer100, "%s", argv[0]); // BAD: argv[0] could be more than 100 characters
scanf("%s", buffer100); // BAD: the input could be more than 100 characters
scanf("%i", i); // GOOD: no problems with non-strings
scanf("%i %s", i, buffer100); // BAD: second format parameter may overflow
sscanf(argv[0], "%s", buffer100); // BAD: argv[0] could be more than 100 characters
}
// Test cases for BadlyBoundedWrite.ql
{
char buffer110[110];
snprintf(buffer110, 109, argv[0]); // GOOD
snprintf(buffer110, 110, argv[0]); // GOOD
snprintf(buffer110, 111, argv[0]); // BAD: this could still overrun the 110 character buffer
snprintf(buffer110, 109, "%s", argv[0]); // GOOD
snprintf(buffer110, 110, "%s", argv[0]); // GOOD
snprintf(buffer110, 111, "%s", argv[0]); // BAD: this could still overrun the 110 character buffer
}
// Test cases for OverrunWrite.ql
{
char buffer10[10];
sprintf(buffer10, "123456789"); // GOOD
sprintf(buffer10, "1234567890"); // BAD: the null terminator of this string overruns the buffer
sprintf(buffer10, "%.9s", "123456789"); // GOOD
sprintf(buffer10, "%.9s", "1234567890"); // GOOD
sprintf(buffer10, "%.10s", "123456789"); // GOOD
sprintf(buffer10, "%.10s", "1234567890"); // BAD: the precision specified is too large for this buffer
scanf("%8s", buffer10); // GOOD: restricted to 8 characters + null
scanf("%9s", buffer10); // GOOD: restricted to 9 characters + null
scanf("%10s", buffer10); // BAD: null can overflow
scanf("%11s", buffer10); // BAD: string can overflow
}
// More complex tests for OverrunWrite.ql
{
char buffer5[5];
char *str4, *str24, *str35;
str4 = "1234";
strcpy(buffer5, str4); // GOOD: str4 fits in the buffer
str24 = "12";
if (argc == 1)
{
str24 = "1234";
}
strcpy(buffer5, str24); // GOOD: both possible strings fit in the buffer
str35 = "123";
if (argc == 1)
{
str35 = "12345";
}
strcpy(buffer5, str35); // BAD: if str35 is "12345", it overflows the buffer
str35 = "abc";
strcpy(buffer5, str35); // GOOD: str35 is guaranteed to fit now
strcpy(buffer5, (argc == 2) ? "1234" : "abcd"); // GOOD: both of the strings fit
strcpy(buffer5, (argc == 2) ? "1234" : "abcde"); // BAD: "abcde" overflows the buffer
}
// Test cases for OverrunWriteFloat.ql
{
char buffer256[256];
char buffer999[999];
double bigval = 1e304;
sprintf(buffer256, "%e", bigval); // GOOD
sprintf(buffer256, "%f", bigval); // BAD: this %f representation may need more than 256 characters
sprintf(buffer256, "%g", bigval); // GOOD
sprintf(buffer256, "%e%f%g", bigval, bigval, bigval); // BAD: the %f representation may need more than 256 characters
// GOOD: a 999 character buffer is sufficient in all of these cases
sprintf(buffer999, "%e", bigval); // GOOD
sprintf(buffer999, "%f", bigval); // GOOD
sprintf(buffer999, "%g", bigval); // GOOD
sprintf(buffer999, "%e%f%g", bigval, bigval, bigval); // GOOD
}
// Test cases for %p
{
char buffer1[1];
char buffer16[16];
char buffer17[17];
char buffer49[49];
sprintf(buffer1, "%p", argv); // BAD
sprintf(buffer16, "%p", argv); // BAD
sprintf(buffer17, "%p", argv); // GOOD
sprintf(buffer49, "%p and then a few more words", argv); // GOOD
}
return 0;
}
typedef char MyCharArray[10];
void test_fn2()
{
MyCharArray myBuffer10;
sprintf(myBuffer10, "%s", "123456789"); // GOOD
sprintf(myBuffer10, "%s", "1234567890"); // BAD: buffer overflow
}
// ---
typedef struct
{
char *string;
int value;
} StringStruct;
#define GETSTRING(x) ((x)->string)
#define GETVALUE(x) ((x)->value)
#define MAX_INT_LEN (11)
void testStringStruct(StringStruct *ss)
{
snprintf(GETSTRING(ss), sizeof("Number: "), "Number: %i", GETVALUE(ss)); // BAD: potential buffer overflow [NOT DETECTED]
snprintf(GETSTRING(ss), sizeof("Number: ") + MAX_INT_LEN, "Number: %i", GETVALUE(ss)); // GOOD
}
// ---
typedef struct
{
int size;
char data[0];
} VarSizeStruct;
void testVarSizeStruct()
{
char buffer[sizeof(VarSizeStruct) + 10];
VarSizeStruct *s = buffer;
snprintf(s->data, 10, "abcdefghijklmnopqrstuvwxyz"); // GOOD
}

View File

@@ -0,0 +1,33 @@
//semmle-extractor-options: --edg --target --edg win64
// Semmle test cases for UnboundedWrite.ql, BadlyBoundedWrite.ql, OverrunWrite.ql and OverrunWriteFloat.ql
// Associated with CWE-120 http://cwe.mitre.org/data/definitions/120.html
// Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
///// Library functions //////
typedef unsigned long long size_t;
char *strcpy(char *s1, const char *s2);
//// Test code /////
typedef union {
char *ptr;
char buffer[15];
} MyUnion;
void unions_test(MyUnion *mu)
{
char buffer[25];
strcpy(mu, "1234567890"); // GOOD
strcpy(&(mu->ptr), "1234567890"); // GOOD (dubious)
strcpy(&(mu->buffer), "1234567890"); // GOOD
strcpy(mu, "12345678901234567890"); // BAD [NOT DETECTED]
strcpy(&(mu->ptr), "12345678901234567890"); // BAD
strcpy(&(mu->buffer), "12345678901234567890"); // BAD
mu->ptr = buffer;
strcpy(mu->ptr, "1234567890"); // GOOD
strcpy(mu->ptr, "12345678901234567890"); // GOOD
strcpy(mu->ptr, "123456789012345678901234567890"); // BAD
}

View File

@@ -0,0 +1,23 @@
//semmle-extractor-options: --edg --target --edg linux_x86_64
// Semmle test cases for rule CWE-120 involving variable size structs.
// library types, functions etc
typedef unsigned long size_t;
void *malloc(size_t size);
char *strcpy(char *s1, const char *s2);
// --- Semmle tests ---
struct varStruct {
int size;
char data[1];
};
void testVarStruct() {
varStruct *vs = (varStruct *)malloc(sizeof(varStruct) + 8);
vs->size = 9;
strcpy(vs->data, "12345678"); // GOOD
strcpy(vs->data, "123456789"); // BAD: buffer overflow
}

View File

@@ -0,0 +1,9 @@
| more_tests.cpp:23:2:23:12 | call to myFunction2 | Calls to $@ should use the value -1 as a terminator (4 calls do). | more_tests.cpp:5:6:5:16 | myFunction2 | myFunction2 |
| more_tests.cpp:34:2:34:12 | call to myFunction4 | Calls to $@ should use the value 0 as a terminator (3 calls do). | more_tests.cpp:7:6:7:16 | myFunction4 | myFunction4 |
| more_tests.cpp:44:2:44:12 | call to myFunction6 | Calls to $@ should use the value 0 as a terminator (3 calls do). | more_tests.cpp:9:6:9:16 | myFunction6 | myFunction6 |
| more_tests.cpp:55:2:55:12 | call to myFunction7 | Calls to $@ should use the value 0 as a terminator (7 calls do). | more_tests.cpp:10:6:10:16 | myFunction7 | myFunction7 |
| more_tests.cpp:56:2:56:12 | call to myFunction7 | Calls to $@ should use the value 0 as a terminator (7 calls do). | more_tests.cpp:10:6:10:16 | myFunction7 | myFunction7 |
| tests.c:34:2:34:3 | call to f1 | Calls to $@ should use the value 0 as a terminator (4 calls do). | tests.c:4:6:4:7 | f1 | f1 |
| tests.c:67:2:67:3 | call to f6 | Calls to $@ should use the value -1 as a terminator (3 calls do). | tests.c:24:6:24:7 | f6 | f6 |
| tests.c:68:2:68:3 | call to f6 | Calls to $@ should use the value -1 as a terminator (3 calls do). | tests.c:24:6:24:7 | f6 | f6 |
| tests.c:73:2:73:3 | call to f7 | Calls to $@ should use the value 0 as a terminator (3 calls do). | tests.c:28:6:28:7 | f7 | f7 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-121/UnterminatedVarargsCall.ql

View File

@@ -0,0 +1,59 @@
#define NULL (0)
void myFunction1(char *format, ...);
void myFunction2(...);
void myFunction3(...);
void myFunction4(int i, int j, ...);
void myFunction5(...);
void myFunction6(...);
void myFunction7(...);
int main()
{
int x;
myFunction1("%i", 0); // not common enough to be assumed a terminator
myFunction1("%i", x);
myFunction2(-1);
myFunction2(0, -1);
myFunction2(0, 1, -1);
myFunction2(0, 1, 2, -1);
myFunction2(0, 1, 2, 3); // missing terminator
myFunction3(-1);
myFunction3(0, -1);
myFunction3(-1, 1, -1); // -1 isn't a terminator because it's used in a non-terminal position
myFunction3(0, 1, 2, -1);
myFunction3(0, 1, 2, 3);
myFunction4(x, x, 0);
myFunction4(0, x, 1, 0);
myFunction4(0, 0, 1, 1, 0);
myFunction4(x, 0, 1, 1, 1); // missing terminator
myFunction5('a', 'b', 'c', 0); // ambiguous terminator
myFunction5('a', 'b', 'c', 0);
myFunction5('a', 'b', 'c', 0);
myFunction5('a', 'b', 'c', -1);
myFunction5('a', 'b', 'c', -1);
myFunction5('a', 'b', 'c', -1);
myFunction6(0.0);
myFunction6(1.0); // missing terminator
myFunction6(1.0, 2.0, 0.0);
myFunction6(1.0, 2.0, 3.0, 0.0);
myFunction7(NULL);
myFunction7("hello", "world", NULL);
myFunction7("apple", "banana", "pear", "mango", NULL);
myFunction7("dog", "cat", "elephant", "badger", "fish", NULL);
myFunction7("one", "two", "three", 0);
myFunction7("alpha", "beta", "gamma", 0);
myFunction7("", 0);
myFunction7("yes", "no"); // missing terminator
myFunction7(); // missing terminator
return 0;
}

View File

@@ -0,0 +1,76 @@
// Semmle test cases for UnterminatedVarargsCall.ql
// Associated with CWE-121 http://cwe.mitre.org/data/definitions/121.html
void f1(char *format, ...)
{
}
void f2(char *format, ...)
{
}
void f3(char *format, ...)
{
}
void f4(char *format, ...)
{
}
void f5(char *format, ...)
{
}
void f6(char *format, ...)
{
}
void f7(char *format, ...)
{
}
int main(int argc, char *argv[])
{
f1("", 1); // BAD: not terminated with 0
f1("", 1, 0);
f1("", 1, 1, 0);
f1("", 1, 1, 1, 0);
f1("", 1, 1, 1, 1, 0);
// GOOD: no obvious required terminator
f2("", 10);
// GOOD: 0 is not common enough to be sure it's a terminator
f3("", 0);
f3("", 10);
// GOOD: -1 is not common enough to be sure it's a terminator
f4("", 0);
f4("", 0);
f4("", -1);
f4("", -1);
f4("", -1);
f4("", 1);
// GOOD: no obvious required terminator
f5("");
f5("");
f5("");
f5("");
f5("", 0);
f5("", 0);
f5("", 10);
f6("fsdf", 3, 8, -1);
f6("a", 7, 9, 10, -1);
f6("a", 1, 22, 6, 17, 2, -1);
f6("fgasfgas", 5, 6, argc); // BAD: not (necessarily) terminated with -1
f6("sadfsaf"); // BAD: not terminated with -1
f7("", 0);
f7("", 0);
f7("", 0);
f7(""); // BAD: not terminated with 0
return 0;
}

View File

@@ -0,0 +1,4 @@
| test1.c:18:16:18:16 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:33:11:33:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:37:11:37:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
| test1.c:53:15:53:15 | j | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-129/ImproperArrayIndexValidation.ql

View File

@@ -0,0 +1,54 @@
int atoi(const char *nptr);
void dosomething(char c);
const char chr[26] = "abcdefghijklmnopqrstuvwxyz";
int main(int argc, char *argv[]) {
int i = atoi(argv[1]);
test1(i);
test2(i);
test3(i);
test4(i);
test5(i);
}
void test1(int i) {
// BAD: i has not been validated.
char c = chr[i];
dosomething(c);
}
void test2(int i) {
if (0 <= i && i < 26) {
// GOOD: i has been validated.
char c = chr[i];
dosomething(c);
}
}
int myArray[10];
void test3(int i) {
myArray[i] = 0; // BAD: i has not been validated
i = 5;
myArray[i] = 0; // GOOD: i is not untrusted input [FALSE POSITIVE]
}
void test4(int i) {
myArray[i] = 0; // BAD: i has not been validated [NOT REPORTED]
if ((i < 0) || (i >= 10)) return;
myArray[i] = 1; // GOOD: i has been validated
}
void test5(int i) {
int j = 0;
j = i;
j = myArray[j]; // BAD: j has not been validated
}

View File

@@ -0,0 +1,65 @@
/* Semmle test case for NoSpaceForZeroTerminator.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
//// Test code /////
void bad0(char *str) {
// BAD -- Not allocating space for '\0' terminator
char *buffer = malloc(strlen(str));
free(buffer);
}
void good0(char *str) {
// GOOD -- Allocating extra byte for terminator
char *buffer = malloc(strlen(str)+1);
free(buffer);
}
void bad1(char *str) {
int len = strlen(str);
// BAD -- Not allocating space for '\0' terminator
char *buffer = malloc(len);
free(buffer);
}
void good1(char *str) {
int len = strlen(str);
// GOOD -- Allocating extra byte for terminator
char *buffer = malloc(len+1);
free(buffer);
}
void bad2(char *str) {
int len = strlen(str);
// BAD -- Not allocating space for '\0' terminator
char *buffer = malloc(len);
free(buffer);
}
void good2(char *str) {
int len = strlen(str)+1;
// GOOD -- Allocating extra byte for terminator
char *buffer = malloc(len);
free(buffer);
}
void bad3(char *str) {
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
char *buffer = malloc(strlen(str) * sizeof(char));
free(buffer);
}
void good3(char *str) {
// GOOD -- Allocating extra byte for terminator
char *buffer = malloc((strlen(str) + 1) * sizeof(char));
free(buffer);
}

View File

@@ -0,0 +1,32 @@
/* Semmle test case for NoSpaceForZeroTerminator.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
size_t wcslen(const wchar_t *s);
//// Test code /////
void bad1(wchar_t *wstr) {
// BAD -- Not allocating space for '\0' terminator
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr));
free(wbuffer);
}
void bad2(wchar_t *wstr) {
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t));
free(wbuffer);
}
void good1(wchar_t *wstr) {
// GOOD -- Allocating extra character for terminator
wchar_t *wbuffer = (wchar_t *)malloc((wcslen(wstr) + 1) * sizeof(wchar_t));
free(wbuffer);
}

View File

@@ -0,0 +1,4 @@
| test.c:15:20:15:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.c:29:20:29:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.c:44:20:44:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:18:35:18:40 | call to malloc | This allocation does not include space to null-terminate the string. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql

View File

@@ -0,0 +1,47 @@
/* Semmle test case for SizeCheck.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
//// Test code /////
void bad0(void) {
float *fptr = malloc(3); // BAD -- Too small
double *dptr = malloc(5); // BAD -- Too small
free(fptr);
free(dptr);
}
void good0(void) {
float *fptr = malloc(4); // GOOD -- Correct size
double *dptr = malloc(8); // GOOD -- Correct size
free(fptr);
free(dptr);
}
void bad1(void) {
float *fptr = malloc(sizeof(short)); // BAD -- Too small
double *dptr = malloc(sizeof(float)); // BAD -- Too small
free(fptr);
free(dptr);
}
void good1(void) {
float *fptr = malloc(sizeof(float)); // GOOD -- Correct size
double *dptr = malloc(sizeof(double)); // GOOD -- Correct size
free(fptr);
free(dptr);
}

View File

@@ -0,0 +1,4 @@
| test.c:16:19:16:24 | call to malloc | Type 'float' is 4 bytes, but only 3 bytes are allocated. |
| test.c:17:20:17:25 | call to malloc | Type 'double' is 8 bytes, but only 5 bytes are allocated. |
| test.c:32:19:32:24 | call to malloc | Type 'float' is 4 bytes, but only 2 bytes are allocated. |
| test.c:33:20:33:25 | call to malloc | Type 'double' is 8 bytes, but only 4 bytes are allocated. |

View File

@@ -0,0 +1 @@
Critical/SizeCheck.ql

View File

@@ -0,0 +1,47 @@
/* Semmle test case for SizeCheck2.ql
Associated with CWE-131 http://cwe.mitre.org/data/definitions/131.html
Each query is expected to find exactly the lines marked BAD in the section corresponding to it.
*/
///// Library functions //////
typedef unsigned long size_t;
void *malloc(size_t size);
void free(void *ptr);
//// Test code /////
void bad0(void) {
long long *lptr = malloc(27); // BAD -- Not a multiple of sizeof(long long)
double *dptr = malloc(33); // BAD -- Not a multiple of sizeof(double)
free(lptr);
free(dptr);
}
void good0(void) {
float *fptr = malloc(24); // GOOD -- An integral multiple
double *dptr = malloc(56); // GOOD -- An integral multiple
free(fptr);
free(dptr);
}
void bad1(void) {
long long *lptr = malloc(sizeof(long long)*7/2); // BAD -- Not a multiple of sizeof(long long)
double *dptr = malloc(sizeof(double)*5/2); // BAD -- Not a multiple of sizeof(double)
free(lptr);
free(dptr);
}
void good1(void) {
long long *lptr = malloc(sizeof(long long)*5); // GOOD -- An integral multiple
double *dptr = malloc(sizeof(double)*7); // GOOD -- An integral multiple
free(lptr);
free(dptr);
}

View File

@@ -0,0 +1,4 @@
| test.c:16:23:16:28 | call to malloc | Allocated memory (27 bytes) is not a multiple of the size of 'long long' (8 bytes). |
| test.c:17:20:17:25 | call to malloc | Allocated memory (33 bytes) is not a multiple of the size of 'double' (8 bytes). |
| test.c:32:23:32:28 | call to malloc | Allocated memory (28 bytes) is not a multiple of the size of 'long long' (8 bytes). |
| test.c:33:20:33:25 | call to malloc | Allocated memory (20 bytes) is not a multiple of the size of 'double' (8 bytes). |

View File

@@ -0,0 +1 @@
Critical/SizeCheck2.ql

View File

@@ -0,0 +1,169 @@
// Semmle test case for rule UncontrolledFormatString.ql (Uncontrolled format string).
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
// This file tests different ways to use argv as an argument to printf.
typedef unsigned long size_t;
int printf(const char *format, ...);
void *memcpy(void *s1, const void *s2, size_t n);
void *malloc(size_t size);
void printWrapper(char *correct) {
printf(correct);
}
int main(int argc, char **argv) {
// GOOD: constant format
printf("Correct");
printWrapper("Correct");
// GOOD: c1 is always a constant format
char *c1 = "Correct";
printf(c1);
printWrapper(c1);
// GOOD: c2 is always a constant format
char *c2 = c1;
printf(c2);
printWrapper(c2);
// GOOD: c3 is always a constant format
char **c3 = &c2;
printf(*c3);
printWrapper(*c3);
// GOOD: c4 is always a constant format
char c4[5012];
memcpy(c4, "Correct", 5012);
printf(c4);
printWrapper(c4);
// GOOD: c5 is always a constant format
char *c5 = c4;
printf(c5);
printWrapper(c5);
// GOOD: c6 is always a constant format
char *c6;
*c6 = *c1;
printf(c6);
printWrapper(c6);
// GOOD: constant format
printf("Correct" + 1);
printWrapper("Correct" + 1);
// GOOD: c6 is always a constant format
printf(c6++);
printWrapper(--c6);
// GOOD: c5 is always a constant format
printf(1 ? "a" : c5);
printWrapper(1 ? "a" : c5);
// GOOD: both c5 and "a" are always constant
printf(argv[1] ? "a" : c5);
printWrapper(argv[1] ? "a" : c5);
// GOOD: c7 equals "a", which is constant
char *c7 = (argv[1] , "a");
printf(c7);
printWrapper(c7);
// GOOD: c8 is always a constant format
char *c8;
*(&c8 + 1) = "a";
printf(c8);
printWrapper(c8);
// GOOD: c9 is always a constant format
char *c9;
memcpy(1 ? c9++ : 0, "Correct", 5012);
printf(c9);
printWrapper(c9);
// GOOD: c91 is always a constant format
char *c91;
memcpy(0 ? 0 : (char *)((int) c91 * 2), "Correct", 5012);
printf(c91);
printWrapper(c91);
// GOOD: c10 is always a constant format
int c10 = (int) "aaa";
printf((char *) c10);
printWrapper((char *) c10);
// BAD: format comes from argv
printf(argv[1]);
printWrapper(argv[1]);
// BAD: i1 value comes from argv
char *i1;
i1 = argv[1];
printf(i1);
printWrapper(i1);
// BAD: i2 value comes from argv
char **i2 = argv;
printf(i2[0]);
printWrapper(i2[0]);
// BAD: i2 value comes from argv
printf(*i2);
printWrapper(*i2);
// BAD: i3 value comes from argv
char i3[5012];
memcpy(i3, argv[1], 5012);
printf(i3);
printWrapper(i3);
// BAD: i4 value comes from argv
char *i4 = i3;
printf(i4);
printWrapper(i4);
// BAD: i5 value comes from argv
char i5[5012];
i5[0] = argv[1][0];
printf(i5);
printWrapper(i5);
// BAD: i5 value comes from argv
printf(i5 + 1);
printWrapper(i5 + 1);
// BAD: i4 value comes from argv
printf(i4++);
printWrapper(--i4);
// BAD: i5 value comes from argv, so in some cases the format come from argv
printf(argv[1] ? "a" : i5);
printWrapper(argv[1] ? "a" : i5);
// BAD: i7 receives the value of i1, which comes from argv
char *i7 = (argv[1] , i1);
printf(i7);
printWrapper(i7);
// BAD: i8 value comes from argv
char *i8;
*(&i8 + 1) = argv[1];
printf(i8);
printWrapper(i8);
// BAD: i9 value comes from argv
char *i9;
memcpy(1 ? i9++ : 0, argv[1], 1);
printf(i9);
printWrapper(i9);
// BAD: i91 value comes from argv
char *i91;
memcpy(0 ? 0 : (char *)((int) i91 * 2), argv[1], 1);
printf(i91);
printWrapper(i91);
// BAD: i10 value comes from argv
int i10 = (int) argv[1];
printf((char *) i10);
printWrapper((char *) i10);
}

View File

@@ -0,0 +1,30 @@
| argvLocal.c:95:9:95:15 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:95:9:95:12 | argv | argv |
| argvLocal.c:96:15:96:21 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:96:15:96:18 | argv | argv |
| argvLocal.c:101:9:101:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
| argvLocal.c:102:15:102:16 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
| argvLocal.c:106:9:106:13 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv |
| argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv |
| argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv |
| argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv |
| argvLocal.c:116:9:116:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:117:15:117:16 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:121:9:121:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:122:15:122:16 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
| argvLocal.c:139:9:139:26 | ... ? ... : ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:140:15:140:32 | ... ? ... : ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
| argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
| argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
| argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:15:149:18 | argv | argv |
| argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:15:149:18 | argv | argv |
| argvLocal.c:156:9:156:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:155:23:155:26 | argv | argv |
| argvLocal.c:157:15:157:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:155:23:155:26 | argv | argv |
| argvLocal.c:162:9:162:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:161:42:161:45 | argv | argv |
| argvLocal.c:163:15:163:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:161:42:161:45 | argv | argv |
| argvLocal.c:167:18:167:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:166:18:166:21 | argv | argv |
| argvLocal.c:168:24:168:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:166:18:166:21 | argv | argv |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatString.ql

View File

@@ -0,0 +1,16 @@
| consts.cpp:63:9:63:10 | c5 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:69:9:69:10 | c6 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:81:9:81:10 | c8 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:86:9:86:10 | v1 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:91:9:91:10 | v2 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:95:9:95:10 | v3 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:100:9:100:10 | v4 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:103:9:103:15 | call to varFunc | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:107:9:107:10 | v5 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:112:9:112:10 | v6 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:116:9:116:13 | access to array | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:121:9:121:10 | v8 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:130:9:130:10 | v9 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:135:9:135:11 | v10 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:140:9:140:11 | v11 | The format string argument to printf should be constant to prevent security issues and other potential errors. |
| consts.cpp:145:9:145:11 | v12 | The format string argument to printf should be constant to prevent security issues and other potential errors. |

View File

@@ -0,0 +1 @@
Likely Bugs/Format/NonConstantFormat.ql

View File

@@ -0,0 +1,146 @@
// Semmle test case for rule NonConstantFormat.ql (non-constant format string).
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
// Constant strings are compliant with CWE-134 and non-constant strings may be non-compliant with CWE-134.
int printf(const char *format, ...);
int sprintf(char *s, const char *format, ...);
char *gets(char *s);
void readString(char **line);
void readStringRef(char *&line);
char *varFunc();
char *constFunc() {
return "asd";
}
char *gc1[] = {
"a",
"b"
};
char *constFuncToArray(int i) {
return gc1[i];
}
char *gv1[] = {
"a",
"b"
};
char *nonConstFuncToArray(int i) {
return gv1[i];
}
void a() {
// GOOD: format is always constant
printf("-");
// GOOD: c1 value is always constant
const char *c1 = "a";
printf(c1);
// GOOD: c2 value is always constant
const char *c2;
c2 = "b";
printf(c2);
// GOOD: c3 value is copied from c1 which is always constant
//
const char *c3 = c1;
printf(c3);
// GOOD: c4 value is copied from c1 which is always constant
//
const char *c4;
c4 = c1;
printf(c4);
// GOOD: constFunc() always returns a constant string
printf(constFunc());
// GOOD: constFunc() always returns a constant string
// But we still don't track constantness flow from functions to variables
char *c5 = constFunc();
printf(c5);
// GOOD: constFunc() always returns a constant string
// But we still don't track constantness flow from functions to variables
char *c6;
c6 = constFunc();
printf(c6);
// GOOD: all elements of c7 are always constant
char *c7[] = { "a", "b" };
printf(c7[0]);
// GOOD: constFuncToArray() always returns a value from gc1, which is always constant
printf(constFuncToArray(0));
// BAD: format string is not constant
char c8[10];
sprintf(c8, "%d", 1);
printf(c8);
// BAD: v1 value came from the user
char *v1;
gets(v1);
printf(v1);
// BAD: v2 value came from the user
char *v2;
v2 = gets(v1);
printf(v2);
// BAD: v3 value is copied from v1, which came from the user
char *v3 = v1;
printf(v3);
// BAD: v4 value is copied from v1, which came from the user
char *v4;
v4 = v1;
printf(v4);
// BAD: varFunc() is not defined, so it may not be constant
printf(varFunc());
// BAD: varFunc() is not defined, so it may not be constant
char *v5 = varFunc();
printf(v5);
// BAD: varFunc() is not defined, so it may not be constant
char *v6;
v6 = varFunc();
printf(v6);
// BAD: all elements of v7 came from the user
char *v7[] = { v1, v2 };
printf(v7[0]);
// BAD: v8 started as constant, but changed to a value that came from the user
char *v8 = "a";
v8 = v7[1];
printf(v8);
gv1[1] = v1;
// BAD: nonConstFuncToArray() always returns a value from gv1, which is started as constant but was changed to a value that came from the user
printf(nonConstFuncToArray(0));
// BAD: v9 value is copied from v1, which came from the user [NOT DETECTED]
const char *v9 = v1;
printf(v9);
// BAD: v10 value is derived from values that are not constant
char v10[10];
sprintf(v10, "%s", v1);
printf(v10);
// BAD: v11 is initialized via a pointer
char *v11;
readString(&v11);
printf(v11);
// BAD: v12 is initialized via a reference
char *v12;
readStringRef(v12);
printf(v12);
}

View File

@@ -0,0 +1,61 @@
// Semmle test case for rule UncontrolledFormatString.ql (Uncontrolled format string).
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
// This file tests different ways to use the results of various function calls (that read information from the user) as an argument to printf.
int printf(const char *format, ...);
typedef unsigned long size_t;
typedef void FILE;
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);
FILE *f;
int main(int argc, char **argv) {
// BAD: i1 comes from the user
char i1[1024];
fread(i1, sizeof(char), 1024, f);
printf(i1);
// GOOD: i2 comes from the user, but is not the format string here
char i2[1024];
fread(i2, sizeof(char), 1024, f);
printf("%s", i2);
// BAD: i3 comes from the user
char i3[1024];
fgets(i3, 1, 0);
printf(i3);
// BAD: i4 comes from the user
char i41[1024];
char *i4 = fgets(i41, 1, f);
printf(i4);
// BAD: i5 comes from the user
char i5[1024];
gets(i5);
printf(i5);
// BAD: i6 comes from the user
char i61[1024];
char *i6 = gets(i61);
printf(i6);
// BAD: i7 comes from the user
char **i7;
gets(*i7);
printf(*i7);
// BAD: i8 comes from the user
char i81[1024];
char **i8;
*i8 = gets(i81);
printf(*i8);
// BAD: e1 comes from i1, which comes from the user
char e1[1];
e1[0] = i1[0];
printf(e1);
return 0;
}

View File

@@ -0,0 +1,8 @@
| funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread |
| funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets |
| funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets |
| funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets |
| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets |
| funcsLocal.c:47:9:47:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:46:7:46:9 | * ... | gets |
| funcsLocal.c:53:9:53:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:52:8:52:11 | call to gets | gets |
| funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatString.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatString.ql

View File

@@ -0,0 +1,5 @@
| globalVars.c:27:9:27:12 | copy | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:8:7:8:10 | copy | copy | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:30:15:30:18 | copy | This value may flow through $@, originating from $@, and is a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:8:7:8:10 | copy | copy | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:38:9:38:13 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:41:15:41:19 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv |
| globalVars.c:50:9:50:13 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql

View File

@@ -0,0 +1,51 @@
// Semmle test case for rule UncontrolledFormatStringThroughGlobalVar.ql (Uncontrolled format string (through global variable)).
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
// This file tests different ways to track argv usage to printf calls through global variables.
int printf(const char *format, ...);
char *copy;
char *copy2;
void copyArgv(char **argv) {
copy = argv[1];
}
void setCopy2(char *val) {
copy2 = val;
}
void printWrapper(char *str) {
printf(str);
}
int main(int argc, char **argv) {
copyArgv(argv);
// BAD: format comes from argv through copy
printf(copy);
// BAD: format comes from argv through copy
printWrapper(copy);
// GOOD: constant format
printf("%s", copy);
setCopy2(copy);
// BAD: format comes from argv through copy2 (that is set to copy that is set to argv[1])
printf(copy2);
// BAD: format comes from argv through copy2 (that is set to copy that is set to argv[1])
printWrapper(copy2);
// GOOD: constant format
printf("%s", copy2);
setCopy2("asdf");
// Should be GOOD because copy2 has value "asdf"
// But we flag this case because once a global variable gets tainted we mark all usages as tainted
printf(copy2);
}

View File

@@ -0,0 +1,132 @@
// Semmle test case for rule UncontrolledFormatString.ql (Uncontrolled format string).
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
// This file tests different ways to ignore branchs in code that will never be executed.
int printf(const char *format, ...);
int func();
int globalZero = 0;
int globalOne = 1;
int globalUnknown;
int inv(int a) {
return !a;
}
int main(int argc, char **argv) {
int varZero = 0;
int varOne = 1;
globalUnknown = func();
// GOOD: condition is false and it never goes inside the if
char *c1;
if (0)
c1 = argv[1];
printf(c1);
// GOOD: condition is false and it never goes inside the if
char *c2;
if (1 == 0)
c2 = argv[1];
printf(c2);
// GOOD: condition is false and it never goes inside the if
char *c3;
if (!1)
c3 = argv[1];
printf(c3);
// GOOD: varZero is 0 so condition is false and it never goes inside the if
char *c4;
if (varZero)
c4 = argv[1];
printf(c4);
// GOOD: varOne is 1 so condition is false and it never goes inside the if
char *c5;
if (!varOne)
c5 = argv[1];
printf(c5);
// GOOD: condition is false and it never goes inside the if
char *c6;
if (varOne == varZero)
c6 = argv[1];
printf(c6);
// GOOD: globalZero is 0 so condition is false and it never goes inside the if
char *c7;
if (globalZero)
c7 = argv[1];
printf(c7);
// GOOD: inv(1) returns 0 and it never goes inside the if
// But we can't handle this case because currently we don't analyse arguments in function calls
char *c8;
if (inv(1))
c8 = argv[1];
printf(c8);
// BAD: condition is true and it always goes inside the if
char *i1;
if (1)
i1 = argv[1];
printf(i1);
// BAD: condition is true and it always goes inside the if
char *i2;
if (0 == 0)
i2 = argv[1];
printf(i2);
// BAD: condition is true and it always goes inside the if
char *i3;
if (!0)
i3 = argv[1];
printf(i3);
// BAD: varOne is 1 so condition is true and it always goes inside the if
char *i4;
if (varOne)
i4 = argv[1];
printf(i4);
// BAD: varZero is 0 so condition is true and it always goes inside the if
char *i5;
if (!varZero)
i5 = argv[1];
printf(i5);
// BAD: condition is true and it always goes inside the if
// But our analysis only handle booleans, so it isn't able the detect that both values are the same (we can handle only 0 == 0)
char *i6;
if (varOne == varOne)
i6 = argv[1];
printf(i6);
// BAD: globalOne is 1 so condition is true and it always goes inside the if
char *i7;
if (globalOne)
i7 = argv[1];
printf(i7);
// BAD: we don't know the value of globalUnknown so we have to assume it can be true
char *i8;
if (globalUnknown)
i8 = argv[1];
printf(i8);
// BAD: inv(0) returns 1 and it always goes inside the if
char *i9;
if (inv(0))
i9 = argv[1];
printf(i9);
return 0;
// GOOD: because it is after a return and never will be reached
char *c9;
c9 = argv[1];
printf(c9);
}

View File

@@ -0,0 +1,10 @@
| ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv |
| ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv |
| ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv |
| ifs.c:87:9:87:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:86:8:86:11 | argv | argv |
| ifs.c:93:9:93:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:92:8:92:11 | argv | argv |
| ifs.c:99:9:99:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:98:8:98:11 | argv | argv |
| ifs.c:106:9:106:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:105:8:105:11 | argv | argv |
| ifs.c:112:9:112:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:111:8:111:11 | argv | argv |
| ifs.c:118:9:118:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:117:8:117:11 | argv | argv |
| ifs.c:124:9:124:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:123:8:123:11 | argv | argv |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatString.ql

View File

@@ -0,0 +1,8 @@
| test.c:17:10:17:12 | min | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:8:9:8:15 | 2147483647 | Extreme value |
| test.c:48:3:48:5 | sc2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:47:9:47:16 | - ... | Extreme value |
| test.c:50:3:50:5 | sc3 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:49:9:49:16 | 127 | Extreme value |
| test.c:56:3:56:5 | sc5 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:9:54:16 | 127 | Extreme value |
| test.c:59:3:59:5 | sc6 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:58:9:58:16 | 127 | Extreme value |
| test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value |
| test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |
| test.c:76:3:76:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql

View File

@@ -0,0 +1,85 @@
// Semmle test case for rule ArithmeticWithExtremeValues.ql (Use of extreme values in arithmetic expression).
// Associated with CWE-190: Integer Overflow or Wraparound. http://cwe.mitre.org/data/definitions/190.html
#define INT_MAX 2147483647
int len_last(int n, char** lines) {
int min;
min = INT_MAX;
int i;
for (i = 0; i < n; i++) {
int len = strlen(lines[i]);
min = len;
}
// BAD: if the input array is empty, then max will still be INT_MAX
return min + 1;
}
int len_last_good(int n, char** lines) {
int min;
min = INT_MAX;
int i;
for (i = 0; i < n; i++) {
int len = strlen(lines[i]);
min = len;
}
// GOOD: check for INT_MAX
if (min < INT_MAX) {
return min + 1;
} else {
return 0;
}
}
#define CHAR_MIN -128
#define CHAR_MAX 127
void test_crement() {
signed char sc1, sc2, sc3, sc4, sc5, sc6, sc7, sc8, sc9, sc10;
sc1 = CHAR_MIN;
sc1++; // GOOD
sc2 = CHAR_MIN;
sc2--; // BAD
sc3 = CHAR_MAX;
sc3++; // BAD
sc4 = CHAR_MAX;
sc4--; // GOOD
sc5 = CHAR_MAX;
sc5 = 0;
sc5++; // GOOD [FALSE POSITIVE]
sc6 = CHAR_MAX;
sc6 += 1; // BAD
sc7 = CHAR_MAX;
sc7 -= 1; // GOOD
sc8 = CHAR_MIN;
sc8 -= 1; // BAD
sc9 = CHAR_MIN;
sc9 += 1; // GOOD
sc10 = 1;
sc10 += CHAR_MAX; // BAD [NOT DETECTED]
}
void test_negatives() {
signed char sc1, sc2, sc3, sc4, sc5, sc6, sc7, sc8;
sc1 = CHAR_MAX;
sc1 += 0; // GOOD [FALSE POSITIVE]
sc1 += -1; // GOOD [FALSE POSITIVE]
sc2 = CHAR_MIN;
sc2 += -1; // BAD [NOT DETECTED]
sc3 = CHAR_MIN;
sc3 = sc3 + -1; // BAD [NOT DETECTED]
sc4 = CHAR_MAX;
sc4 -= -1; // BAD [NOT DETECTED]
sc5 = -1;
sc5 += CHAR_MIN; // BAD [NOT DETECTED]
}

View File

@@ -0,0 +1 @@
#define SYSTEM_CAST(c) ((int)(unsigned char)(c))

View File

@@ -0,0 +1,10 @@
| test3.c:15:10:15:10 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
| test3.c:15:14:15:14 | y | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
| test3.c:15:18:15:18 | z | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test3.c:11:15:11:18 | argv | User-provided value |
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
| test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
| test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
| test.c:74:7:74:10 | len5 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:71:19:71:22 | argv | User-provided value |
| test.c:84:7:84:10 | len6 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:19:81:22 | argv | User-provided value |
| test.c:94:7:94:10 | len7 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:91:19:91:22 | argv | User-provided value |

Some files were not shown because too many files have changed in this diff Show More