@@ -115,17 +115,32 @@ impl LinuxProcess {
115115 let data = std:: fs:: read ( path)
116116 . map_err ( |_| Error ( ErrorOrigin :: OsLayer , ErrorKind :: EnvarNotFound ) ) ?;
117117
118+ // /proc/<pid>/environ is exactly the memory range env_start..env_end,
119+ // so in-process addresses can be derived from byte offsets within it.
120+ let env_start = self
121+ . proc_handle ( )
122+ . ok ( )
123+ . and_then ( |p| p. stat ( ) . ok ( ) )
124+ . and_then ( |stat| stat. env_start ) ;
125+
118126 let mut out = Vec :: new ( ) ;
119- for entry in data. split ( |b| * b == 0 ) . filter ( |entry| !entry. is_empty ( ) ) {
120- let entry = String :: from_utf8_lossy ( entry) ;
121- if let Some ( ( name, value) ) = entry. split_once ( '=' ) {
122- out. push ( EnvVarInfo {
123- name : ReprCString :: from ( name) ,
124- value : ReprCString :: from ( value) ,
125- address : Address :: NULL ,
126- arch : self . info . proc_arch ,
127- } ) ;
127+ let mut offset = 0u64 ;
128+ for entry in data. split ( |b| * b == 0 ) {
129+ let entry_len = entry. len ( ) as u64 ;
130+ if !entry. is_empty ( ) {
131+ let entry = String :: from_utf8_lossy ( entry) ;
132+ if let Some ( ( name, value) ) = entry. split_once ( '=' ) {
133+ out. push ( EnvVarInfo {
134+ name : ReprCString :: from ( name) ,
135+ value : ReprCString :: from ( value) ,
136+ address : env_start
137+ . map ( |start| Address :: from ( start + offset) )
138+ . unwrap_or ( Address :: NULL ) ,
139+ arch : self . info . proc_arch ,
140+ } ) ;
141+ }
128142 }
143+ offset += entry_len + 1 ;
129144 }
130145
131146 Ok ( out)
@@ -152,11 +167,10 @@ impl Process for LinuxProcess {
152167
153168 module_maps
154169 . iter ( )
155- . enumerate ( )
156170 . filter ( |_| target_arch. is_none ( ) || Some ( & self . info ( ) . sys_arch ) == target_arch)
157- . take_while ( |( i , _ ) | {
171+ . take_while ( |map | {
158172 callback. call ( ModuleAddressInfo {
159- address : Address :: from ( * i as u64 ) ,
173+ address : Address :: from ( map . address . 0 ) ,
160174 arch : self . info . proc_arch ,
161175 } )
162176 } )
@@ -182,7 +196,8 @@ impl Process for LinuxProcess {
182196 let module_maps = self . module_maps ( ) ?;
183197
184198 module_maps
185- . get ( address. to_umem ( ) as usize )
199+ . iter ( )
200+ . find ( |map| Address :: from ( map. address . 0 ) == address)
186201 . map ( |map| ModuleInfo {
187202 address,
188203 parent_process : self . info . address ,
@@ -223,8 +238,23 @@ impl Process for LinuxProcess {
223238 ///
224239 /// This will generally be for the initial executable that was run
225240 fn primary_module_address ( & mut self ) -> Result < Address > {
226- // TODO: Is it always 0th mod?
227- Ok ( Address :: from ( 0 ) )
241+ let exe = self . proc_handle ( ) ?. exe ( ) . ok ( ) ;
242+ let module_maps = self . module_maps ( ) ?;
243+
244+ if let Some ( exe) = exe {
245+ if let Some ( map) = module_maps
246+ . iter ( )
247+ . find ( |m| matches ! ( & m. pathname, MMapPath :: Path ( p) if * p == exe) )
248+ {
249+ return Ok ( Address :: from ( map. address . 0 ) ) ;
250+ }
251+ }
252+
253+ // exe link unreadable or unmatched (e.g. deleted binary) - fall back to first mapping
254+ module_maps
255+ . first ( )
256+ . map ( |m| Address :: from ( m. address . 0 ) )
257+ . ok_or ( Error ( ErrorOrigin :: OsLayer , ErrorKind :: NotFound ) )
228258 }
229259
230260 /// Retrieves the process info
@@ -234,7 +264,16 @@ impl Process for LinuxProcess {
234264
235265 /// Retrieves the state of the process
236266 fn state ( & mut self ) -> ProcessState {
237- ProcessState :: Unknown
267+ match procfs:: process:: Process :: new ( self . pid ) . and_then ( |p| p. stat ( ) ) {
268+ Ok ( stat) => match stat. state {
269+ // Z = zombie (exited, unreaped), X/x = dead
270+ 'Z' | 'X' | 'x' => ProcessState :: Dead ( stat. exit_code . unwrap_or ( 0 ) ) ,
271+ _ => ProcessState :: Alive ,
272+ } ,
273+ // /proc/<pid> vanished -> the process was reaped; exit code is no longer recoverable
274+ Err ( procfs:: ProcError :: NotFound ( _) ) => ProcessState :: Dead ( 0 ) ,
275+ Err ( _) => ProcessState :: Unknown ,
276+ }
238277 }
239278
240279 /// Changes the dtb this process uses for memory translations.
@@ -321,8 +360,13 @@ impl Process for LinuxProcess {
321360
322361 #[ cfg( memflow_plugin_api = "2" ) ]
323362 fn environment_block_address ( & mut self , _architecture : ArchitectureIdent ) -> Result < Address > {
324- // Linux does not expose a stable public env-block pointer through procfs.
325- Ok ( Address :: NULL )
363+ // env_start is only exposed on kernel >= 3.5 and may be hidden by permission checks.
364+ self . proc_handle ( ) ?
365+ . stat ( )
366+ . map_err ( |_| Error ( ErrorOrigin :: OsLayer , ErrorKind :: UnableToReadFile ) ) ?
367+ . env_start
368+ . map ( Address :: from)
369+ . ok_or ( Error ( ErrorOrigin :: OsLayer , ErrorKind :: NotSupported ) )
326370 }
327371
328372 #[ cfg( memflow_plugin_api = "2" ) ]
0 commit comments