@@ -40,7 +40,10 @@ handler(int signo)
4040void
4141intercept_closure_reset (struct intercept_closure * closure )
4242{
43+ /* Preserve closure->details, zero everything else. */
44+ const struct command_details * details = closure -> details ;
4345 memset (closure , 0 , sizeof (* closure ));
46+ closure -> details = details ;
4447}
4548
4649bool
@@ -106,6 +109,8 @@ main(int argc, char *argv[])
106109 struct sudo_debug_file debug_file ;
107110 const char * base , * shell = _PATH_SUDO_BSHELL ;
108111 struct intercept_closure closure = { 0 };
112+ struct command_details details = { 0 };
113+ int intercept_sv [2 ];
109114 const char * errstr ;
110115 sigset_t blocked , empty ;
111116 struct sigaction sa ;
@@ -145,20 +150,29 @@ main(int argc, char *argv[])
145150 if (sudo_debug_instance == SUDO_DEBUG_INSTANCE_ERROR )
146151 return EXIT_FAILURE ;
147152
148- /* Block SIGCHLD and SIGUSR during critical section. */
153+ /* Use socketpair to coordinate between parent and child. */
154+ if (socketpair (PF_UNIX , SOCK_STREAM , 0 , intercept_sv ) == -1 )
155+ sudo_fatal ("%s" , U_ ("unable to create sockets" ));
156+ if (fcntl (intercept_sv [0 ], F_SETFD , FD_CLOEXEC ) == -1 ||
157+ fcntl (intercept_sv [1 ], F_SETFD , FD_CLOEXEC ) == -1 ) {
158+ sudo_fatal ("%s" , U_ ("unable to create sockets" ));
159+ }
160+
161+ /* Block SIGCHLD during critical section. */
149162 sigemptyset (& empty );
150163 sigemptyset (& blocked );
151164 sigaddset (& blocked , SIGCHLD );
152- sigaddset (& blocked , SIGUSR1 );
153165 sigprocmask (SIG_BLOCK , & blocked , NULL );
154166
155- /* Signal handler sets a flag for SIGCHLD, nothing for SIGUSR1. */
167+ /* Avoid NULL deref of closure.details. */
168+ closure .details = & details ;
169+
170+ /* Signal handler sets a flag for SIGCHLD. */
156171 memset (& sa , 0 , sizeof (sa ));
157172 sigemptyset (& sa .sa_mask );
158173 sa .sa_flags = SA_RESTART ;
159174 sa .sa_handler = handler ;
160175 sigaction (SIGCHLD , & sa , NULL );
161- sigaction (SIGUSR1 , & sa , NULL );
162176
163177 /* Fork a shell. */
164178 my_pid = getpid ();
@@ -174,13 +188,16 @@ main(int argc, char *argv[])
174188 if (!set_exec_filter ())
175189 _exit (EXIT_FAILURE );
176190
177- /* Suspend child until tracer seizes control and sends SIGUSR1. */
178- sigsuspend (& empty );
191+ /* Child waits until tracer seizes control and sends SIGUSR1. */
192+ close (intercept_sv [0 ]);
193+ recv (intercept_sv [1 ], & ch , sizeof (ch ), 0 );
194+
179195 execl (shell , base , NULL );
180196 sudo_fatal ("execl" );
181197 default :
182198 /* Parent attaches to child and allows it to continue. */
183- if (exec_ptrace_seize (child ) == -1 )
199+ close (intercept_sv [1 ]);
200+ if (exec_ptrace_seize (child , intercept_sv [0 ]) == -1 )
184201 return EXIT_FAILURE ;
185202 break ;
186203 }
0 commit comments