util: Ensure debugger is not started until it is allowed to attach
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Sun, 11 Apr 2021 22:23:20 +0000 (10:23 +1200)
committerAndreas Schneider <asn@cryptomilk.org>
Tue, 20 Apr 2021 12:33:40 +0000 (12:33 +0000)
Use a pipe to ensure that the debugger is not started until after the
prctl() call allowing it to attach to the parent, avoiding a potential
race condition.

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Tue Apr 20 12:33:40 UTC 2021 on sn-devel-184

lib/util/util.c

index b175b22cf13d664ed081d9d06704109470d00d37..7eee60b85cd200bc3456f9f2cb829fbe8814550f 100644 (file)
@@ -1166,27 +1166,56 @@ void anonymous_shared_free(void *ptr)
 */
 void samba_start_debugger(void)
 {
-       pid_t pid = fork();
-       if (pid == -1) {
-               return;
-       } else if (pid) {
+       int ready_pipe[2];
+       char c;
+       int ret;
+       pid_t pid;
+
+       ret = pipe(ready_pipe);
+       SMB_ASSERT(ret == 0);
+
+       pid = fork();
+       SMB_ASSERT(pid >= 0);
+
+       if (pid) {
+               c = 0;
+
+               ret = close(ready_pipe[0]);
+               SMB_ASSERT(ret == 0);
 #if defined(HAVE_PRCTL) && defined(PR_SET_PTRACER)
                /*
                 * Make sure the child process can attach a debugger.
+                *
+                * We don't check the error code as the debugger
+                * will tell us if it can't attach.
                 */
-               prctl(PR_SET_PTRACER, pid, 0, 0, 0);
+               (void)prctl(PR_SET_PTRACER, pid, 0, 0, 0);
 #endif
+               ret = write(ready_pipe[1], &c, 1);
+               SMB_ASSERT(ret == 1);
+
+               ret = close(ready_pipe[1]);
+               SMB_ASSERT(ret == 0);
+
+               /* Wait for gdb to attach. */
                sleep(2);
        } else {
                char *cmd = NULL;
 
-               if (asprintf(&cmd, "gdb --pid %u", getppid()) == -1) {
-                       _exit(EXIT_FAILURE);
-               }
+               ret = close(ready_pipe[1]);
+               SMB_ASSERT(ret == 0);
+
+               ret = read(ready_pipe[0], &c, 1);
+               SMB_ASSERT(ret == 1);
+
+               ret = close(ready_pipe[0]);
+               SMB_ASSERT(ret == 0);
+
+               ret = asprintf(&cmd, "gdb --pid %u", getppid());
+               SMB_ASSERT(ret != -1);
 
                execlp("xterm", "xterm", "-e", cmd, (char *) NULL);
-               free(cmd);
-               _exit(errno);
+               smb_panic("execlp() failed");
        }
 }
 #endif