Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # The MIT License (MIT)
- #
- # Copyright (c) 2015 David Wison (original code)
- # Copyright (c) 2019 Moshe Malawach (modified for smart contract use)
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
- # in the Software without restriction, including without limitation the rights
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the Software is
- # furnished to do so, subject to the following conditions:
- #
- # The above copyright notice and this permission notice shall be included in
- # all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- # THE SOFTWARE.
- import ctypes
- import json
- import os
- import resource
- import signal
- import socket
- import struct
- from multiprocessing import Process
- from RestrictedPython import (compile_restricted, safe_builtins,
- utility_builtins)
- builtins = {**safe_builtins, **utility_builtins}
- #builtins['__metaclass__'] = type
- builtins['__name__'] = "SC"
- del builtins['random']
- del builtins['whrandom']
- _libc = ctypes.CDLL(None)
- _exit = _libc._exit
- _prctl = _libc.prctl
- PR_SET_SECCOMP = 22
- SECCOMP_MODE_STRICT = 1
- def enable_seccomp():
- rc = _prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0)
- assert rc == 0
- def read_exact(fp, n):
- buf = b''
- while len(buf) < n:
- buf2 = os.read(fp.fileno(), n)
- if not buf2:
- _exit(123)
- buf += buf2
- return buf2
- def write_exact(fp, s):
- done = 0
- while done < len(s):
- written = os.write(fp.fileno(), s[done:])
- if not written:
- _exit(123)
- done += written
- class SecureEvalHost(object):
- def __init__(self):
- self.host, self.child = socket.socketpair()
- self.pid = None
- def start_child(self):
- assert not self.pid
- self.pid = os.fork()
- if not self.pid:
- self._child_main()
- self.child.close()
- def kill_child(self):
- assert self.pid
- pid, status = os.waitpid(self.pid, os.WNOHANG)
- os.kill(self.pid, signal.SIGKILL)
- def do_eval(self, msg):
- return {'result': eval(msg['body'])}
- def _do_exec(self, msg):
- locs = {}
- globs = {'__builtins__': builtins}
- byte_code = compile(msg['body'], '<restricted-python>', 'exec')
- exec(byte_code, globs, locs)
- return locs
- def do_exec_func(self, msg):
- try:
- locs = self._do_exec(msg)
- except Exception as e:
- return {'error': repr(e), 'error_step': 'prepare', 'result': None}
- try:
- result = locs[msg['func']](*msg['args'], **msg['kwargs'])
- return {'result': result}
- except Exception as e:
- return {'error': repr(e), 'error_step': 'call', 'result': None}
- def do_construct(self, msg):
- try:
- locs = self._do_exec(msg)
- except Exception as e:
- return {'error': repr(e), 'error_step': 'prepare', 'result': None}
- try:
- item_class = locs['SmartContract']
- obj = item_class(*msg['args'], **msg['kwargs'])
- return {'result': True, 'state': obj.__dict__}
- except Exception as e:
- return {'error': repr(e), 'error_step': 'call', 'result': None}
- def do_call(self, msg):
- try:
- locs = self._do_exec(msg)
- except Exception as e:
- return {'error': repr(e), 'error_step': 'prepare', 'result': None}
- try:
- item_class = locs['SmartContract']
- instance = item_class.__new__(item_class)
- instance.__dict__ = msg['state']
- result = getattr(instance, msg['func'])(*msg['args'],
- **msg['kwargs'])
- return {'result': result, 'state': instance.__dict__}
- except Exception as e:
- return {'error': repr(e), 'error_step': 'call', 'result': None}
- def _child_main(self):
- self.host.close()
- for fd in map(int, os.listdir('/proc/self/fd')):
- try:
- if fd != self.child.fileno():
- os.close(fd)
- except OSError:
- pass
- resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
- soft, hard = resource.getrlimit(resource.RLIMIT_AS)
- resource.setrlimit(resource.RLIMIT_AS, (64 * 1024, 128 * 1024))
- soft, hard = resource.getrlimit(resource.RLIMIT_AS)
- print(soft, hard)
- enable_seccomp()
- while True:
- sz, = struct.unpack('>L', read_exact(self.child, 4))
- doc = json.loads(read_exact(self.child, sz))
- try:
- if doc['cmd'] == 'eval':
- resp = self.do_eval(doc)
- elif doc['cmd'] == 'exec_func':
- resp = self.do_exec_func(doc)
- elif doc['cmd'] == 'construct':
- resp = self.do_construct(doc)
- elif doc['cmd'] == 'call':
- resp = self.do_call(doc)
- elif doc['cmd'] == 'exit':
- _exit(0)
- except Exception as e:
- resp = {'error': repr(e), 'error_step': 'unhandled',
- 'result': None}
- goobs = json.dumps(resp)
- write_exact(self.child, struct.pack('>L', len(goobs)))
- write_exact(self.child, goobs.encode('utf-8'))
- def eval(self, s):
- msg = json.dumps({'cmd': 'eval', 'body': s})
- write_exact(self.host, struct.pack('>L', len(msg)))
- write_exact(self.host, msg.encode('utf-8'))
- sz, = struct.unpack('>L', read_exact(self.host, 4))
- goobs = json.loads(read_exact(self.host, sz).decode('utf-8'))
- return goobs['result']
- def exec_func(self, s, func, *args, **kwargs):
- msg = json.dumps({'cmd': 'exec_func', 'body': s,
- 'func': func, 'args': args,
- 'kwargs': kwargs})
- write_exact(self.host, struct.pack('>L', len(msg)))
- write_exact(self.host, msg.encode('utf-8'))
- sz, = struct.unpack('>L', read_exact(self.host, 4))
- goobs = json.loads(read_exact(self.host, sz).decode('utf-8'))
- return goobs
- def construct(self, s, args, kwargs={}):
- msg = json.dumps({'cmd': 'construct', 'body': s,
- 'args': args,
- 'kwargs': kwargs})
- write_exact(self.host, struct.pack('>L', len(msg)))
- write_exact(self.host, msg.encode('utf-8'))
- sz, = struct.unpack('>L', read_exact(self.host, 4))
- goobs = json.loads(read_exact(self.host, sz).decode('utf-8'))
- return goobs
- def call(self, s, func, state, args, kwargs={}):
- msg = json.dumps({'cmd': 'call', 'body': s, 'state': state,
- 'func': func, 'args': args,
- 'kwargs': kwargs})
- write_exact(self.host, struct.pack('>L', len(msg)))
- write_exact(self.host, msg.encode('utf-8'))
- sz, = struct.unpack('>L', read_exact(self.host, 4))
- goobs = json.loads(read_exact(self.host, sz).decode('utf-8'))
- return goobs
- def go():
- insecure_code = open('token_class.py', 'r').read()
- sec = SecureEvalHost()
- sec.start_child()
- try:
- print(sec.eval('1+100'))
- res = sec.construct(insecure_code, [{'from': '0xblah'}, 'Test Token', 'TST', 1000])
- print(res)
- res = sec.call(insecure_code, 'transfer', res['state'],
- [{'from': '0xblah'}, "0xbluh", 2])
- print(res)
- res = sec.call(insecure_code, 'transfer', res['state'],
- [{'from': '0xbluh'}, "0xblih", 3])
- print(res)
- except:
- print("error in process")
- finally:
- sec.kill_child()
- print("finished")
- if __name__ == '__main__':
- go()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement