Segfault if /proc/PID/maps is opened in parallel threads [CAUSE: RtlQueryProcessDebugInformation]

Christian Franke Christian.Franke@t-online.de
Wed Jul 2 14:18:13 GMT 2025


On Tue, 27 May 2025 17:44:10 +0200 Christian Franke wrote:
> On Sun, 25 May 2025 16:46:49 +0200, Christian Franke wrote:
>> On Sat, 24 May 2025 15:19:10 +0200, Christian Franke wrote:
>>> If /proc/PID/maps is opened in parallel threads, the process PID may 
>>> segfault.
>>>
>>> Testcase:
>>>
>>> ...
>>>
>>> Problem is not reproducible with any of the other /proc/PID/* files.
>>>
>>
>> A closer look shows that the problem is unrelated to thread safety. 
>> The segfault also occurs when the following command is run 
>> simultaneously in two terminals:
>>
>> $ while cat /proc/1234/maps > /dev/null; do printf .; done
>> .............cat: /proc/1234/maps: No such file or directory
>>
>
> The root of the problem is the call of 
> RtlQueryProcessDebugInformation() here:
> https://cygwin.com/git/?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/fhandler/process.cc;h=8fae9be5#l630 
>
>
> If this part is removed, the segfault does no longer occur. Then 
> /proc/PID/maps still work but the "[win heap ...]" information is 
> missing. No patch provided because I don't know whether this could 
> possibly be fixed without removing this functionality.
>
> A test with a separate test program shows that the problem is 
> unrelated to Cygwin: Parallel calls to 
> RtlQueryProcessDebugInformation() with the same PID could be used to 
> crash this process. It also "worked" with Notepad.exe.
>
> Possible Windows (Version 10.0.22631.5039) bug?
>

Testcase (attached):

$ gcc -o querydebug querydebug.c -lntdll

$ sleep 3600 &
[1] 3940

$ ps -p 3940
       PID    PPID    PGID     WINPID   TTY         UID    STIME COMMAND
      3940    1379    3940      18036  pty0      197609 15:52:50 
/usr/bin/sleep

$ while ./querydebug 18036; do printf .; done & \
while ./querydebug 18036; do printf +; done
[2] 3943
.+.+.+.+.+RtlQueryProcessDebugInformation(): NTSTATUS = 0xC0000005
+RtlQueryProcessDebugInformation(): NTSTATUS = 0xC000000B
[1]-  Done                    sleep 3600
[2]+  Done                   while ./querydebug ...


Conclusion: Possible Windows bug in RtlQueryProcessDebugInformation(). 
Cygwin should not use this function to provide "nice to have" types of 
information like "[win heap...]" if this may crash the target process.

-- 
Regards,
Christian

-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

// From ntdll.h
typedef struct { int dummy; } *PDEBUG_BUFFER;
PDEBUG_BUFFER RtlCreateQueryDebugBuffer (ULONG, BOOLEAN);
NTSTATUS RtlQueryProcessDebugInformation (ULONG, ULONG, PDEBUG_BUFFER);
NTSTATUS RtlDestroyQueryDebugBuffer (PDEBUG_BUFFER);
#define PDI_HEAPS 0x04
#define PDI_HEAP_BLOCKS 0x10
// From ntdll.h end

int main(int argc, char **argv)
{
  if (argc != 2) {
    printf("Usage: %s WINPID\n", argv[0]); return 1;
  }
  int pid = atoi(argv[1]);
  PDEBUG_BUFFER buf = RtlCreateQueryDebugBuffer(0x100000, FALSE);
  if (!buf) {
    printf("RtlCreateQueryDebugBuffer(): failed\n"); return 1;
  }
  NTSTATUS s = RtlQueryProcessDebugInformation(pid,
                 PDI_HEAPS | PDI_HEAP_BLOCKS, buf);
  RtlDestroyQueryDebugBuffer(buf);
  if (s < 0) {
    // Observed:
    // STATUS_ACCESS_VIOLATION (0xC0000005)
    // STATUS_INVALID_CID (0xC000000B)
    // STATUS_PROCESS_IS_TERMINATING (0xC000010A)
    printf("RtlQueryProcessDebugInformation(): NTSTATUS = 0x%X\n", s);
    return 1;
  }
  return 0;
}


More information about the Cygwin mailing list