[PATCH] fhandler_pipe: add sanity limit to handle loops

Takashi Yano takashi.yano@nifty.ne.jp
Sat Dec 25 17:10:10 GMT 2021


On Fri, 24 Dec 2021 21:40:24 -0800 (PST)
Jeremy Drake wrote:
> On Sat, 25 Dec 2021, Takashi Yano wrote:
> 
> > On Fri, 24 Dec 2021 19:47:46 -0800 (PST)
> > Jeremy Drake wrote:
> > > phi->NumberOfHandles = 7999168, n_handle = 256
> > > assertion "phi->NumberOfHandles <= n_handle" failed: file
> > > "../../.././winsup/cygwin/fhandler_pipe.cc", line 1280, function: void*
> > > fhandler_pipe::get_query_hdl_per_process(WCHAR*, OBJECT_NAME_INFORMATION*)
> > > Aborted
> >
> > What!? Could you please check value of the "status" ?
> 
> status = 0x00000000, phi->NumberOfHandles = 7286688, n_handle = 256
> assertion "phi->NumberOfHandles <= n_handle" failed: file
> "../../.././winsup/cygwin/fhandler_pipe.cc", line 1281, function: void*
> fhandler_pipe::get_query_hdl_per_process(WCHAR*, OBJECT_NAME_INFORMATION*)
> Aborted
> 
> > What version of windows do you use?
> 
> This was on Windows 11 (22000.376) on ARM64, but msys2 has started seeing
> similar hangs on Github's "windows-2022" runner.  I don't have one of
> those locally to test against however.  But if push came to shove, I think
> I downloaded a Server 2022 evaluation ISO, I could set up a VM and see
> what happens.

Could you please check the result of the following test case
in that ARM64 platform?

The following code can be compiled using mingw compiper with
-lntdll flag.

#include <windows.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <stdlib.h>
#include <stdio.h>

typedef enum
{
  ProcessHandleInformation = 51 /* Since Win8 */
} PROCESSINFOCLASS;

typedef struct
{
  HANDLE HandleValue;
  ULONG_PTR HandleCount;
  ULONG_PTR PointerCount;
  ULONG GrantedAccess;
  ULONG ObjectTypeIndex;
  ULONG HandleAttributes;
  ULONG Reserved;
} PROCESS_HANDLE_TABLE_ENTRY_INFO, *PPROCESS_HANDLE_TABLE_ENTRY_INFO;

typedef struct
{
  ULONG_PTR NumberOfHandles;
  ULONG_PTR Reserved;
  PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];
} PROCESS_HANDLE_SNAPSHOT_INFORMATION;


NTSTATUS NTAPI NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS,
  PVOID, ULONG, PULONG);

typedef enum
{
  SystemHandleInformation = 16
} SYSTEM_INFORMATION_CLASS;

typedef struct
{
  USHORT UniqueProcessId;
  USHORT CreatorBackTraceIndex;
  UCHAR ObjectTypeIndex;
  UCHAR HandleAttributes;
  USHORT HandleValue;
  PVOID Object;
  ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO;

typedef struct
{
  ULONG NumberOfHandles;
  SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION;

NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS,
  PVOID, ULONG, PULONG);

int main()
{
	NTSTATUS status;
	DWORD n_handle = 1;
	PROCESS_HANDLE_SNAPSHOT_INFORMATION *phi;
	do {
		DWORD nbytes = 2 * sizeof(ULONG_PTR)
			+ n_handle * sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO);
		phi = (PROCESS_HANDLE_SNAPSHOT_INFORMATION *)
			HeapAlloc(GetProcessHeap(), 0, nbytes);
		if (!phi) {
			fprintf(stderr, "HeapAlloc() Error: %08x\n", GetLastError());
			exit(1);
		}
		ULONG len;
		status = NtQueryInformationProcess(GetCurrentProcess(),
			ProcessHandleInformation, phi, nbytes, &len);
		if (NT_SUCCESS (status)) break;
		HeapFree(GetProcessHeap(), 0, phi);
		n_handle ++;
	} while (status == STATUS_INFO_LENGTH_MISMATCH);

	if (!NT_SUCCESS (status)) {
		fprintf(stderr, "NtQueryInformationProcess() error: %08x\n", status);
		HeapFree(GetProcessHeap(), 0, phi);
		exit(1);
	}

	printf("per_process: n_handle=%d, NumberOfHandles=%d\n",
		n_handle, phi->NumberOfHandles);
	if (phi->NumberOfHandles > n_handle) {
		HeapFree(GetProcessHeap(), 0, phi);
		exit(1);
	}
	HeapFree(GetProcessHeap(), 0, phi);


	n_handle = 1;
	SYSTEM_HANDLE_INFORMATION *shi;
	do {
		SIZE_T nbytes = sizeof(ULONG)
			+ n_handle * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
		shi = (SYSTEM_HANDLE_INFORMATION *) HeapAlloc (GetProcessHeap(),
			0, nbytes);
		if (!shi) {
			fprintf(stderr, "HeapAlloc() Error: %08x\n", GetLastError());
			exit(1);
		}
		status = NtQuerySystemInformation(SystemHandleInformation,
			shi, nbytes, NULL);
		if (NT_SUCCESS(status)) break;
		HeapFree (GetProcessHeap(), 0, shi);
		n_handle *= 2;
	} while (status == STATUS_INFO_LENGTH_MISMATCH);
	
	if (!NT_SUCCESS (status)) {
		fprintf(stderr, "NtQuerySystemInformation() error: %08x\n", status);
		HeapFree(GetProcessHeap(), 0, shi);
		exit(1);
	}

	printf("per_system: n_handle=%d, NumberOfHandles=%d\n",
		n_handle, shi->NumberOfHandles);
	if (shi->NumberOfHandles > n_handle) {
		HeapFree(GetProcessHeap(), 0, shi);
		exit(1);
	}
	HeapFree(GetProcessHeap(), 0, shi);

	return 0;
}

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>


More information about the Cygwin-patches mailing list