Skip to content

CPP: Add the Semmle security tests. #552

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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) |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Security/CWE/CWE-022/TaintedPath.ql
13 changes: 13 additions & 0 deletions cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/stdlib.h
Original file line number Diff line number Diff line change
@@ -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);
30 changes: 30 additions & 0 deletions cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/test.c
Original file line number Diff line number Diff line change
@@ -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+");
}
}

Original file line number Diff line number Diff line change
@@ -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) |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Security/CWE/CWE-078/ExecTainted.ql
Original file line number Diff line number Diff line change
@@ -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);
}
}

Original file line number Diff line number Diff line change
@@ -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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Security/CWE/CWE-079/CgiXss.ql
Original file line number Diff line number Diff line change
@@ -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);
}
}

Original file line number Diff line number Diff line change
@@ -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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Security/CWE/CWE-114/UncontrolledProcessOperation.ql
Original file line number Diff line number Diff line change
@@ -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"));
}
Original file line number Diff line number Diff line change
@@ -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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Critical/OverflowStatic.ql
Original file line number Diff line number Diff line change
@@ -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
}

Original file line number Diff line number Diff line change
@@ -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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql

Original file line number Diff line number Diff line change
@@ -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));
}

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| test.c:24:2:24:8 | call to strncat | Potentially unsafe call to strncat. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
Original file line number Diff line number Diff line change
@@ -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
}

Original file line number Diff line number Diff line change
@@ -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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Security/CWE/CWE-120/BadlyBoundedWrite.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
Loading