@@ -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+
111128class 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
297316def 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