Skip to content

Commit 27a1d72

Browse files
committed
Make a few changes so that the server / client processes of pyrasite-shell can be in two different docker containers.
We need a deterministic listen-back port so the connecting (debugging) container can provide it at launch. We need to write the payload file to a temporary location and it should have others read bit set so a container that dropped permissions can still read it. There are a few settings required in the docker run command of the debugging container process, but not other requirements for the container under inspection.
1 parent d0c90ab commit 27a1d72

File tree

2 files changed

+30
-21
lines changed

2 files changed

+30
-21
lines changed

pyrasite/ipc.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,18 @@ class PyrasiteIPC(object):
6464
# shell payloads with netcat.
6565
reliable = True
6666

67-
def __init__(self, pid, reverse='ReversePythonConnection', timeout=5):
67+
def __init__(self, pid, reverse='ReversePythonConnection', timeout=5, port=None, server_host='localhost', client_host='localhost', tmpdir=None):
6868
super(PyrasiteIPC, self).__init__()
6969
self.pid = pid
7070
self.sock = None
7171
self.server_sock = None
7272
self.hostname = None
73-
self.port = None
73+
self.port = port
7474
self.reverse = reverse
7575
self.timeout = float(timeout)
76+
self.server_host = server_host
77+
self.client_host = client_host
78+
self.tmpdir = tmpdir
7679

7780
def __enter__(self):
7881
self.connect()
@@ -109,7 +112,7 @@ def connect(self):
109112

110113
def listen(self):
111114
"""Listen on a random port"""
112-
for res in socket.getaddrinfo('localhost', None, socket.AF_UNSPEC,
115+
for res in socket.getaddrinfo(self.server_host, self.port, socket.AF_UNSPEC,
113116
socket.SOCK_STREAM, 0, 0):
114117
af, socktype, proto, canonname, sa = res
115118
try:
@@ -134,15 +137,18 @@ def listen(self):
134137

135138
def create_payload(self):
136139
"""Write out a reverse python connection payload with a custom port"""
137-
(fd, filename) = tempfile.mkstemp()
140+
(fd, filename) = tempfile.mkstemp(dir=self.tmpdir)
141+
if platform.system() != 'Windows':
142+
os.fchmod(fd, stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)
138143
tmp = os.fdopen(fd, 'w')
139144
path = dirname(abspath(pyrasite.__file__))
140145
payload = open(join(path, 'reverse.py'))
141146

142147
for line in payload.readlines():
143148
if line.startswith('#'):
144149
continue
145-
line = line.replace('port = 9001', 'port = %d' % self.port)
150+
line = line.replace('port = 9001', 'port = {}'.format(self.port))
151+
line = line.replace('host = localhost', 'host = {}'.format(self.client_host))
146152
if not self.reliable:
147153
line = line.replace('reliable = True', 'reliable = False')
148154
tmp.write(line)
@@ -151,9 +157,6 @@ def create_payload(self):
151157
tmp.close()
152158
payload.close()
153159

154-
if platform.system() != 'Windows':
155-
os.chmod(filename, stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)
156-
157160
return filename
158161

159162
def inject(self):

pyrasite/tools/shell.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,32 @@
1515
#
1616
# Copyright (C) 2011-2013 Red Hat, Inc., Luke Macken <lmacken@redhat.com>
1717

18+
import argparse
1819
import os
19-
import sys
2020
import pyrasite
2121

2222

2323
def shell():
24-
"""Open a Python shell in a running process"""
24+
parser = argparse.ArgumentParser(description='Open a Python shell in a running process')
25+
parser.add_argument('pid', type=int, help='PID of the running process to attach to.')
26+
parser.add_argument('--timeout', type=int, default=5, help='IPC Timeout, applies for each command.')
27+
parser.add_argument('--server-host', default='localhost', help='The hostname to use for the listening (server) side of the IPC communication. Sometimes, (docker), localhost does not work.')
28+
parser.add_argument('--client-host', default='localhost', help='The hostname to use for the connecting (client) side of the IPC communication. Sometimes, (docker), localhost does not work.')
29+
parser.add_argument('--port', type=int, default=None, help='Optionally specify a port that will be listened on for the remote process to attach back.')
30+
parser.add_argument('--tmpdir', default=None, help='Use the following tmp directory for transferring the payload')
2531

26-
usage = "Usage: pyrasite-shell <PID>"
27-
if not len(sys.argv) == 2:
28-
print(usage)
29-
sys.exit(1)
30-
try:
31-
pid = int(sys.argv[1])
32-
except ValueError:
33-
print(usage)
34-
sys.exit(1)
32+
args = parser.parse_args()
33+
34+
ipc = pyrasite.PyrasiteIPC(
35+
args.pid,
36+
'ReversePythonShell',
37+
timeout=args.timeout,
38+
server_host=args.server_host,
39+
client_host=args.client_host,
40+
port=args.port,
41+
tmpdir=args.tmpdir,
42+
)
3543

36-
ipc = pyrasite.PyrasiteIPC(pid, 'ReversePythonShell',
37-
timeout=os.getenv('PYRASITE_IPC_TIMEOUT') or 5)
3844
ipc.connect()
3945

4046
print("Pyrasite Shell %s" % pyrasite.__version__)

0 commit comments

Comments
 (0)