Skip to content

Commit 132e96f

Browse files
authored
Merge pull request #1076 from wtdcode/fix-path-traverse
Add fix and example for openat path traversion
2 parents 4afc306 + 8b951b2 commit 132e96f

File tree

6 files changed

+38
-11
lines changed

6 files changed

+38
-11
lines changed

examples/rootfs

examples/src/linux/path_traverse.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// gcc -static ~/qiling/examples/src/linux/path_traverse.c -g -O0 -o ~/qiling/examples/rootfs/x8664_linux/bin/path_traverse_static
2+
// https://www.kalmarunionen.dk/writeups/2022/rwctf/qlaas/
3+
#include <fcntl.h>
4+
#include <unistd.h>
5+
6+
int main(){
7+
char buf[4096];
8+
int fd = openat(1, "/etc/passwd", O_RDONLY);
9+
ssize_t len = read(fd, buf, sizeof(buf));
10+
write(1, buf, len);
11+
12+
fd = openat(1, "/etc/passwd_link", O_RDONLY);
13+
len = read(fd, buf, sizeof(buf));
14+
write(1, buf, len);
15+
}

qiling/os/mapper.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,11 @@ def has_mapping(self, fm):
9595
def mapping_count(self):
9696
return len(self._mapping)
9797

98-
def open_ql_file(self, path, openflags, openmode, dir_fd=None):
98+
def open_ql_file(self, path, openflags, openmode):
9999
if self.has_mapping(path):
100100
self.ql.log.info(f"mapping {path}")
101101
return self._open_mapping_ql_file(path, openflags, openmode)
102102
else:
103-
if dir_fd:
104-
return ql_file.open(path, openflags, openmode, dir_fd=dir_fd)
105-
106103
real_path = self.ql.os.path.transform_to_real_path(path)
107104
return ql_file.open(real_path, openflags, openmode)
108105

qiling/os/path.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,16 @@ def transform_to_link_path(self, path: str) -> str:
128128
return str(real_path.absolute())
129129

130130
def transform_to_real_path(self, path: str) -> str:
131+
# TODO: We really need a virtual file system.
131132
real_path = self.convert_path(self.ql.rootfs, self.cwd, path)
132133

133134
if os.path.islink(real_path):
134135
link_path = Path(os.readlink(real_path))
135136

136-
if not link_path.is_absolute():
137-
real_path = Path(os.path.join(os.path.dirname(real_path), link_path))
137+
real_path = self.convert_path(os.path.dirname(real_path), "/", link_path)
138+
139+
if os.path.islink(real_path):
140+
real_path = self.transform_to_real_path(real_path)
138141

139142
# resolve multilevel symbolic link
140143
if not os.path.exists(real_path):

qiling/os/posix/syscall/fcntl.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#
55

66
import os
7+
from pathlib import Path
78

89
from qiling import Qiling
910
from qiling.const import QL_OS, QL_ARCH
@@ -101,11 +102,13 @@ def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int):
101102
fd = ql.unpacks(ql.pack(fd))
102103

103104
if 0 <= fd < NR_OPEN:
104-
dir_fd = ql.os.fd[fd].fileno()
105-
else:
106-
dir_fd = None
105+
fobj = ql.os.fd[fd]
106+
# ql_file object or QlFsMappedObject
107+
if hasattr(fobj, "fileno") and hasattr(fobj, "name"):
108+
if not Path.is_absolute(Path(file_path)):
109+
file_path = Path(fobj.name) / Path(file_path)
107110

108-
ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(file_path, flags, mode, dir_fd)
111+
ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(file_path, flags, mode)
109112

110113
regreturn = idx
111114
except QlSyscallError as e:

tests/test_elf.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,15 @@ def test_memory_search(self):
10911091
self.assertEqual([0x1000 + 11, 0x2000 + 11, 0x3000 + 43], ql.mem.search(b"\x09\x53(\x0f|\x1a|\x04)[^\x0d]"))
10921092

10931093
del ql
1094+
1095+
def test_elf_linux_x8664_path_traversion(self):
1096+
mock_stdout = pipe.SimpleOutStream(sys.stdout.fileno())
1097+
ql = Qiling(["../examples/rootfs/x8664_linux/bin/path_traverse_static"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG, stdout=mock_stdout)
1098+
1099+
ql.run()
1100+
self.assertTrue("root\n" not in ql.os.stdout.read().decode("utf-8"))
1101+
1102+
del ql
10941103

10951104
if __name__ == "__main__":
10961105
unittest.main()

0 commit comments

Comments
 (0)