Skip to content

Commit 2479b91

Browse files
committed
Flesh out tests, clean up
1 parent e208a34 commit 2479b91

File tree

4 files changed

+67
-19
lines changed

4 files changed

+67
-19
lines changed

qiling/os/posix/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,3 +1083,4 @@ class qnx_mmap_prot_flags(QlPrettyFlag):
10831083
EPOLLWAKEUP = 1 << 29
10841084
EPOLLONESHOT = 1 << 30
10851085
EPOLLET = 1 << 31
1086+
EPOLL_CLOEXEC = 0x02000000

qiling/os/posix/syscall/epoll.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
import qiling
2+
from qiling.const import *
3+
from qiling.os.posix.const import *
4+
from qiling.os.const import *
5+
from qiling.os.filestruct import ql_file
6+
import select
7+
from ctypes import *
8+
from qiling.os import struct
9+
import struct
10+
from qiling.os.filestruct import PersistentQlFile
11+
from qiling.extensions import pipe
12+
import sys
13+
114
class QlEpollObj:
215
def __init__(self, epoll_object):
316
self._epoll_object = epoll_object
@@ -43,9 +56,14 @@ def is_present(self, fd):
4356
return 0
4457
return 1
4558

46-
59+
'''
60+
Recursively checks each epoll instance's 'watched'
61+
fds for an instance of epoll being watched.
62+
If a chain of over 5 levels is detected, return
63+
1, which will return ELOOP in ql_epoll_wait
64+
'''
4765
def check_epoll_depth(ql_fd_list, epolls_list, depth):
48-
if depth == 6:
66+
if depth == 7:
4967
return 1
5068
new_epolls_list = []
5169
flag = 0
@@ -59,7 +77,10 @@ def check_epoll_depth(ql_fd_list, epolls_list, depth):
5977
check_epoll_depth(ql_fd_list, new_epolls_list, depth + 1)
6078
return 0
6179

62-
80+
'''
81+
Modify an existing epoll
82+
man 7 epoll for more details
83+
'''
6384
def ql_epoll_ctl(ql: qiling.Qiling, epfd: int, op: int, fd: int, event: POINTER):
6485
# Basic sanity checks first
6586
if event != 0:
@@ -152,6 +173,10 @@ def ql_epoll_ctl(ql: qiling.Qiling, epfd: int, op: int, fd: int, event: POINTER)
152173
return 0
153174

154175

176+
'''
177+
Wait on an existing epoll for events specified
178+
earlier. man 7 epoll_wait for more info
179+
'''
155180
def ql_epoll_wait(
156181
ql: qiling.Qiling, epfd: int, epoll_events: POINTER, maxevents: int, timeout: int
157182
):
@@ -203,8 +228,6 @@ def ql_epoll_wait(
203228
Use select.epoll for underlying implementation,
204229
just as select.poll is used for emulating poll()
205230
"""
206-
207-
208231
def ql_epoll_create1(ql: qiling.Qiling, flags: int):
209232
if flags != select.EPOLL_CLOEXEC and flags != 0:
210233
return EINVAL
@@ -217,16 +240,13 @@ def ql_epoll_create1(ql: qiling.Qiling, flags: int):
217240

218241
"""
219242
Almost identical to above, but can't simply wrap
220-
because of the slightly different args and the different
221-
syscall number
243+
because of the slightly different prototype
222244
"""
223-
224-
225245
def ql_epoll_create(ql: qiling.Qiling, size: int):
226246
if size < 0:
227247
return EINVAL
228248
ret = select.epoll(sizehint=size, flags=0)
229249
fd = ret.fileno()
230250
ql_obj = QlEpollObj(ret)
231251
ql.os.fd[fd] = ql_obj
232-
return fd
252+
return fd

tests/test_elf.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
import os
1010
import io
1111
import re
12-
12+
import socket
1313
import sys
14+
import time
1415
sys.path.append("..")
1516

1617
from typing import Any, Sequence
@@ -771,17 +772,45 @@ def test_elf_linux_x8664_path_traversion(self):
771772
del ql
772773

773774
def test_elf_linux_x8664_epoll_simple(self):
774-
# TODO: Get the example in rootfs
775+
# TODO: Get the example in rootfs, see https://github.com/qilingframework/rootfs/pull/35
776+
# epoll-0 source: https://github.com/maxasm/epoll-c/blob/main/main.c
775777
rootfs = "../examples/rootfs/x8664_linux"
776-
argv = r"../examples/rootfs/x8664_linux/epoll-0".split()
778+
argv = r"../examples/rootfs/x8664_linux/bin/epoll-0".split()
777779
ql = qiling.Qiling(argv, rootfs, verbose=QL_VERBOSE.DEBUG)
778-
ql.os.stdin = pipe.SimpleInStream(0)
779-
ql.os.stdin.write(b"stop\n")
780+
ql.os.stdin = pipe.InteractiveInStream(0)
781+
ql.os.stdin.write(b'echo\n')
782+
ql.os.stdin.write(b"stop\n") # signal to exit gracefully
780783
ql.run()
784+
self.assertIn("echo", ql.os.stdout.read().decode("utf-8"))
781785
del ql
782-
783786
def test_elf_linux_x8664_epoll_server(self):
784-
pass
787+
# TODO: https://github.com/qilingframework/rootfs/pull/35 must be merged
788+
# Source for onestraw server: https://github.com/onestraw/epoll-example
789+
# with a slight change to exit after the first request
790+
def client():
791+
time.sleep(3) # give time for the server to listen
792+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
793+
dest = ("127.0.0.1", 8000)
794+
try:
795+
s.connect(dest)
796+
except Exception as e:
797+
ql.log.debug('test failed')
798+
ql.log.debug(e)
799+
800+
test = b"hello world"
801+
s.send(test)
802+
s.close()
803+
# use threads here to test how the server
804+
# handles the request
805+
client_thread = threading.Thread(target=client, daemon=True)
806+
client_thread.start()
807+
rootfs = "../examples/rootfs/"
808+
argv = r"../examples/rootfs/x8664_linux/bin/onestraw-server s".split() # s means 'server mode'
809+
ql = qiling.Qiling(argv, rootfs, multithread=False, verbose=QL_VERBOSE.DEBUG)
810+
ql.os.stdout = pipe.SimpleOutStream(1) # server prints data received to stdout
811+
ql.filter = '^data:'
812+
ql.run()
813+
self.assertIn('hello world', ql.os.stdout.read().decode("utf-8"))
785814
del ql
786815
if __name__ == "__main__":
787816
unittest.main()

tests/test_elf_multithread.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import http.client
77
import platform
88
import re
9-
import socket
109
import sys
1110
import os
1211
import threading
@@ -636,6 +635,5 @@ def picohttpd():
636635
feedback = response.read()
637636
self.assertEqual('httpd_test_successful', feedback.decode())
638637

639-
640638
if __name__ == "__main__":
641639
unittest.main()

0 commit comments

Comments
 (0)