Skip to content

Commit 610b8f5

Browse files
committed
fixup! linux: switch to target process UID/GID
1 parent d959515 commit 610b8f5

File tree

1 file changed

+25
-43
lines changed

1 file changed

+25
-43
lines changed

ci_core_dumper/linux.py

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def forknpark(fn, **kws):
7171
if sts!=0:
7272
raise RuntimeError(sts)
7373

74-
def nsenter(pid):
74+
def nsenter(pid, limit=None):
7575
"""Join the current process to all of the namespaces
7676
of the target PID of which it is not already a member.
7777
"""
@@ -95,7 +95,7 @@ def setns(F, nstype=0):
9595
# must open all NS files first (from init mount ns)
9696
# before entering any (including mount ns)
9797
for ns in os.listdir('/proc/%d/ns'%pid):
98-
if ns not in ('mnt',):
98+
if limit and ns not in limit:
9999
continue
100100
NSs.append((ns,
101101
open('/proc/%d/ns/%s'%(pid, ns), 'rb'),
@@ -108,6 +108,23 @@ def setns(F, nstype=0):
108108
T.close()
109109
S.close()
110110

111+
def read_uid_gid(pid):
112+
'Detect UID/GID of target PID'
113+
res = os.stat('/proc/{}/status'.format(pid))
114+
return res.st_uid, res.st_gid
115+
116+
def readenv(pid):
117+
'Read environment of running process'
118+
env = {}
119+
with open('/proc/{}/environ'.format(pid), 'r') as F:
120+
# b"VAR=value\0...\0"
121+
lines = F.read().split('\0')
122+
lines.pop() # trailing nil
123+
for ev in lines:
124+
K, V = ev.split('=', 1)
125+
env[K] = V
126+
return env
127+
111128
class FLock(object):
112129
def __init__(self, file):
113130
self._file = file
@@ -285,8 +302,10 @@ def dump(outdir, gdb, extra_cmds):
285302
print('Dumping PID %d (%d) @ %d %s'%(tpid, ipid, dtime, time.ctime(dtime)))
286303

287304
try:
288-
nsenter(ipid)
305+
# only need to join mount namespace
306+
nsenter(ipid, limit=('mnt', 'pid'))
289307

308+
# must fork in order to fully join
290309
forknpark(dump2, pid=tpid, gdb=gdb, extra_cmds=extra_cmds)
291310
except:
292311
traceback.print_exc()
@@ -296,48 +315,11 @@ def dump(outdir, gdb, extra_cmds):
296315

297316
def dump2(pid, gdb, extra_cmds):
298317
# running as root, fully in the target/container namespaces
299-
print('Initial uid %d, gid %d'%(os.getuid(), os.getgid()))
300-
301-
uid = gid = None
302-
with open('/proc/{}/status'.format(pid)) as F:
303-
for line in F:
304-
if line.startswith('Uid:'): # Uid: 1000 1000 1000 1000
305-
uid = int(line.split()[1])
306-
307-
elif line.startswith('Gid:'): # Gid: 1000 1000 1000 1000
308-
gid = int(line.split()[1])
309-
310-
if gid:
311-
os.setgid(gid)
312-
if uid:
313-
os.setuid(uid)
314-
print('Target UID %s/%s'%(uid, gid))
315-
316-
# os.environ is still from the init namespaces.
317-
# copy the target process environment
318-
env = os.environ.copy()
319-
320-
with open('/proc/{}/environ'.format(pid), 'rb') as F:
321-
for ev in F.read().split(b'\0'):
322-
K, _sep, V = ev.partition(b'=')
323-
if K and V is not None:
324-
env[K.decode(errors='replace')] = V.decode(errors='replace')
325-
326-
# fill in some ~sensible defaults
327-
env.setdefault('TERM', 'vt100')
328-
env.setdefault('USER', 'root')
329-
env.setdefault('PATH', "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
330-
for sh in (os.environ.get('SHELL','sh'), 'sh', 'bash', 'dash'):
331-
shell = find_executable(sh, path=env['PATH'])
332-
if sh:
333-
env['SHELL'] = shell
334-
break
335-
else:
336-
print('ERROR: no support shell in target')
337-
sys.exit(1)
318+
319+
env = readenv(pid)
338320

339321
for gname in (gdb, 'gdb'):
340-
gdb = find_executable(gname, path=env['PATH'])
322+
gdb = find_executable(gname, path=env.get('PATH') or '')
341323
if gdb:
342324
break
343325
else:

0 commit comments

Comments
 (0)