Skip to content

Commit e9b1146

Browse files
authored
Merge pull request #6948 from ihsinme/ihsinme-patch-076
CPP: Add query for CWE-243 Creation of chroot Jail Without Changing Working Directory
2 parents d00196f + aef0275 commit e9b1146

File tree

6 files changed

+165
-0
lines changed

6 files changed

+165
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
...
2+
chroot("/myFold/myTmp"); // BAD
3+
...
4+
chdir("/myFold/myTmp"); // BAD
5+
...
6+
int fd = open("/myFold/myTmp", O_RDONLY | O_DIRECTORY);
7+
fchdir(fd); // BAD
8+
...
9+
if (chdir("/myFold/myTmp") == -1) {
10+
exit(-1);
11+
}
12+
if (chroot("/myFold/myTmp") == -1) { // GOOD
13+
exit(-1);
14+
}
15+
...
16+
if (chdir("/myFold/myTmp") == -1) { // GOOD
17+
exit(-1);
18+
}
19+
...
20+
int fd = open("/myFold/myTmp", O_RDONLY | O_DIRECTORY);
21+
if(fchdir(fd) == -1) { // GOOD
22+
exit(-1);
23+
}
24+
...
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Working with changing directories, without checking the return value or pinning the directory, may not be safe. Requires the attention of developers.</p>
7+
8+
</overview>
9+
10+
<example>
11+
<p>The following example demonstrates erroneous and corrected work with changing working directories.</p>
12+
<sample src="IncorrectChangingWorkingDirectory.cpp" />
13+
14+
</example>
15+
<references>
16+
17+
<li>
18+
CERT C Coding Standard:
19+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail">POS05-C. Limit access to files by creating a jail.</a>
20+
</li>
21+
22+
</references>
23+
</qhelp>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @name Find work with changing working directories, with security errors.
3+
* @description Not validating the return value or pinning the directory can be unsafe.
4+
* @kind problem
5+
* @id cpp/work-with-changing-working-directories
6+
* @problem.severity warning
7+
* @precision medium
8+
* @tags correctness
9+
* security
10+
* external/cwe/cwe-243
11+
* external/cwe/cwe-252
12+
*/
13+
14+
import cpp
15+
import semmle.code.cpp.commons.Exclusions
16+
17+
/** Holds if a `fc` function call is available before or after a `chdir` function call. */
18+
predicate inExistsChdir(FunctionCall fcp) {
19+
exists(FunctionCall fctmp |
20+
(
21+
fctmp.getTarget().hasGlobalOrStdName("chdir") or
22+
fctmp.getTarget().hasGlobalOrStdName("fchdir")
23+
) and
24+
(
25+
fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
26+
fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock()
27+
)
28+
)
29+
}
30+
31+
/** Holds if a `fc` function call is available before or after a function call containing a `chdir` call. */
32+
predicate outExistsChdir(FunctionCall fcp) {
33+
exists(FunctionCall fctmp |
34+
exists(FunctionCall fctmp2 |
35+
(
36+
fctmp2.getTarget().hasGlobalOrStdName("chdir") or
37+
fctmp2.getTarget().hasGlobalOrStdName("fchdir")
38+
) and
39+
// we are looking for a call containing calls chdir and fchdir
40+
fctmp2.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*()
41+
) and
42+
(
43+
fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
44+
fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock()
45+
)
46+
)
47+
}
48+
49+
from FunctionCall fc, string msg
50+
where
51+
fc.getTarget().hasGlobalOrStdName("chroot") and
52+
not inExistsChdir(fc) and
53+
not outExistsChdir(fc) and
54+
// in this section I want to exclude calls to functions containing chroot that have a direct path to chdir, or to a function containing chdir
55+
exists(FunctionCall fctmp |
56+
fc.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*() and
57+
not inExistsChdir(fctmp) and
58+
not outExistsChdir(fctmp)
59+
) and
60+
msg = "Creation of 'chroot' jail without changing the working directory"
61+
or
62+
(
63+
fc.getTarget().hasGlobalOrStdName("chdir") or
64+
fc.getTarget().hasGlobalOrStdName("fchdir")
65+
) and
66+
fc instanceof ExprInVoidContext and
67+
not isFromMacroDefinition(fc) and
68+
msg = "Unchecked return value for call to '" + fc.getTarget().getName() + "'."
69+
select fc, msg
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.cpp:12:7:12:12 | call to chroot | Creation of 'chroot' jail without changing the working directory |
2+
| test.cpp:29:3:29:7 | call to chdir | Unchecked return value for call to 'chdir'. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
typedef int FILE;
2+
#define size_t int
3+
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
4+
FILE *fopen(const char *filename, const char *mode);
5+
int fread(char *buf, int size, int count, FILE *fp);
6+
int fclose(FILE *fp);
7+
int chroot(char *path);
8+
int chdir(char *path);
9+
void exit(int status);
10+
11+
int funTest1(){
12+
if (chroot("/myFold/myTmp") == -1) { // BAD
13+
exit(-1);
14+
}
15+
return 0;
16+
}
17+
18+
int funTest2(){
19+
if (chdir("/myFold/myTmp") == -1) { // GOOD
20+
exit(-1);
21+
}
22+
if (chroot("/myFold/myTmp") == -1) { // GOOD
23+
exit(-1);
24+
}
25+
return 0;
26+
}
27+
28+
int funTest3(){
29+
chdir("/myFold/myTmp"); // BAD
30+
return 0;
31+
}
32+
int main(int argc, char *argv[])
33+
{
34+
if(argc = 0) {
35+
funTest3();
36+
return 2;
37+
}
38+
if(argc = 1)
39+
funTest1();
40+
else
41+
funTest2();
42+
FILE *fp = fopen(argv[1], "w");
43+
fwrite("12345", 5, 1, fp);
44+
fclose(fp);
45+
return 0;
46+
}

0 commit comments

Comments
 (0)