2 # class for use inside gdb which is debugging the donor process
9 def _string_escape_for_c(s):
11 for c in bytearray(s): # gets us bytes in py2 and py3
12 if c == ord('\\') or c == ord('"') or c < 32 or c > 126:
23 def _lit_aggregate_uncasted(val_lit_strs):
24 return '{' + ', '.join(['(%s)' % v for v in val_lit_strs]) + ' }'
26 def _lit_string_uncasted(s):
27 if not isinstance(s, bytes):
28 s = s.encode('utf-8') # sigh, python 2/3 compat
30 return _lit_aggregate_uncasted(map(_lit_integer, b) + [ '0' ])
32 def _lit_array(elemtype, val_lit_strs):
35 (elem_type, len(val_lit_strs), _lit_aggregate_uncasted(val_lit_strs))
38 def _lit_addressof(v):
42 if isinstance(v, int):
43 return _lit_integer(v)
45 return v # should already be an integer
48 sys.stderr.write("## EVAL %s\n" % repr(expr))
49 x = gdb.parse_and_eval(expr)
50 sys.stderr.write('## => %s\n' % x)
54 class DonorStructLayout():
55 def __init__(l, typename):
56 x = parse_eval('(%s){ }' % typename)
57 l._typename = typename
60 for f in x.type.fields():
61 l._posns[f.name] = len(l._template)
62 try: f.type.fields(); blank = '{ }'
63 except AttributeError: blank = '0'
64 l._template.append(blank)
66 def substitute(l, values):
67 build = copy.deepcopy(l._template)
68 for (k,v) in values.items():
69 build[ l._posns[k] ] = _make_lit(v)
70 return '((%s)%s)' % (l._typename, _lit_aggregate_uncasted(build))
72 class DonorImplementation():
75 di._saved_errno = None
76 di._result_stream = os.fdopen(3, 'w')
79 # sigh, we have to record the order of the arguments!
80 def _find_fields(typename):
82 fields = di._structs[typename]
83 except AttributeError:
84 fields = DonorStructLayout(typename)
85 di._structs[typename] = fields
88 def _make(typename, values):
89 fields = di._find_fields(typename)
90 return fields.substitute(values)
92 # calling functions (need to cast the function name to the right
93 # type in case maybe gdb doesn't know the type)
95 def _func(di, functype, funcname, realargs):
96 expr = '((%s) %s) %s' % (functype, funcname, realargs)
97 return parse_eval(expr)
99 def _must_func(di, functype, funcname, realargs):
100 retval = di._func(functype, funcname, realargs)
102 errnoval = parse_eval('errno')
103 raise RuntimeError("%s gave errno=%d `%s'" %
104 (funcname, errnoval, os.strerror(errnoval)))
107 # wrappers for the syscalls that do what we want
109 def _sendmsg(di, carrier, control_msg):
110 iov_base = _lit_array('int', map(str,fds))
111 iov = di._make('struct iovec', {
112 'iov_base': iov_base,
113 'iov_len' : len(fds),
116 msg = di._make('struct msghdr', {
117 'msg_iov' : _lit_addressof(iov),
119 'msg_control' : _lit_array('char', control_msg),
120 'msg_controllen': len(control_msg),
124 'ssize_t (*)(int, const struct msghdr*, int flags)',
126 '(%s, %s, 0)' % (carrier, _lit_addressof(msg))
130 return di._must_func(
131 'int (*)(int, int, int)',
133 '(%d, %d, 0)' % (socket.AF_UNIX, socket.SOCK_STREAM)
136 def _connect(di, fd, path):
137 addr = di._make('struct sockaddr_un', {
138 'sun_family' : _lit_integer(socket.AF_UNIX),
139 'sun_path' : _lit_string_uncasted(path),
143 'int (*)(int, const struct sockaddr*, socklen_t)',
145 '(%d, (const struct sockaddr*)%s, sizeof(struct sockaddr_un))'
146 % (fd, _lit_addressof(addr))
150 di._must_func('int (*)(int)', 'close', '(%d)' % fd)
152 def _mkdir(di, path, mode):
154 'int (*)(const char*, mode_t)',
156 '("%s", %d)' % (_string_escape_for_c(path), mode)
159 errnoval = parse_eval('errno')
160 if errnoval != os.errno.EEXIST:
161 raise RuntimeError("mkdir %s failed: `%s'" %
162 (repr(path), os.strerror(errnoval)))
167 di._saved_errno = parse_eval('errno')
169 def _errno_restore(di):
170 to_restore = di._saved_errno
171 di._saved_errno = None
172 if to_restore is not None:
173 parse_eval('errno = %d' % to_restore)
175 def _result(di, output):
176 sys.stderr.write("#> %s" % output)
177 di._result_stream.write(output)
178 di._result_stream.flush()
182 def donate(di, path, control_msg):
183 # control_msg is an array of integers being the ancillary data
184 # array ("control") for sendmsg, and hence specifies which fds
190 carrier = di._socket()
191 di._connect(carrier, path)
192 di._sendmsg(carrier, control_msg)
196 if carrier is not None:
197 try: di._close(carrier)
198 except Exception: pass
206 val = di._must_func('uid_t (*)(void)', 'geteuid', '()')
210 di._result('%d\n' % val)
215 val = di._mkdir(path, int('0700', 8))
219 di._result('%d\n' % val)
221 def _protocol_read(di):
222 input = sys.stdin.readline().rstrip('\n')
223 sys.stderr.write("#< %s\n" % input)
229 cmd = di._protocol_read()