Skip to content

Commit a51d24c

Browse files
committed
apply suggestions from code review, and the examples to the test
1 parent 3989717 commit a51d24c

File tree

5 files changed

+37
-21
lines changed

5 files changed

+37
-21
lines changed

cpp/ql/src/Security/CWE/CWE-022/examples/TaintedPath.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ int main(int argc, char** argv) {
22
char *userAndFile = argv[2];
33

44
{
5-
char fileBuffer[FILENAME_MAX] = "/home/";
6-
char *fileName = fileBuffer;
7-
size_t len = strlen(fileName);
8-
strncat(fileName+len, userAndFile, FILENAME_MAX-len-1);
5+
char fileBuffer[PATH_MAX];
6+
snprintf(fileBuffer, sizeof(fileBuffer), "/home/%s", userAndFile);
97
// BAD: a string from the user is used in a filename
10-
fopen(fileName, "wb+");
8+
fopen(fileBuffer, "wb+");
119
}
1210
}

cpp/ql/src/Security/CWE/CWE-022/examples/TaintedPathFolder.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
int main(int argc, char** argv) {
55
char *userAndFile = argv[2];
6-
char baseDir[PATH_MAX] = "/home/user/public/";
6+
const char *baseDir = "/home/user/public/";
77
char fullPath[PATH_MAX];
88

99
// Attempt to concatenate the base directory and the user-supplied path

cpp/ql/src/Security/CWE/CWE-022/examples/TaintedPathNormalize.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
#include <string.h>
33

44
int main(int argc, char** argv) {
5-
6-
char *userAndFile = argv[2];
5+
char *fileName = argv[2];
76
// Check for invalid sequences in the user input
8-
if (strstr(userAndFile, "..") || strchr(userAndFile, '/') || strchr(userAndFile, '\\')) {
7+
if (strstr(fileName , "..") || strchr(fileName , '/') || strchr(fileName , '\\')) {
98
printf("Invalid filename.\n");
109
return 1;
1110
}
1211

13-
// use `userAndFile` as a safe filename
12+
char fileBuffer[PATH_MAX];
13+
snprintf(fileBuffer, sizeof(fileBuffer), "/home/user/files/%s", fileName);
14+
// GOOD: We know that the filename is safe and stays within the public folder
15+
FILE *file = fopen(fileBuffer, "wb+");
1416
}

cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ edges
33
| test.c:8:27:8:30 | **argv | test.c:31:22:31:28 | *access to array | provenance | |
44
| test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | provenance | |
55
| test.c:8:27:8:30 | **argv | test.c:80:25:80:31 | *access to array | provenance | |
6+
| test.c:8:27:8:30 | **argv | test.c:88:22:88:28 | *access to array | provenance | |
67
| test.c:9:23:9:29 | *access to array | test.c:17:11:17:18 | *fileName | provenance | TaintFunction |
78
| test.c:31:22:31:28 | *access to array | test.c:32:11:32:18 | *fileName | provenance | |
89
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | provenance | |
@@ -12,7 +13,8 @@ edges
1213
| test.c:54:21:54:26 | *call to getenv | test.c:55:11:55:16 | *buffer | provenance | TaintFunction |
1314
| test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
1415
| test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
15-
| test.c:80:25:80:31 | *access to array | test.c:91:24:91:33 | *fileBuffer | provenance | TaintFunction |
16+
| test.c:80:25:80:31 | *access to array | test.c:84:11:84:20 | *fileBuffer | provenance | TaintFunction |
17+
| test.c:88:22:88:28 | *access to array | test.c:98:24:98:33 | *fileBuffer | provenance | TaintFunction |
1618
nodes
1719
| test.c:8:27:8:30 | **argv | semmle.label | **argv |
1820
| test.c:9:23:9:29 | *access to array | semmle.label | *access to array |
@@ -33,7 +35,9 @@ nodes
3335
| test.c:75:13:75:18 | read output argument | semmle.label | read output argument |
3436
| test.c:76:11:76:16 | *buffer | semmle.label | *buffer |
3537
| test.c:80:25:80:31 | *access to array | semmle.label | *access to array |
36-
| test.c:91:24:91:33 | *fileBuffer | semmle.label | *fileBuffer |
38+
| test.c:84:11:84:20 | *fileBuffer | semmle.label | *fileBuffer |
39+
| test.c:88:22:88:28 | *access to array | semmle.label | *access to array |
40+
| test.c:98:24:98:33 | *fileBuffer | semmle.label | *fileBuffer |
3741
subpaths
3842
#select
3943
| test.c:17:11:17:18 | fileName | test.c:8:27:8:30 | **argv | 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:8:27:8:30 | **argv | user input (a command-line argument) |
@@ -45,4 +49,5 @@ subpaths
4549
| test.c:69:14:69:20 | access to array | test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | This argument to a file access function is derived from $@ and then passed to readFile(fileName), which calls fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
4650
| test.c:76:11:76:16 | buffer | test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:74:13:74:18 | read output argument | user input (buffer read by read) |
4751
| test.c:76:11:76:16 | buffer | test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:75:13:75:18 | read output argument | user input (buffer read by read) |
48-
| test.c:91:24:91:33 | fileBuffer | test.c:8:27:8:30 | **argv | test.c:91:24:91:33 | *fileBuffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
52+
| test.c:84:11:84:20 | fileBuffer | test.c:8:27:8:30 | **argv | test.c:84:11:84:20 | *fileBuffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
53+
| test.c:98:24:98:33 | fileBuffer | test.c:8:27:8:30 | **argv | test.c:98:24:98:33 | *fileBuffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |

cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/test.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,40 +78,51 @@ int main(int argc, char** argv) {
7878

7979
{
8080
char *userAndFile = argv[2];
81+
char fileBuffer[PATH_MAX];
82+
snprintf(fileBuffer, sizeof(fileBuffer), "/home/%s", userAndFile);
83+
// BAD: a string from the user is used in a filename
84+
fopen(fileBuffer, "wb+");
85+
}
86+
87+
{
88+
char *fileName = argv[2];
8189
// Check for invalid sequences in the user input
82-
if (strstr(userAndFile, "..") || strchr(userAndFile, '/') || strchr(userAndFile, '\\')) {
83-
// printf("Invalid filename.\n");
90+
if (strstr(fileName , "..") || strchr(fileName , '/') || strchr(fileName , '\\')) {
91+
printf("Invalid filename.\n");
8492
return 1;
8593
}
8694

87-
char fileBuffer[FILENAME_MAX] = "/home/user/files/";
88-
// Ensure buffer overflow is prevented
89-
strncat(fileBuffer, userAndFile, FILENAME_MAX - strlen(fileBuffer) - 1);
95+
char fileBuffer[PATH_MAX];
96+
snprintf(fileBuffer, sizeof(fileBuffer), "/home/user/files/%s", fileName);
9097
// GOOD: We know that the filename is safe and stays within the public folder. But we currently get an FP here.
9198
FILE *file = fopen(fileBuffer, "wb+");
9299
}
93100

94101
{
95102
char *userAndFile = argv[2];
96-
char baseDir[PATH_MAX] = "/home/user/public/";
103+
const char *baseDir = "/home/user/public/";
97104
char fullPath[PATH_MAX];
98-
char resolvedPath[PATH_MAX];
99105

100106
// Attempt to concatenate the base directory and the user-supplied path
101107
snprintf(fullPath, sizeof(fullPath), "%s%s", baseDir, userAndFile);
102108

103109
// Resolve the absolute path, normalizing any ".." or "."
104-
if (realpath(fullPath, resolvedPath) == 0) {
110+
char *resolvedPath = realpath(fullPath, 0); // <- we're using `NULL` in the example, but 0 here to get it to compile. Same for next line.
111+
if (resolvedPath == 0) {
112+
perror("Error resolving path");
105113
return 1;
106114
}
107115

108116
// Check if the resolved path starts with the base directory
109117
if (strncmp(baseDir, resolvedPath, strlen(baseDir)) != 0) {
118+
free(resolvedPath);
110119
return 1;
111120
}
112121

113122
// GOOD: Path is within the intended directory
114123
FILE *file = fopen(resolvedPath, "wb+");
124+
free(resolvedPath);
125+
115126
}
116127
}
117128

0 commit comments

Comments
 (0)