import gdb
import copy
import os
+import sys
+import socket
+
+def _string_bytearray(s):
+ # gets us bytes in py2 and py3
+ if not isinstance(s, bytes):
+ s = s.encode('utf-8') # sigh, python 2/3 compat
+ return bytearray(s)
def _string_escape_for_c(s):
out = ''
- for c in bytearray(s): # gets us bytes in py2 and py3
- if c == ord('\\') or c == ord('=') or c < 32 or c > 126:
+ for c in _string_bytearray(s):
+ if c == ord('\\') or c == ord('"') or c < 32 or c > 126:
out += '\\x%02x' % c
else:
out += chr(c)
return '{' + ', '.join(['(%s)' % v for v in val_lit_strs]) + ' }'
def _lit_string_uncasted(s):
- if not isinstance(s, bytes):
- s = s.encode('utf-8') # sigh, python 2/3 compat
- b = bytearray(s)
- return _lit_aggregate_uncasted(map(_lit_integer, b) + [ '0' ])
+ b = _string_bytearray(s)
+ return _lit_aggregate_uncasted([_lit_integer(x) for x in b] + [ '0' ])
def _lit_array(elemtype, val_lit_strs):
return (
'((%s[%d])%s)' %
- (elem_type, len(val_lit_strs), _lit_aggregate_uncasted(val_lit_strs))
+ (elemtype, len(val_lit_strs), _lit_aggregate_uncasted(val_lit_strs))
)
def _lit_addressof(v):
- return '&(%s)' % v
+ return '&(char[])(%s)' % v
def _make_lit(v):
if isinstance(v, int):
else:
return v # should already be an integer
+def parse_eval(expr):
+ sys.stderr.write("## EVAL %s\n" % repr(expr))
+ x = gdb.parse_and_eval(expr)
+ sys.stderr.write('## => %s\n' % x)
+ sys.stderr.flush()
+ return x
+
class DonorStructLayout():
def __init__(l, typename):
- x = gdb.parse_and_eval('(%s){ }' % typename)
+ x = gdb.lookup_type(typename)
l._typename = typename
l._template = [ ]
l._posns = { }
- for f in x.type.fields():
+ for f in x.fields():
l._posns[f.name] = len(l._template)
- try f.type.fields(): blank = '{ }'
+ try: f.type.fields(); blank = '{ }'
+ except TypeError: blank = '0'
except AttributeError: blank = '0'
l._template.append(blank)
+ sys.stderr.write('## STRUCT %s template %s fields %s\n'
+ % (typename, l._template, l._posns))
+
def substitute(l, values):
build = copy.deepcopy(l._template)
for (k,v) in values.items():
return '((%s)%s)' % (l._typename, _lit_aggregate_uncasted(build))
class DonorImplementation():
- def __init__(d):
- d._structs = { }
+ def __init__(di):
+ di._structs = { }
+ di._saved_errno = None
+ di._result_stream = os.fdopen(3, 'w')
# assembling structs
# sigh, we have to record the order of the arguments!
- def d._find_fields(typename):
+ def _find_fields(di, typename):
try:
- fields = d._structs[typename]
- except AttributeError:
+ fields = di._structs[typename]
+ except KeyError:
fields = DonorStructLayout(typename)
- d._structs[typename] = fields
+ di._structs[typename] = fields
return fields
- def d._make(typename, values):
- fields = d._find_fields(typename)
- return fieldd.substitute(values)
+ def _make(di, typename, values):
+ fields = di._find_fields(typename)
+ return fields.substitute(values)
# calling functions (need to cast the function name to the right
# type in case maybe gdb doesn't know the type)
- def _func(d, functype, funcname, realargs):
+ def _func(di, functype, funcname, realargs):
expr = '((%s) %s) %s' % (functype, funcname, realargs)
- return gdb.parse_and_eval(expr)
+ return parse_eval(expr)
- def _must_func(d, functype, funcname, realargs):
- retval = d._func(functype, funcname, realargs)
+ def _must_func(di, functype, funcname, realargs):
+ retval = di._func(functype, funcname, realargs)
if retval < 0:
- errnoval = gdb.parse_and_eval('errno')
+ errnoval = parse_eval('errno')
raise RuntimeError("%s gave errno=%d `%s'" %
- (funcname, errnoval, od.strerror(errnoval)))
+ (funcname, errnoval, os.strerror(errnoval)))
+ return retval
# wrappers for the syscalls that do what we want
- def _sendmsg(d, carrier, control_msg):
- iov_base = _lit_array('int', map(str,fds))
- iov = d._make('struct iovec', {
+ def _sendmsg(di, carrier, control_msg):
+ iov_base = _lit_array('char', [1])
+ iov = di._make('struct iovec', {
'iov_base': iov_base,
- 'iov_len' : len(fds),
+ 'iov_len' : 1,
})
- msg = d._make('struct msghdr', {
+ msg = di._make('struct msghdr', {
'msg_iov' : _lit_addressof(iov),
'msg_iovlen' : 1,
'msg_control' : _lit_array('char', control_msg),
'msg_controllen': len(control_msg),
})
- d._must_func(
- 'ssize_t (*)(int, const struct msghdr*, int flags)',
+ di._must_func(
+ 'ssize_t (*)(int, const struct msghdr*, int)',
'sendmsg',
'(%s, %s, 0)' % (carrier, _lit_addressof(msg))
)
- def _socket(d):
- return d._must_func(
+ def _socket(di):
+ return di._must_func(
'int (*)(int, int, int)',
'socket',
'(%d, %d, 0)' % (socket.AF_UNIX, socket.SOCK_STREAM)
)
- def _connect(d, fd, path):
- addr = d._make('struct sockaddr_un', {
+ def _connect(di, fd, path):
+ addr = di._make('struct sockaddr_un', {
'sun_family' : _lit_integer(socket.AF_UNIX),
'sun_path' : _lit_string_uncasted(path),
})
- d._must_func(
+ di._must_func(
'int (*)(int, const struct sockaddr*, socklen_t)',
'connect',
'(%d, (const struct sockaddr*)%s, sizeof(struct sockaddr_un))'
- % (fd, _lit_addressof(addr)
+ % (fd, _lit_addressof(addr))
)
- def _close(d, fd):
- d._must_func('int (*)(int)', 'close', '(%d)' % fd)
+ def _close(di, fd):
+ di._must_func('int (*)(int)', 'close', '(%d)' % fd)
+
+ def _mkdir(di, path, mode):
+ r = di._func(
+ 'int (*)(const char*, mode_t)',
+ 'mkdir',
+ '("%s", %d)' % (_string_escape_for_c(path), mode)
+ )
+ if r < 0:
+ errnoval = parse_eval('errno')
+ if errnoval != os.errno.EEXIST:
+ raise RuntimeError("mkdir %s failed: `%s'" %
+ (repr(path), os.strerror(errnoval)))
+ return 0
+ return 1
+
+ def _errno_save(di):
+ di._saved_errno = parse_eval('errno')
+
+ def _errno_restore(di):
+ to_restore = di._saved_errno
+ di._saved_errno = None
+ if to_restore is not None:
+ parse_eval('errno = %d' % to_restore)
+
+ def _result(di, output):
+ sys.stderr.write("#> %s" % output)
+ di._result_stream.write(output)
+ di._result_stream.flush()
# main entrypoints
- def donate(d, path, control_msg):
+ def donate(di, path, control_msg):
# control_msg is an array of integers being the ancillary data
# array ("control") for sendmsg, and hence specifies which fds
# to pass
carrier = None
- errnoval = None
try:
- errnoval = gdb.parse_and_eval('errno')
- carrier = d._socket()
- d._connect(carrier, path)
- d._sendmsg(carrier, control_msg)
- d._close(carrier)
+ di._errno_save()
+ carrier = di._socket()
+ di._connect(carrier, path)
+ di._sendmsg(carrier, control_msg)
+ di._close(carrier)
carrier = None
finally:
if carrier is not None:
- try: d._close(carrier)
+ try: di._close(carrier)
except Exception: pass
- if errnoval is not None:
- gdb.parse_and_eval('errno = %d' % errnoval)
+ di._errno_restore()
+
+ di._result('1\n')
+
+ def geteuid(di):
+ try:
+ di._errno_save()
+ val = di._must_func('uid_t (*)(void)', 'geteuid', '()')
+ finally:
+ di._errno_restore()
+
+ di._result('%d\n' % val)
+
+ def mkdir(di, path):
+ try:
+ di._errno_save()
+ val = di._mkdir(path, int('0700', 8))
+ finally:
+ di._errno_restore()
+
+ di._result('%d\n' % val)
+
+ def _protocol_read(di):
+ input = sys.stdin.readline()
+ if input == '': return None
+ input = input.rstrip('\n')
+ sys.stderr.write("#< %s\n" % input)
+ return input
+
+ def eval_loop(di):
+ while True:
+ di._result('!\n')
+ cmd = di._protocol_read()
+ if cmd is None: break
+ eval(cmd)