PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/sandbox/test/test_sandlib.py

https://bitbucket.org/pypy/pypy/
Python | 267 lines | 255 code | 11 blank | 1 comment | 3 complexity | f440bfd8a2018060ca93e643e7f5bbfd MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import errno, os, StringIO
  3. from rpython.tool.sourcetools import func_with_new_name
  4. from rpython.rtyper.lltypesystem import rffi
  5. from rpython.translator.sandbox.sandlib import SandboxedProc
  6. from rpython.translator.sandbox.sandlib import SimpleIOSandboxedProc
  7. from rpython.translator.sandbox.sandlib import VirtualizedSandboxedProc
  8. from rpython.translator.sandbox.sandlib import VirtualizedSocketProc
  9. from rpython.translator.sandbox.test.test_sandbox import compile
  10. from rpython.translator.sandbox.vfs import Dir, File, RealDir, RealFile
  11. class MockSandboxedProc(SandboxedProc):
  12. """A sandbox process wrapper that replays expected syscalls."""
  13. def __init__(self, args, expected):
  14. SandboxedProc.__init__(self, args)
  15. self.expected = expected
  16. self.seen = 0
  17. def _make_method(name):
  18. def do_xxx(self, *input):
  19. print "decoded from subprocess: %s%r" % (name, input)
  20. expectedmsg, expectedinput, output = self.expected[self.seen]
  21. assert name == expectedmsg
  22. assert input == expectedinput
  23. self.seen += 1
  24. if isinstance(output, Exception):
  25. raise output
  26. return output
  27. return func_with_new_name(do_xxx, 'do_%s' % name)
  28. do_ll_os__ll_os_open = _make_method("open")
  29. do_ll_os__ll_os_read = _make_method("read")
  30. do_ll_os__ll_os_write = _make_method("write")
  31. do_ll_os__ll_os_close = _make_method("close")
  32. def test_lib():
  33. def entry_point(argv):
  34. fd = os.open("/tmp/foobar", os.O_RDONLY, 0777)
  35. assert fd == 77
  36. res = os.read(fd, 123)
  37. assert res == "he\x00llo"
  38. count = os.write(fd, "world\x00!\x00")
  39. assert count == 42
  40. for arg in argv:
  41. count = os.write(fd, arg)
  42. assert count == 61
  43. os.close(fd)
  44. return 0
  45. exe = compile(entry_point)
  46. proc = MockSandboxedProc([exe, 'x1', 'y2'], expected = [
  47. ("open", ("/tmp/foobar", os.O_RDONLY, 0777), 77),
  48. ("read", (77, 123), "he\x00llo"),
  49. ("write", (77, "world\x00!\x00"), 42),
  50. ("write", (77, exe), 61),
  51. ("write", (77, "x1"), 61),
  52. ("write", (77, "y2"), 61),
  53. ("close", (77,), None),
  54. ])
  55. proc.handle_forever()
  56. assert proc.seen == len(proc.expected)
  57. def test_foobar():
  58. py.test.skip("to be updated")
  59. foobar = rffi.llexternal("foobar", [rffi.CCHARP], rffi.LONG)
  60. def entry_point(argv):
  61. s = rffi.str2charp(argv[1]); n = foobar(s); rffi.free_charp(s)
  62. s = rffi.str2charp(argv[n]); n = foobar(s); rffi.free_charp(s)
  63. return n
  64. exe = compile(entry_point)
  65. proc = MockSandboxedProc([exe, 'spam', 'egg'], expected = [
  66. ("foobar", ("spam",), 2),
  67. ("foobar", ("egg",), 0),
  68. ])
  69. proc.handle_forever()
  70. assert proc.seen == len(proc.expected)
  71. def test_simpleio():
  72. def entry_point(argv):
  73. print "Please enter a number:"
  74. buf = ""
  75. while True:
  76. t = os.read(0, 1) # 1 character from stdin
  77. if not t:
  78. raise EOFError
  79. if t == '\n':
  80. break
  81. buf += t
  82. num = int(buf)
  83. print "The double is:", num * 2
  84. return 0
  85. exe = compile(entry_point)
  86. proc = SimpleIOSandboxedProc([exe, 'x1', 'y2'])
  87. output, error = proc.communicate("21\n")
  88. assert output == "Please enter a number:\nThe double is: 42\n"
  89. assert error == ""
  90. def test_socketio():
  91. class SocketProc(VirtualizedSocketProc, SimpleIOSandboxedProc):
  92. def build_virtual_root(self):
  93. pass
  94. def entry_point(argv):
  95. fd = os.open("tcp://python.org:80", os.O_RDONLY, 0777)
  96. os.write(fd, 'GET /\n')
  97. print os.read(fd, 50)
  98. return 0
  99. exe = compile(entry_point)
  100. proc = SocketProc([exe])
  101. output, error = proc.communicate("")
  102. assert output.startswith('HTTP/1.1 301 Moved Permanently')
  103. def test_oserror():
  104. def entry_point(argv):
  105. try:
  106. os.open("/tmp/foobar", os.O_RDONLY, 0777)
  107. except OSError as e:
  108. os.close(e.errno) # nonsense, just to see outside
  109. return 0
  110. exe = compile(entry_point)
  111. proc = MockSandboxedProc([exe], expected = [
  112. ("open", ("/tmp/foobar", os.O_RDONLY, 0777), OSError(-42, "baz")),
  113. ("close", (-42,), None),
  114. ])
  115. proc.handle_forever()
  116. assert proc.seen == len(proc.expected)
  117. class SandboxedProcWithFiles(VirtualizedSandboxedProc, SimpleIOSandboxedProc):
  118. """A sandboxed process with a simple virtualized filesystem.
  119. For testing file operations.
  120. """
  121. def build_virtual_root(self):
  122. return Dir({
  123. 'hi.txt': File("Hello, world!\n"),
  124. 'this.pyc': RealFile(__file__),
  125. })
  126. def test_too_many_opens():
  127. def entry_point(argv):
  128. try:
  129. open_files = []
  130. for i in range(500):
  131. fd = os.open('/hi.txt', os.O_RDONLY, 0777)
  132. open_files.append(fd)
  133. txt = os.read(fd, 100)
  134. if txt != "Hello, world!\n":
  135. print "Wrong content: %s" % txt
  136. except OSError as e:
  137. # We expect to get EMFILE, for opening too many files.
  138. if e.errno != errno.EMFILE:
  139. print "OSError: %s!" % (e.errno,)
  140. else:
  141. print "We opened 500 fake files! Shouldn't have been able to."
  142. for fd in open_files:
  143. os.close(fd)
  144. try:
  145. open_files = []
  146. for i in range(500):
  147. fd = os.open('/this.pyc', os.O_RDONLY, 0777)
  148. open_files.append(fd)
  149. except OSError as e:
  150. # We expect to get EMFILE, for opening too many files.
  151. if e.errno != errno.EMFILE:
  152. print "OSError: %s!" % (e.errno,)
  153. else:
  154. print "We opened 500 real files! Shouldn't have been able to."
  155. print "All ok!"
  156. return 0
  157. exe = compile(entry_point)
  158. proc = SandboxedProcWithFiles([exe])
  159. output, error = proc.communicate("")
  160. assert output == "All ok!\n"
  161. assert error == ""
  162. def test_fstat():
  163. def compare(a, b, i):
  164. if a != b:
  165. print "stat and fstat differ @%d: %s != %s" % (i, a, b)
  166. def entry_point(argv):
  167. try:
  168. # Open a file, and compare stat and fstat
  169. fd = os.open('/hi.txt', os.O_RDONLY, 0777)
  170. st = os.stat('/hi.txt')
  171. fs = os.fstat(fd)
  172. # RPython requires the index for stat to be a constant.. :(
  173. compare(st[0], fs[0], 0)
  174. compare(st[1], fs[1], 1)
  175. compare(st[2], fs[2], 2)
  176. compare(st[3], fs[3], 3)
  177. compare(st[4], fs[4], 4)
  178. compare(st[5], fs[5], 5)
  179. compare(st[6], fs[6], 6)
  180. compare(st[7], fs[7], 7)
  181. compare(st[8], fs[8], 8)
  182. compare(st[9], fs[9], 9)
  183. except OSError as e:
  184. print "OSError: %s" % (e.errno,)
  185. print "All ok!"
  186. return 0
  187. exe = compile(entry_point)
  188. proc = SandboxedProcWithFiles([exe])
  189. output, error = proc.communicate("")
  190. assert output == "All ok!\n"
  191. assert error == ""
  192. def test_lseek():
  193. def char_should_be(c, should):
  194. if c != should:
  195. print "Wrong char: '%s' should be '%s'" % (c, should)
  196. def entry_point(argv):
  197. fd = os.open('/hi.txt', os.O_RDONLY, 0777)
  198. char_should_be(os.read(fd, 1), "H")
  199. new = os.lseek(fd, 3, os.SEEK_CUR)
  200. if new != 4:
  201. print "Wrong offset, %d should be 4" % new
  202. char_should_be(os.read(fd, 1), "o")
  203. new = os.lseek(fd, -3, os.SEEK_END)
  204. if new != 11:
  205. print "Wrong offset, %d should be 11" % new
  206. char_should_be(os.read(fd, 1), "d")
  207. new = os.lseek(fd, 7, os.SEEK_SET)
  208. if new != 7:
  209. print "Wrong offset, %d should be 7" % new
  210. char_should_be(os.read(fd, 1), "w")
  211. print "All ok!"
  212. return 0
  213. exe = compile(entry_point)
  214. proc = SandboxedProcWithFiles([exe])
  215. output, error = proc.communicate("")
  216. assert output == "All ok!\n"
  217. assert error == ""
  218. def test_getuid():
  219. if not hasattr(os, 'getuid'):
  220. py.test.skip("posix only")
  221. def entry_point(argv):
  222. import os
  223. print "uid is %s" % os.getuid()
  224. print "euid is %s" % os.geteuid()
  225. print "gid is %s" % os.getgid()
  226. print "egid is %s" % os.getegid()
  227. return 0
  228. exe = compile(entry_point)
  229. proc = SandboxedProcWithFiles([exe])
  230. output, error = proc.communicate("")
  231. assert output == "uid is 1000\neuid is 1000\ngid is 1000\negid is 1000\n"
  232. assert error == ""