Skip to content

Commit 65f4ec4

Browse files
authored
Merge pull request #6593 from geoffw0/samate-move
C++: Add test cases with SAMATE Juliet code snippets to the codeql test suite.
2 parents 3f736d3 + 9ad51fb commit 65f4ec4

File tree

66 files changed

+2251
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2251
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* This test case is closely based on CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp
3+
* from the SAMATE Juliet test suite.
4+
*/
5+
6+
#define NULL (0)
7+
8+
typedef unsigned long size_t;
9+
typedef size_t time_t;
10+
time_t time(time_t *timer);
11+
12+
typedef struct {} FILE;
13+
extern FILE *stdin;
14+
FILE *fopen(const char *filename, const char *mode);
15+
int fclose(FILE *stream);
16+
#define FILENAME_MAX (4096)
17+
18+
typedef unsigned long size_t;
19+
size_t strlen(const char *s);
20+
char *strcat(char *s1, const char *s2);
21+
char *fgets(char *s, int n, FILE *stream);
22+
23+
int globalReturnsTrue()
24+
{
25+
return 1;
26+
}
27+
28+
int globalReturnsFalse()
29+
{
30+
return 0;
31+
}
32+
33+
void printLine(const char *str);
34+
35+
#define BASEPATH "c:\\temp\\"
36+
#define FOPEN fopen
37+
38+
namespace CWE23_Relative_Path_Traversal__char_console_fopen_11
39+
{
40+
41+
void bad()
42+
{
43+
char * data;
44+
char dataBuffer[FILENAME_MAX] = BASEPATH;
45+
data = dataBuffer;
46+
if(globalReturnsTrue())
47+
{
48+
{
49+
/* Read input from the console */
50+
size_t dataLen = strlen(data);
51+
/* if there is room in data, read into it from the console */
52+
if (FILENAME_MAX-dataLen > 1)
53+
{
54+
/* POTENTIAL FLAW: Read data from the console */
55+
if (fgets(data+dataLen, (int)(FILENAME_MAX-dataLen), stdin) != NULL)
56+
{
57+
/* The next few lines remove the carriage return from the string that is
58+
* inserted by fgets() */
59+
dataLen = strlen(data);
60+
if (dataLen > 0 && data[dataLen-1] == '\n')
61+
{
62+
data[dataLen-1] = '\0';
63+
}
64+
}
65+
else
66+
{
67+
printLine("fgets() failed");
68+
/* Restore NUL terminator if fgets fails */
69+
data[dataLen] = '\0';
70+
}
71+
}
72+
}
73+
}
74+
{
75+
FILE *pFile = NULL;
76+
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
77+
pFile = FOPEN(data, "wb+");
78+
if (pFile != NULL)
79+
{
80+
fclose(pFile);
81+
}
82+
}
83+
}
84+
85+
/* goodG2B1() - use goodsource and badsink by changing the globalReturnsTrue() to globalReturnsFalse() */
86+
static void goodG2B1()
87+
{
88+
char * data;
89+
char dataBuffer[FILENAME_MAX] = BASEPATH;
90+
data = dataBuffer;
91+
if(globalReturnsFalse())
92+
{
93+
/* INCIDENTAL: CWE 561 Dead Code, the code below will never run */
94+
printLine("Benign, fixed string");
95+
}
96+
else
97+
{
98+
/* FIX: Use a fixed file name */
99+
strcat(data, "file.txt");
100+
}
101+
{
102+
FILE *pFile = NULL;
103+
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
104+
pFile = FOPEN(data, "wb+");
105+
if (pFile != NULL)
106+
{
107+
fclose(pFile);
108+
}
109+
}
110+
}
111+
112+
/* goodG2B2() - use goodsource and badsink by reversing the blocks in the if statement */
113+
static void goodG2B2()
114+
{
115+
char * data;
116+
char dataBuffer[FILENAME_MAX] = BASEPATH;
117+
data = dataBuffer;
118+
if(globalReturnsTrue())
119+
{
120+
/* FIX: Use a fixed file name */
121+
strcat(data, "file.txt");
122+
}
123+
{
124+
FILE *pFile = NULL;
125+
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
126+
pFile = FOPEN(data, "wb+");
127+
if (pFile != NULL)
128+
{
129+
fclose(pFile);
130+
}
131+
}
132+
}
133+
134+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
edges
2+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... |
3+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data |
4+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection |
5+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... |
6+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data |
7+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection |
8+
nodes
9+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... |
10+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument |
11+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
12+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
13+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
14+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
15+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
16+
#select
17+
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename) | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-022/TaintedPath.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| tests.cpp:53:16:53:19 | data | This argument to an OS command is derived from $@ and then passed to system(string) | tests.cpp:33:34:33:39 | call to getenv | user input (getenv) |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-078/ExecTainted.ql
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//semmle-extractor-options: --edg --target --edg win64
2+
3+
// A selection of tests from the SAMATE Juliet framework for rule CWE-78.
4+
5+
// library types, functions etc
6+
#define NULL (0)
7+
typedef unsigned long size_t;
8+
size_t strlen(const char *s);
9+
char *strncat(char *s1, const char *s2, size_t n);
10+
char *getenv(const char *name);
11+
int system(const char *string);
12+
void exit(int status);
13+
14+
#define FULL_COMMAND "dir "
15+
#define ENV_VARIABLE "ADD"
16+
#define GETENV getenv
17+
#define SYSTEM system
18+
19+
void printLine(const char *str);
20+
21+
// ----------
22+
23+
/* The static variable below is used to drive control flow in the source function */
24+
static int badStatic = 0;
25+
26+
static char * badSource(char * data)
27+
{
28+
if(badStatic)
29+
{
30+
{
31+
/* Append input from an environment variable to data */
32+
size_t dataLen = strlen(data);
33+
char * environment = GETENV(ENV_VARIABLE);
34+
/* If there is data in the environment variable */
35+
if (environment != NULL)
36+
{
37+
/* POTENTIAL FLAW: Read data from an environment variable */
38+
strncat(data+dataLen, environment, 100-dataLen-1);
39+
}
40+
}
41+
}
42+
return data;
43+
}
44+
45+
void CWE78_OS_Command_Injection__char_environment_system_21_bad()
46+
{
47+
char * data;
48+
char data_buf[100] = FULL_COMMAND;
49+
data = data_buf;
50+
badStatic = 1; /* true */
51+
data = badSource(data);
52+
/* POTENTIAL FLAW: Execute command in data possibly leading to command injection [NOT DETECTED] */
53+
if (SYSTEM(data) != 0)
54+
{
55+
printLine("command execution failed!");
56+
exit(1);
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
edges
2+
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | (LPCSTR)... |
3+
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data |
4+
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data indirection |
5+
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | (LPCSTR)... |
6+
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
7+
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
8+
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data indirection |
9+
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
10+
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
11+
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
12+
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
13+
| test.cpp:73:17:73:22 | data | test.cpp:37:73:37:76 | data |
14+
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | *data |
15+
nodes
16+
| test.cpp:37:73:37:76 | *data | semmle.label | *data |
17+
| test.cpp:37:73:37:76 | data | semmle.label | data |
18+
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
19+
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
20+
| test.cpp:43:32:43:35 | data | semmle.label | data |
21+
| test.cpp:43:32:43:35 | data | semmle.label | data |
22+
| test.cpp:43:32:43:35 | data | semmle.label | data |
23+
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
24+
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
25+
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
26+
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
27+
| test.cpp:73:17:73:22 | data | semmle.label | data |
28+
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
29+
#select
30+
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA | test.cpp:64:30:64:35 | call to getenv | call to getenv |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-114/UncontrolledProcessOperation.ql
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Some SAMATE Juliet test cases for CWE-114.
2+
3+
typedef unsigned long size_t;
4+
typedef unsigned int BOOL;
5+
typedef const char *LPCSTR;
6+
typedef void *HMODULE;
7+
#define NULL (0)
8+
9+
size_t strlen(const char *s);
10+
char *strncat(char *s1, const char *s2, size_t n);
11+
12+
HMODULE LoadLibraryA(LPCSTR libname);
13+
BOOL FreeLibrary(HMODULE hModule);
14+
15+
char *getenv(const char *name);
16+
17+
#define GETENV getenv
18+
#define ENV_VARIABLE "ADD"
19+
20+
void printLine(const char *msg);
21+
22+
// --- CWE114_Process_Control__w32_char_environment_82 ---
23+
24+
class CWE114_Process_Control__w32_char_environment_82_base
25+
{
26+
public:
27+
/* pure virtual function */
28+
virtual void action(char * data) = 0;
29+
};
30+
31+
class CWE114_Process_Control__w32_char_environment_82_bad : public CWE114_Process_Control__w32_char_environment_82_base
32+
{
33+
public:
34+
void action(char * data);
35+
};
36+
37+
void CWE114_Process_Control__w32_char_environment_82_bad::action(char * data)
38+
{
39+
{
40+
HMODULE hModule;
41+
/* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to
42+
* replace his own file with the intended library */
43+
hModule = LoadLibraryA(data);
44+
if (hModule != NULL)
45+
{
46+
FreeLibrary(hModule);
47+
printLine("Library loaded and freed successfully");
48+
}
49+
else
50+
{
51+
printLine("Unable to load library");
52+
}
53+
}
54+
}
55+
56+
void bad()
57+
{
58+
char * data;
59+
char dataBuffer[100] = "";
60+
data = dataBuffer;
61+
{
62+
/* Append input from an environment variable to data */
63+
size_t dataLen = strlen(data);
64+
char * environment = GETENV(ENV_VARIABLE);
65+
/* If there is data in the environment variable */
66+
if (environment != NULL)
67+
{
68+
/* POTENTIAL FLAW: Read data from an environment variable */
69+
strncat(data+dataLen, environment, 100-dataLen-1);
70+
}
71+
}
72+
CWE114_Process_Control__w32_char_environment_82_base* baseObject = new CWE114_Process_Control__w32_char_environment_82_bad;
73+
baseObject->action(data);
74+
delete baseObject;
75+
}
76+
77+
// --- CWE114_Process_Control__w32_char_console_33 ---
78+
79+
typedef struct {} FILE;
80+
char *fgets(char *s, int n, FILE *stream);
81+
FILE *stdin;
82+
83+
void CWE114_Process_Control__w32_char_console_33_bad()
84+
{
85+
char * data;
86+
char * &dataRef = data;
87+
char dataBuffer[100] = "";
88+
data = dataBuffer;
89+
{
90+
/* Read input from the console */
91+
size_t dataLen = strlen(data);
92+
/* if there is room in data, read into it from the console */
93+
if (100-dataLen > 1)
94+
{
95+
/* POTENTIAL FLAW: Read data from the console [NOT DETECTED] */
96+
if (fgets(data+dataLen, (int)(100-dataLen), stdin) != NULL)
97+
{
98+
/* The next few lines remove the carriage return from the string that is
99+
* inserted by fgets() */
100+
dataLen = strlen(data);
101+
if (dataLen > 0 && data[dataLen-1] == '\n')
102+
{
103+
data[dataLen-1] = '\0';
104+
}
105+
}
106+
else
107+
{
108+
printLine("fgets() failed");
109+
/* Restore NUL terminator if fgets fails */
110+
data[dataLen] = '\0';
111+
}
112+
}
113+
}
114+
{
115+
char * data = dataRef;
116+
{
117+
HMODULE hModule;
118+
/* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to
119+
* replace his own file with the intended library */
120+
hModule = LoadLibraryA(data);
121+
if (hModule != NULL)
122+
{
123+
FreeLibrary(hModule);
124+
printLine("Library loaded and freed successfully");
125+
}
126+
else
127+
{
128+
printLine("Unable to load library");
129+
}
130+
}
131+
}
132+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| tests.cpp:350:13:350:19 | call to strncat | This 'call to strncat' operation is limited to 100 bytes but the destination is only 50 bytes. |
2+
| tests.cpp:452:9:452:15 | call to wcsncpy | This 'call to wcsncpy' operation is limited to 396 bytes but the destination is only 200 bytes. |
3+
| tests.cpp:481:9:481:16 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. |
4+
| tests.cpp:630:13:630:20 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. |

0 commit comments

Comments
 (0)