@@ -28,15 +28,39 @@ use crate::{
2828 kthread:: KernelThreadMechanism ,
2929 namespace:: user_namespace:: map_id_up,
3030 pid:: { Pid , PidType } ,
31- ptrace,
32- resource:: RUsageWho ,
33- ProcessControlBlock , ProcessFlags , ProcessManager , ProcessState , RawPid ,
31+ ptrace, ProcessControlBlock , ProcessFlags , ProcessManager , ProcessState , RawPid ,
3432 } ,
3533 sched:: { cputime:: ns_to_clock_t, SchedMode , __schedule_with_current} ,
3634 smp:: core:: smp_get_processor_id,
3735 syscall:: user_access:: clear_user_protected,
3836} ;
3937
38+ struct ChildExitSiginfoSnapshot {
39+ code : i32 ,
40+ pid : RawPid ,
41+ uid : u32 ,
42+ status : i32 ,
43+ utime : i64 ,
44+ stime : i64 ,
45+ }
46+
47+ impl ChildExitSiginfoSnapshot {
48+ fn into_siginfo ( self , signal : Signal ) -> SigInfo {
49+ SigInfo :: new (
50+ signal,
51+ 0 ,
52+ SigCode :: Raw ( self . code ) ,
53+ SigType :: SigChild {
54+ pid : self . pid ,
55+ uid : self . uid ,
56+ status : self . status ,
57+ utime : self . utime ,
58+ stime : self . stime ,
59+ } ,
60+ )
61+ }
62+ }
63+
4064impl ProcessManager {
4165 const DEFAULT_OVERFLOW_UID : u32 = 65534 ;
4266
@@ -49,11 +73,23 @@ impl ProcessManager {
4973 // A claimed old leader must retain all hashed identity until the exec
5074 // owner swaps it. In particular it is never autoreaped here.
5175 if claimed_exec_leader {
52- current. set_exit_state_zombie ( ) ;
76+ let ptrace_notification = {
77+ let _relation_guard = crate :: process:: PTRACE_RELATION_LOCK . lock_irqsave ( ) ;
78+ let tracer = ptrace:: ptracer_of_locked ( current) ;
79+ let snapshot = tracer
80+ . as_ref ( )
81+ . map ( |tracer| Self :: child_exit_siginfo_snapshot ( current, tracer) ) ;
82+ current. set_exit_state_zombie ( ) ;
83+ tracer. map ( |tracer| {
84+ (
85+ tracer,
86+ Signal :: SIGCHLD as i32 ,
87+ snapshot. expect ( "ptrace tracer requires an exit siginfo snapshot" ) ,
88+ )
89+ } )
90+ } ;
5391 Self :: wake_pidfd_pollers_for_task_exit ( current) ;
54- Self :: notify_ptrace_parent (
55- ptrace:: ptracer_of ( current) . map ( |tracer| ( tracer, Signal :: SIGCHLD as i32 ) ) ,
56- ) ;
92+ Self :: notify_ptrace_parent ( ptrace_notification) ;
5793 current. mark_exit_notify_complete ( ) ;
5894 let completed = sighand. complete_group_exec_leader_exit ( current) ;
5995 debug_assert ! ( completed) ;
@@ -75,6 +111,13 @@ impl ProcessManager {
75111 // cannot lose the transition either.
76112 let _relation_guard = crate :: process:: PTRACE_RELATION_LOCK . lock_irqsave ( ) ;
77113 let tracer = ptrace:: ptracer_of_locked ( current) ;
114+ // A polling tracer may reap and unhash the child as soon as
115+ // Zombie becomes visible. Freeze every child-derived field
116+ // before publishing Zombie; signal delivery must consume only
117+ // this immutable snapshot.
118+ let ptrace_snapshot = tracer
119+ . as_ref ( )
120+ . map ( |tracer| Self :: child_exit_siginfo_snapshot ( current, tracer) ) ;
78121 let leader = current. is_thread_group_leader ( ) ;
79122 let ( group_empty, natural_token) = if leader {
80123 // Publish Zombie and inspect group emptiness under the same
@@ -107,7 +150,11 @@ impl ProcessManager {
107150 } else {
108151 Signal :: SIGCHLD as i32
109152 } ;
110- ( tracer, signal)
153+ (
154+ tracer,
155+ signal,
156+ ptrace_snapshot. expect ( "ptrace tracer requires an exit siginfo snapshot" ) ,
157+ )
111158 } ) ;
112159 ( ptrace_notification, natural_token, autoreap_nonleader)
113160 } ;
@@ -134,20 +181,31 @@ impl ProcessManager {
134181 sighand. complete_group_exec_leader_exit ( current) ;
135182 }
136183
137- fn notify_ptrace_parent ( tracer : Option < ( Arc < ProcessControlBlock > , i32 ) > ) {
138- if let Some ( ( tracer, signal) ) = tracer {
184+ fn notify_ptrace_parent (
185+ tracer : Option < ( Arc < ProcessControlBlock > , i32 , ChildExitSiginfoSnapshot ) > ,
186+ ) {
187+ if let Some ( ( tracer, signal, snapshot) ) = tracer {
139188 if signal > 0 {
140- let _ = crate :: ipc:: kill:: send_signal_to_pcb ( tracer. clone ( ) , Signal :: from ( signal) ) ;
189+ let signal = Signal :: from ( signal) ;
190+ let mut info = snapshot. into_siginfo ( signal) ;
191+ if let Err ( e) =
192+ signal. send_signal_info_to_pcb ( Some ( & mut info) , tracer. clone ( ) , PidType :: TGID )
193+ {
194+ warn ! (
195+ "failed to send ptrace exit signal to tracer {:?}: {:?}" ,
196+ tracer. raw_pid( ) ,
197+ e
198+ ) ;
199+ }
141200 }
142201 ProcessManager :: wake_wait_parent ( & tracer) ;
143202 }
144203 }
145204
146- fn child_exit_siginfo (
205+ fn child_exit_siginfo_snapshot (
147206 child : & Arc < ProcessControlBlock > ,
148207 parent : & Arc < ProcessControlBlock > ,
149- signal : Signal ,
150- ) -> SigInfo {
208+ ) -> ChildExitSiginfoSnapshot {
151209 let raw_status = child
152210 . sched_info ( )
153211 . state ( )
@@ -171,22 +229,18 @@ impl ProcessManager {
171229 let parent_user_ns = parent. cred ( ) . user_ns . clone ( ) ;
172230 let uid = map_id_up ( & parent_user_ns. inner . lock ( ) . uid_map , child_uid)
173231 . unwrap_or ( Self :: DEFAULT_OVERFLOW_UID ) ;
174- let rusage = child. get_rusage ( RUsageWho :: RUsageSelf ) . unwrap_or_default ( ) ;
232+ let rusage = child. exit_notification_rusage ( ) ;
175233 let utime = i64:: try_from ( ns_to_clock_t ( rusage. ru_utime . to_ns ( ) ) ) . unwrap_or ( i64:: MAX ) ;
176234 let stime = i64:: try_from ( ns_to_clock_t ( rusage. ru_stime . to_ns ( ) ) ) . unwrap_or ( i64:: MAX ) ;
177235
178- SigInfo :: new (
179- signal,
180- 0 ,
181- SigCode :: Raw ( code) ,
182- SigType :: SigChild {
183- pid,
184- uid,
185- status,
186- utime,
187- stime,
188- } ,
189- )
236+ ChildExitSiginfoSnapshot {
237+ code,
238+ pid,
239+ uid,
240+ status,
241+ utime,
242+ stime,
243+ }
190244 }
191245
192246 /// Complete the unique natural-parent notification transaction. Build the
@@ -217,7 +271,10 @@ impl ProcessManager {
217271 // Snapshot every field before autoreap can unhash the child's PID.
218272 let notification = if exit_signal > 0 && !( autoreap && ignored) {
219273 let signal = Signal :: from ( exit_signal) ;
220- Some ( ( signal, Self :: child_exit_siginfo ( child, & parent, signal) ) )
274+ Some ( (
275+ signal,
276+ Self :: child_exit_siginfo_snapshot ( child, & parent) . into_siginfo ( signal) ,
277+ ) )
221278 } else {
222279 None
223280 } ;
0 commit comments