@@ -132,6 +132,7 @@ ds_ipc_alloc (
132
132
133
133
instance -> overlap .hEvent = INVALID_HANDLE_VALUE ;
134
134
instance -> pipe = INVALID_HANDLE_VALUE ;
135
+ instance -> owningPipe = INVALID_HANDLE_VALUE ;
135
136
136
137
if (ipc_name ) {
137
138
characters_written = sprintf_s (
@@ -350,14 +351,27 @@ ds_ipc_listen (
350
351
351
352
EP_ASSERT (ipc -> pipe == INVALID_HANDLE_VALUE );
352
353
354
+ DWORD creationFlags = PIPE_ACCESS_DUPLEX // read/write access
355
+ | FILE_FLAG_OVERLAPPED ; // async listening.
356
+
357
+ bool ensure_pipe_creation = ipc -> owningPipe == INVALID_HANDLE_VALUE ;
358
+ if (ensure_pipe_creation )
359
+ {
360
+ // Fail if we can't own pipe. Other than manually iterating the DACL,
361
+ // this is the only way to ensure ownership of the pipe via creation,
362
+ // and by extension that it has the default DACL.
363
+ // Otherwise, Windows treats this as a FIFO queue get-or-create
364
+ // request and we might end up with DACLs set by other creators.
365
+ creationFlags |= FILE_FLAG_FIRST_PIPE_INSTANCE ;
366
+ }
367
+
353
368
const uint32_t in_buffer_size = 16 * 1024 ;
354
369
const uint32_t out_buffer_size = 16 * 1024 ;
355
370
356
371
DS_ENTER_BLOCKING_PAL_SECTION ;
357
372
ipc -> pipe = CreateNamedPipeA (
358
373
ipc -> pipe_name , // pipe name
359
- PIPE_ACCESS_DUPLEX | // read/write access
360
- FILE_FLAG_OVERLAPPED , // async listening
374
+ creationFlags ,
361
375
PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS , // message type pipe, message-read and blocking mode
362
376
PIPE_UNLIMITED_INSTANCES , // max. instances
363
377
out_buffer_size , // output buffer size
@@ -372,6 +386,25 @@ ds_ipc_listen (
372
386
ep_raise_error ();
373
387
}
374
388
389
+ if (ensure_pipe_creation )
390
+ {
391
+ // Dupe the handle and hang it off the IPC to ensure EP ownership for process duration.
392
+ bool createdSentinel = DuplicateHandle (
393
+ GetCurrentProcess (),
394
+ ipc -> pipe ,
395
+ GetCurrentProcess (),
396
+ & (ipc -> owningPipe ),
397
+ 0 ,
398
+ FALSE,
399
+ DUPLICATE_SAME_ACCESS );
400
+ if (!createdSentinel )
401
+ {
402
+ if (callback )
403
+ callback ("Failed to ownership sentinel." , GetLastError ());
404
+ ep_raise_error ();
405
+ }
406
+ }
407
+
375
408
EP_ASSERT (ipc -> overlap .hEvent == INVALID_HANDLE_VALUE );
376
409
377
410
ipc -> overlap .hEvent = CreateEventW (NULL , true, false, NULL );
@@ -458,6 +491,9 @@ ds_ipc_accept (
458
491
CloseHandle (ipc -> overlap .hEvent );
459
492
memset (& ipc -> overlap , 0 , sizeof (OVERLAPPED )); // clear the overlapped objects state
460
493
ipc -> overlap .hEvent = INVALID_HANDLE_VALUE ;
494
+ // We explicitly leave the ownership pipe handle untouched to root the IPC as long as the pipe has
495
+ // been bound to our process.
496
+ EP_ASSERT (ipc -> owningPipe != INVALID_HANDLE_VALUE );
461
497
462
498
ep_raise_error_if_nok (ds_ipc_listen (ipc , callback ));
463
499
@@ -534,6 +570,21 @@ ds_ipc_close (
534
570
{
535
571
EP_ASSERT (ipc != NULL );
536
572
573
+ // Always clean this resource - even on shutdown - since
574
+ // it roots resources accross embedding scenarios.
575
+ if (ipc -> owningPipe != INVALID_HANDLE_VALUE ) {
576
+ // Explicitly don't reset ownership if we fail to close.
577
+ // It gives us a diagnostic crumble.
578
+ if (CloseHandle (ipc -> owningPipe ) == TRUE) {
579
+ ipc -> owningPipe = INVALID_HANDLE_VALUE ;
580
+ }
581
+ else {
582
+ if (callback ) {
583
+ callback ("Failed to IPC ownership sentinel handle" , GetLastError ());
584
+ }
585
+ }
586
+ }
587
+
537
588
// don't attempt cleanup on shutdown and let the OS handle it
538
589
if (is_shutdown ) {
539
590
if (callback )
0 commit comments