common,w32: Breakaway detached childs when in job
authorAndre Heinecke <aheinecke@gnupg.org>
Mon, 29 Apr 2019 06:54:39 +0000 (08:54 +0200)
committerAndre Heinecke <aheinecke@gnupg.org>
Mon, 29 Apr 2019 06:54:39 +0000 (08:54 +0200)
* common/exechelp-w32.c (gnupg_spawn_process_detached): Add
CREATE_BREAKAWAY_FROM_JOB creation flag if required.

--
When the gpg process is assigned to a W32 "Job" the
child processes are killed once the Job is finished.
As we want our detached processes to linger e.g.
gpg-agent the breakaway flag is required in
that case.

GnuPG-Bug-Id: T4333

Thanks to Jan Echternach for reporting this and providing
a patch.

Signed-off-by: Andre Heinecke <aheinecke@gnupg.org>
common/exechelp-w32.c

index 86b1d68..ea158a3 100644 (file)
@@ -856,6 +856,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
   STARTUPINFO si;
   int cr_flags;
   char *cmdline;
+  BOOL in_job = FALSE;
 
 
   /* We don't use ENVP.  */
@@ -884,6 +885,50 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
               | GetPriorityClass (GetCurrentProcess ())
               | CREATE_NEW_PROCESS_GROUP
               | DETACHED_PROCESS);
+
+  /* Check if we were spawned as part of a Job.
+   * In a job we need to add CREATE_BREAKAWAY_FROM_JOB
+   * to the cr_flags, otherwise our child processes
+   * are killed when we terminate. */
+  if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
+    {
+      log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
+      in_job = FALSE;
+    }
+
+  if (in_job)
+    {
+      /* Only try to break away from job if it is allowed, otherwise
+       * CreateProcess() would fail with an "Access is denied" error. */
+      JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+      if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
+                                      &info, sizeof info, NULL))
+        {
+          log_error ("QueryInformationJobObject() failed: %s\n",
+                     w32_strerror (-1));
+        }
+      else if ((info.BasicLimitInformation.LimitFlags &
+                JOB_OBJECT_LIMIT_BREAKAWAY_OK))
+        {
+          log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
+          cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
+        }
+      else if ((info.BasicLimitInformation.LimitFlags &
+                JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
+        {
+          /* The child process should automatically detach from the job. */
+          log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
+                     "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
+        }
+      else
+        {
+          /* It seems that the child process must remain in the job.
+           * This is not necessarily an error, although it can cause premature
+           * termination of the child process when the job is closed. */
+          log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
+        }
+    }
+
 /*   log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
 /*              pgmname, cmdline); */
   if (!CreateProcess (pgmname,       /* Program to start.  */