test_libos.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. #!/usr/bin/env python3
  2. import os
  3. import unittest
  4. import subprocess
  5. from regression import (
  6. HAS_SGX,
  7. RegressionTestCase,
  8. )
  9. class TC_00_Unittests(RegressionTestCase):
  10. def test_000_spinlock(self):
  11. stdout, _ = self.run_binary(['spinlock'])
  12. self.assertIn('Test successful!', stdout)
  13. class TC_01_Bootstrap(RegressionTestCase):
  14. def test_100_basic_bootstrapping(self):
  15. stdout, _ = self.run_binary(['bootstrap'])
  16. # Basic Bootstrapping
  17. self.assertIn('User Program Started', stdout)
  18. # One Argument Given
  19. self.assertIn('# of Arguments: 1', stdout)
  20. self.assertIn('argv[0] = bootstrap', stdout)
  21. def test_101_basic_bootstrapping_five_arguments(self):
  22. # Five Arguments Given
  23. stdout, _ = self.run_binary(['bootstrap', 'a', 'b', 'c', 'd'])
  24. self.assertIn('# of Arguments: 5', stdout)
  25. self.assertIn('argv[0] = bootstrap', stdout)
  26. self.assertIn('argv[1] = a', stdout)
  27. self.assertIn('argv[2] = b', stdout)
  28. self.assertIn('argv[3] = c', stdout)
  29. self.assertIn('argv[4] = d', stdout)
  30. @unittest.skipUnless(HAS_SGX,
  31. 'This test is only meaningful on SGX PAL because only SGX catches raw '
  32. 'syscalls and redirects to Graphene\'s LibOS. If we will add seccomp to '
  33. 'Linux PAL, then we should allow this test on Linux PAL as well.')
  34. def test_102_basic_bootstrapping_static(self):
  35. # bootstrap_static
  36. stdout, _ = self.run_binary(['bootstrap_static'])
  37. self.assertIn('Hello world (bootstrap_static)!', stdout)
  38. def test_103_basic_bootstrapping_pie(self):
  39. # bootstrap_pie
  40. stdout, _ = self.run_binary(['bootstrap_pie'])
  41. self.assertIn('User program started', stdout)
  42. self.assertIn('Local Address in Executable: 0x', stdout)
  43. self.assertIn('argv[0] = bootstrap_pie', stdout)
  44. def test_110_basic_bootstrapping_cxx(self):
  45. stdout, _ = self.run_binary(['bootstrap-c++'])
  46. # Basic Bootstrapping (C++)
  47. self.assertIn('User Program Started', stdout)
  48. def test_200_exec(self):
  49. stdout, _ = self.run_binary(['exec'])
  50. # 2 page child binary
  51. self.assertIn(
  52. '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  53. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  54. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  55. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  56. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  57. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  58. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  59. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  60. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  61. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  62. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  63. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  64. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  65. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  66. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
  67. '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ',
  68. stdout)
  69. def test_201_exec_same(self):
  70. stdout, _ = self.run_binary(['exec_same'])
  71. self.assertIn('hello from execv process', stdout)
  72. def test_202_fork_and_exec(self):
  73. stdout, _ = self.run_binary(['fork_and_exec'])
  74. # fork and exec 2 page child binary
  75. self.assertIn('child exited with status: 0', stdout)
  76. self.assertIn('test completed successfully', stdout)
  77. def test_203_vfork_and_exec(self):
  78. stdout, _ = self.run_binary(['vfork_and_exec'])
  79. # vfork and exec 2 page child binary
  80. self.assertIn('child exited with status: 0', stdout)
  81. self.assertIn('test completed successfully', stdout)
  82. def test_210_exec_invalid_args(self):
  83. stdout, _ = self.run_binary(['exec_invalid_args'])
  84. # Execve with invalid pointers in arguments
  85. self.assertIn(
  86. 'execve(invalid-path) correctly returned error', stdout)
  87. self.assertIn(
  88. 'execve(invalid-argv-ptr) correctly returned error', stdout)
  89. self.assertIn(
  90. 'execve(invalid-envp-ptr) correctly returned error', stdout)
  91. self.assertIn(
  92. 'execve(invalid-argv) correctly returned error', stdout)
  93. self.assertIn(
  94. 'execve(invalid-envp) correctly returned error', stdout)
  95. def test_300_shared_object(self):
  96. stdout, _ = self.run_binary(['shared_object'])
  97. # Shared Object
  98. self.assertIn('Hello world', stdout)
  99. def test_400_exit(self):
  100. with self.expect_returncode(113):
  101. self.run_binary(['exit'])
  102. def test_401_exit_group(self):
  103. try:
  104. self.run_binary(['exit_group'])
  105. except subprocess.CalledProcessError as e:
  106. self.assertTrue(1 <= e.returncode and e.returncode <= 4)
  107. def test_402_signalexit(self):
  108. with self.expect_returncode(134):
  109. self.run_binary(['abort'])
  110. def test_403_signalexit_multithread(self):
  111. with self.expect_returncode(134):
  112. self.run_binary(['abort_multithread'])
  113. def test_404_sigprocmask(self):
  114. with self.expect_returncode(113):
  115. self.run_binary(['sigprocmask'])
  116. def test_500_init_fail(self):
  117. try:
  118. self.run_binary(['init_fail'])
  119. self.fail('expected to return nonzero (and != 42)')
  120. except subprocess.CalledProcessError as e:
  121. self.assertNotEqual(e.returncode, 42, 'expected returncode != 42')
  122. def test_600_multi_pthread(self):
  123. stdout, _ = self.run_binary(['multi_pthread'])
  124. # Multiple thread creation
  125. self.assertIn('128 Threads Created', stdout)
  126. @unittest.skipUnless(HAS_SGX,
  127. 'This test is only meaningful on SGX PAL because only SGX catches raw '
  128. 'syscalls and redirects to Graphene\'s LibOS. If we will add seccomp to '
  129. 'Linux PAL, then we should allow this test on Linux PAL as well.')
  130. class TC_02_OpenMP(RegressionTestCase):
  131. def test_000_simple_for_loop(self):
  132. stdout, _ = self.run_binary(['openmp'])
  133. # OpenMP simple for loop
  134. self.assertIn('first: 0, last: 9', stdout)
  135. @unittest.skipUnless(HAS_SGX,
  136. 'This test is only meaningful on SGX PAL because file-check-policy is '
  137. 'only relevant to SGX.')
  138. class TC_03_FileCheckPolicy(RegressionTestCase):
  139. def test_000_strict_success(self):
  140. manifest = self.get_manifest('file_check_policy_strict')
  141. stdout, _ = self.run_binary([manifest, 'trusted_testfile'])
  142. self.assertIn('file_check_policy succeeded', stdout)
  143. def test_001_strict_fail(self):
  144. manifest = self.get_manifest('file_check_policy_strict')
  145. with self.expect_returncode(2):
  146. self.run_binary([manifest, 'unknown_testfile'])
  147. def test_002_allow_all_but_log_success(self):
  148. manifest = self.get_manifest('file_check_policy_allow_all_but_log')
  149. stdout, stderr = self.run_binary([manifest, 'unknown_testfile'])
  150. self.assertIn('Allowing access to an unknown file due to file_check_policy settings: file:unknown_testfile', stderr)
  151. self.assertIn('file_check_policy succeeded', stdout)
  152. def test_003_allow_all_but_log_fail(self):
  153. manifest = self.get_manifest('file_check_policy_allow_all_but_log')
  154. stdout, stderr = self.run_binary([manifest, 'trusted_testfile'])
  155. self.assertNotIn('Allowing access to an unknown file due to file_check_policy settings: file:trusted_testfile', stderr)
  156. self.assertIn('file_check_policy succeeded', stdout)
  157. class TC_30_Syscall(RegressionTestCase):
  158. def test_000_getcwd(self):
  159. stdout, _ = self.run_binary(['getcwd'])
  160. # Getcwd syscall
  161. self.assertIn('[bss_cwd_buf] getcwd succeeded: /', stdout)
  162. self.assertIn('[mmapped_cwd_buf] getcwd succeeded: /', stdout)
  163. def test_010_stat_invalid_args(self):
  164. stdout, _ = self.run_binary(['stat_invalid_args'])
  165. # Stat with invalid arguments
  166. self.assertIn('stat(invalid-path-ptr) correctly returned error', stdout)
  167. self.assertIn('stat(invalid-buf-ptr) correctly returned error', stdout)
  168. self.assertIn('lstat(invalid-path-ptr) correctly returned error', stdout)
  169. self.assertIn('lstat(invalid-buf-ptr) correctly returned error', stdout)
  170. def test_011_fstat_cwd(self):
  171. stdout, _ = self.run_binary(['fstat_cwd'])
  172. # fstat on a directory
  173. self.assertIn('fstat returned the fd type as S_IFDIR', stdout)
  174. def test_020_getdents(self):
  175. # This doesn't catch extraneous entries, but should be fine
  176. # until the LTP test can be run (need symlink support)
  177. stdout, _ = self.run_binary(['getdents'])
  178. self.assertIn('getdents: setup ok', stdout)
  179. # Directory listing (32-bit)
  180. self.assertIn('getdents32: . [0x4]', stdout)
  181. self.assertIn('getdents32: .. [0x4]', stdout)
  182. self.assertIn('getdents32: file1 [0x8]', stdout)
  183. self.assertIn('getdents32: file2 [0x8]', stdout)
  184. self.assertIn('getdents32: dir3 [0x4]', stdout)
  185. # Directory listing (64-bit)
  186. self.assertIn('getdents64: . [0x4]', stdout)
  187. self.assertIn('getdents64: .. [0x4]', stdout)
  188. self.assertIn('getdents64: file1 [0x8]', stdout)
  189. self.assertIn('getdents64: file2 [0x8]', stdout)
  190. self.assertIn('getdents64: dir3 [0x4]', stdout)
  191. def test_021_getdents_large_dir(self):
  192. stdout, _ = self.run_binary(['large_dir_read', 'tmp/large_dir', '3000'])
  193. self.assertIn('Success!', stdout)
  194. def test_022_host_root_fs(self):
  195. stdout, _ = self.run_binary(['host_root_fs'])
  196. self.assertIn('Test was successful', stdout)
  197. def test_030_fopen(self):
  198. if os.path.exists("tmp/filecreatedbygraphene"):
  199. os.remove("tmp/filecreatedbygraphene")
  200. stdout, _ = self.run_binary(['fopen_cornercases'])
  201. # fopen corner cases
  202. self.assertIn('Successfully read from file: Hello World', stdout)
  203. def test_031_readdir(self):
  204. stdout, _ = self.run_binary(['readdir'])
  205. self.assertIn('test completed successfully', stdout)
  206. def test_032_file_size(self):
  207. stdout, _ = self.run_binary(['file_size'])
  208. self.assertIn('test completed successfully', stdout)
  209. def test_040_futex_bitset(self):
  210. stdout, _ = self.run_binary(['futex_bitset'])
  211. # Futex Wake Test
  212. self.assertIn('Woke all kiddos', stdout)
  213. def test_041_futex_timeout(self):
  214. stdout, _ = self.run_binary(['futex_timeout'])
  215. # Futex Timeout Test
  216. self.assertIn('futex correctly timed out', stdout)
  217. def test_042_futex_requeue(self):
  218. stdout, _ = self.run_binary(['futex_requeue'])
  219. self.assertIn('Test successful!', stdout)
  220. def test_043_futex_wake_op(self):
  221. stdout, _ = self.run_binary(['futex_wake_op'])
  222. self.assertIn('Test successful!', stdout)
  223. def test_050_mmap(self):
  224. stdout, _ = self.run_binary(['mmap-file'], timeout=60)
  225. # Private mmap beyond file range
  226. self.assertIn('mmap test 6 passed', stdout)
  227. self.assertIn('mmap test 7 passed', stdout)
  228. # Private mmap beyond file range (after fork)
  229. self.assertIn('mmap test 1 passed', stdout)
  230. self.assertIn('mmap test 2 passed', stdout)
  231. self.assertIn('mmap test 3 passed', stdout)
  232. self.assertIn('mmap test 4 passed', stdout)
  233. @unittest.skipIf(HAS_SGX,
  234. 'On SGX, SIGBUS isn\'t always implemented correctly, for lack '
  235. 'of memory protection. For now, some of these cases won\'t work.')
  236. def test_051_mmap_sgx(self):
  237. stdout, _ = self.run_binary(['mmap-file'], timeout=60)
  238. # SIGBUS test
  239. self.assertIn('mmap test 5 passed', stdout)
  240. self.assertIn('mmap test 8 passed', stdout)
  241. def test_052_large_mmap(self):
  242. stdout, _ = self.run_binary(['large-mmap'], timeout=480)
  243. # Ftruncate
  244. self.assertIn('large-mmap: ftruncate OK', stdout)
  245. # Large mmap
  246. self.assertIn('large-mmap: mmap 1 completed OK', stdout)
  247. self.assertIn('large-mmap: mmap 2 completed OK', stdout)
  248. def test_053_mprotect_file_fork(self):
  249. stdout, _ = self.run_binary(['mprotect_file_fork'])
  250. self.assertIn('Test successful!', stdout)
  251. @unittest.skip('sigaltstack isn\'t correctly implemented')
  252. def test_060_sigaltstack(self):
  253. stdout, _ = self.run_binary(['sigaltstack'])
  254. # Sigaltstack Test
  255. self.assertIn('OK on sigaltstack in main thread before alarm', stdout)
  256. self.assertIn('&act == 0x', stdout)
  257. self.assertIn('sig 14 count 1 goes off with sp=0x', stdout)
  258. self.assertIn('OK on signal stack', stdout)
  259. self.assertIn('OK on sigaltstack in handler', stdout)
  260. self.assertIn('sig 14 count 2 goes off with sp=0x', stdout)
  261. self.assertIn('OK on signal stack', stdout)
  262. self.assertIn('OK on sigaltstack in handler', stdout)
  263. self.assertIn('sig 14 count 3 goes off with sp=0x', stdout)
  264. self.assertIn('OK on signal stack', stdout)
  265. self.assertIn('OK on sigaltstack in handler', stdout)
  266. self.assertIn('OK on sigaltstack in main thread', stdout)
  267. self.assertIn('done exiting', stdout)
  268. def test_070_eventfd(self):
  269. stdout, _ = self.run_binary(['eventfd'])
  270. # Eventfd Test
  271. self.assertIn('eventfd_using_poll completed successfully', stdout)
  272. self.assertIn('eventfd_using_various_flags completed successfully', stdout)
  273. self.assertIn('eventfd_using_fork completed successfully', stdout)
  274. def test_080_sched(self):
  275. stdout, _ = self.run_binary(['sched'])
  276. # Scheduling Syscalls Test
  277. self.assertIn('Test completed successfully', stdout)
  278. @unittest.skipUnless(HAS_SGX,
  279. 'This test is only meaningful on SGX PAL because only SGX catches raw '
  280. 'syscalls and redirects to Graphene\'s LibOS. If we will add seccomp to '
  281. 'Linux PAL, then we should allow this test on Linux PAL as well.')
  282. class TC_31_SyscallSGX(RegressionTestCase):
  283. def test_000_syscall_redirect(self):
  284. stdout, _ = self.run_binary(['syscall'])
  285. # Syscall Instruction Redirection
  286. self.assertIn('Hello world', stdout)
  287. class TC_40_FileSystem(RegressionTestCase):
  288. def test_000_base(self):
  289. stdout, _ = self.run_binary(['proc'])
  290. # Base /proc files present
  291. self.assertIn('/proc/1/..', stdout)
  292. self.assertIn('/proc/1/cwd', stdout)
  293. self.assertIn('/proc/1/exe', stdout)
  294. self.assertIn('/proc/1/root', stdout)
  295. self.assertIn('/proc/1/fd', stdout)
  296. self.assertIn('/proc/1/maps', stdout)
  297. self.assertIn('/proc/.', stdout)
  298. self.assertIn('/proc/1', stdout)
  299. self.assertIn('/proc/self', stdout)
  300. self.assertIn('/proc/meminfo', stdout)
  301. self.assertIn('/proc/cpuinfo', stdout)
  302. def test_010_path(self):
  303. stdout, _ = self.run_binary(['proc-path'])
  304. # Base /proc path present
  305. self.assertIn('proc path test success', stdout)
  306. def test_020_cpuinfo(self):
  307. stdout, _ = self.run_binary(['proc_cpuinfo'], timeout=50)
  308. # proc/cpuinfo Linux-based formatting
  309. self.assertIn('cpuinfo test passed', stdout)
  310. def test_030_fdleak(self):
  311. stdout, _ = self.run_binary(['fdleak'], timeout=10)
  312. self.assertIn("Test succeeded.", stdout)
  313. def test_040_str_close_leak(self):
  314. stdout, _ = self.run_binary(['str_close_leak'], timeout=60)
  315. self.assertIn("Success", stdout)
  316. class TC_80_Socket(RegressionTestCase):
  317. def test_000_getsockopt(self):
  318. stdout, _ = self.run_binary(['getsockopt'])
  319. self.assertIn('getsockopt: Got socket type OK', stdout)
  320. self.assertIn('getsockopt: Got TCP_NODELAY flag OK', stdout)
  321. def test_010_epoll_wait_timeout(self):
  322. stdout, _ = self.run_binary(['epoll_wait_timeout', '8000'],
  323. timeout=50)
  324. # epoll_wait timeout
  325. self.assertIn('epoll_wait test passed', stdout)
  326. def test_020_poll(self):
  327. stdout, _ = self.run_binary(['poll'])
  328. self.assertIn('poll(POLLOUT) returned 1 file descriptors', stdout)
  329. self.assertIn('poll(POLLIN) returned 1 file descriptors', stdout)
  330. def test_021_poll_many_types(self):
  331. stdout, _ = self.run_binary(['poll_many_types'])
  332. self.assertIn('poll(POLLIN) returned 3 file descriptors', stdout)
  333. def test_030_ppoll(self):
  334. stdout, _ = self.run_binary(['ppoll'])
  335. self.assertIn('ppoll(POLLOUT) returned 1 file descriptors', stdout)
  336. self.assertIn('ppoll(POLLIN) returned 1 file descriptors', stdout)
  337. def test_040_select(self):
  338. stdout, _ = self.run_binary(['select'])
  339. self.assertIn('select() on write event returned 1 file descriptors', stdout)
  340. self.assertIn('select() on read event returned 1 file descriptors', stdout)
  341. def test_050_pselect(self):
  342. stdout, _ = self.run_binary(['pselect'])
  343. self.assertIn('pselect() on write event returned 1 file descriptors', stdout)
  344. self.assertIn('pselect() on read event returned 1 file descriptors', stdout)
  345. def test_100_socket_unix(self):
  346. stdout, _ = self.run_binary(['unix'])
  347. self.assertIn('Data: This is packet 0', stdout)
  348. self.assertIn('Data: This is packet 1', stdout)
  349. self.assertIn('Data: This is packet 2', stdout)
  350. self.assertIn('Data: This is packet 3', stdout)
  351. self.assertIn('Data: This is packet 4', stdout)
  352. self.assertIn('Data: This is packet 5', stdout)
  353. self.assertIn('Data: This is packet 6', stdout)
  354. self.assertIn('Data: This is packet 7', stdout)
  355. self.assertIn('Data: This is packet 8', stdout)
  356. self.assertIn('Data: This is packet 9', stdout)
  357. def test_200_socket_udp(self):
  358. stdout, _ = self.run_binary(['udp'], timeout=50)
  359. self.assertIn('Data: This is packet 0', stdout)
  360. self.assertIn('Data: This is packet 1', stdout)
  361. self.assertIn('Data: This is packet 2', stdout)
  362. self.assertIn('Data: This is packet 3', stdout)
  363. self.assertIn('Data: This is packet 4', stdout)
  364. self.assertIn('Data: This is packet 5', stdout)
  365. self.assertIn('Data: This is packet 6', stdout)
  366. self.assertIn('Data: This is packet 7', stdout)
  367. self.assertIn('Data: This is packet 8', stdout)
  368. self.assertIn('Data: This is packet 9', stdout)
  369. def test_300_socket_tcp_msg_peek(self):
  370. stdout, _ = self.run_binary(['tcp_msg_peek'], timeout=50)
  371. self.assertIn('[client] receiving with MSG_PEEK: Hello from server!', stdout)
  372. self.assertIn('[client] receiving without MSG_PEEK: Hello from server!', stdout)
  373. self.assertIn('[client] checking how many bytes are left unread: 0', stdout)
  374. self.assertIn('[client] done', stdout)
  375. self.assertIn('[server] done', stdout)
  376. def test_310_socket_tcp_ipv6_v6only(self):
  377. stdout, _ = self.run_binary(['tcp_ipv6_v6only'], timeout=50)
  378. self.assertIn('test completed successfully', stdout)