Skip to content

Commit 15dcee8

Browse files
authored
Merge e80e2c0 into cb2fa50
2 parents cb2fa50 + e80e2c0 commit 15dcee8

7 files changed

Lines changed: 741 additions & 246 deletions

File tree

NEWS.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ but the `nutshutdown` script would bail out quickly and quietly. [PR #3008]
143143
in other programs. Extended public API of libupsclient and libnutscan
144144
to diligently arrange debug-logging when at run-time those libraries
145145
actually have different copies of the methods and data involved. [#3378]
146+
* Revised 'dstate' machinery to track socket connections closed mid-way
147+
through a call, to avoid access after `free()`. [#3302]
146148

147149
- NUT for Windows specific updates:
148150
* Revised detection of (relative) paths to program and configuration files

common/wincompat.c

Lines changed: 109 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,10 @@ int win_system(const char * command)
401401
si.cb = sizeof(si);
402402
memset(&pi,0,sizeof(pi));
403403

404+
upsdebugx(4, "%s: calling CreateProcess: %s", __func__, NUT_STRARG(command));
404405
res = CreateProcess(NULL,(char *)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
405406

406-
if( res != 0 ) {
407+
if (res != 0) {
407408
return 0;
408409
}
409410

@@ -441,14 +442,17 @@ char * filter_path(const char * source)
441442
of chars containing the message to display (no terminal 0 required here) */
442443
void syslog(int priority, const char *fmt, ...)
443444
{
444-
char pipe_name[] = "\\\\.\\pipe\\"EVENTLOG_PIPE_NAME;
445+
/* At least while this is not configurable, can be static to speed up;
446+
* see https://github.com/networkupstools/nut/issues/3375
447+
*/
448+
static char pipe_full_name[] = "\\\\.\\pipe\\"EVENTLOG_PIPE_NAME;
445449
char buf1[LARGEBUF+sizeof(DWORD)];
446450
char buf2[LARGEBUF];
447451
va_list ap;
448452
HANDLE pipe;
449453
DWORD bytesWritten = 0;
450454

451-
if( EventLogName == NULL ) {
455+
if (EventLogName == NULL) {
452456
return;
453457
}
454458

@@ -462,38 +466,45 @@ void syslog(int priority, const char *fmt, ...)
462466

463467
/* Create the frame */
464468
/* first 4 bytes are priority */
465-
memcpy(buf1,&priority,sizeof(DWORD));
469+
memcpy(buf1, &priority, sizeof(DWORD));
466470
/* then comes the message */
467-
memcpy(buf1+sizeof(DWORD),buf2,sizeof(buf2));
471+
memcpy(buf1+sizeof(DWORD), buf2, sizeof(buf2));
468472

473+
upsdebugx(6, "%s: posting to event log NAMED_PIPE: '%s'", __func__, pipe_full_name);
469474
pipe = CreateFile(
470-
pipe_name, /* pipe name */
471-
GENERIC_WRITE,
472-
0, /* no sharing */
473-
NULL, /* default security attributes FIXME */
474-
OPEN_EXISTING, /* opens existing pipe */
475-
FILE_FLAG_OVERLAPPED, /* enable async IO */
476-
NULL); /* no template file */
477-
475+
pipe_full_name, /* pipe name */
476+
GENERIC_WRITE,
477+
0, /* no sharing */
478+
NULL, /* default security attributes FIXME */
479+
OPEN_EXISTING, /* opens existing pipe */
480+
FILE_FLAG_OVERLAPPED, /* enable async IO */
481+
NULL); /* no template file */
478482

479483
if (pipe == INVALID_HANDLE_VALUE) {
484+
upsdebug_with_errno(1,
485+
"%s: SKIP: can't open existing event log NAMED_PIPE: '%s'",
486+
__func__, pipe_full_name);
487+
480488
return;
481489
}
482490

483-
WriteFile (pipe,buf1,strlen(buf2)+sizeof(DWORD),&bytesWritten,NULL);
491+
WriteFile (pipe, buf1, strlen(buf2)+sizeof(DWORD), &bytesWritten, NULL);
484492

485493
/* testing result is useless. If we have an error and try to report it,
486494
* this will probably lead to a call to this function and an infinite
487495
* loop */
496+
upsdebugx(6, "%s: closing event log NAMED_PIPE", __func__);
488497
CloseHandle(pipe);
489498
}
490499

491500
/* Signal emulation via NamedPipe */
492501

493502
static HANDLE pipe_connection_handle;
503+
static const char *named_pipe_name=NULL;
504+
505+
/* Note these are shared (upsd, upsmon, nut.exe...) for other named pipe uses as well */
494506
OVERLAPPED pipe_connection_overlapped;
495507
pipe_conn_t *pipe_connhead = NULL;
496-
static const char *named_pipe_name=NULL;
497508

498509
void pipe_create(const char * pipe_name)
499510
{
@@ -516,19 +527,20 @@ void pipe_create(const char * pipe_name)
516527
if( pipe_connection_overlapped.hEvent != 0 ) {
517528
CloseHandle(pipe_connection_overlapped.hEvent);
518529
}
519-
memset(&pipe_connection_overlapped,0,sizeof(pipe_connection_overlapped));
530+
memset(&pipe_connection_overlapped, 0, sizeof(pipe_connection_overlapped));
531+
upsdebugx(2, "%s: creating NAMED_PIPE (listener): '%s'", __func__, pipe_full_name);
520532
pipe_connection_handle = CreateNamedPipe(
521-
pipe_full_name,
522-
PIPE_ACCESS_INBOUND | /* to server only */
523-
FILE_FLAG_OVERLAPPED, /* async IO */
524-
PIPE_TYPE_MESSAGE |
525-
PIPE_READMODE_MESSAGE |
526-
PIPE_WAIT,
527-
PIPE_UNLIMITED_INSTANCES, /* max. instances */
528-
LARGEBUF, /* output buffer size */
529-
LARGEBUF, /* input buffer size */
530-
0, /* client time-out */
531-
NULL); /* FIXME: default security attribute */
533+
pipe_full_name,
534+
PIPE_ACCESS_INBOUND /* to server only */
535+
| FILE_FLAG_OVERLAPPED, /* async IO */
536+
PIPE_TYPE_MESSAGE
537+
| PIPE_READMODE_MESSAGE
538+
| PIPE_WAIT,
539+
PIPE_UNLIMITED_INSTANCES, /* max. instances */
540+
LARGEBUF, /* output buffer size */
541+
LARGEBUF, /* input buffer size */
542+
0, /* client time-out */
543+
NULL); /* FIXME: default security attribute */
532544

533545
if (pipe_connection_handle == INVALID_HANDLE_VALUE) {
534546
upslogx(LOG_ERR, "Error creating named pipe");
@@ -537,19 +549,21 @@ void pipe_create(const char * pipe_name)
537549
}
538550

539551
/* Prepare an async wait on a connection on the pipe */
540-
pipe_connection_overlapped.hEvent = CreateEvent(NULL, /*Security*/
541-
FALSE, /* auto-reset*/
542-
FALSE, /* inital state = non signaled*/
543-
NULL /* no name*/);
544-
if(pipe_connection_overlapped.hEvent == NULL ) {
552+
pipe_connection_overlapped.hEvent = CreateEvent(
553+
NULL, /* Security */
554+
FALSE, /* auto-reset */
555+
FALSE, /* initial state = non signaled */
556+
NULL /* no name */
557+
);
558+
if (pipe_connection_overlapped.hEvent == NULL) {
545559
upslogx(LOG_ERR, "Error creating event");
546560
fatal_with_errno(EXIT_FAILURE, "Can't create event");
547561
}
548562

549563
/* Wait for a connection */
550-
ret = ConnectNamedPipe(pipe_connection_handle,&pipe_connection_overlapped);
551-
if(ret == 0 && GetLastError() != ERROR_IO_PENDING ) {
552-
upslogx(LOG_ERR,"ConnectNamedPipe error");
564+
ret = ConnectNamedPipe(pipe_connection_handle, &pipe_connection_overlapped);
565+
if (ret == 0 && GetLastError() != ERROR_IO_PENDING) {
566+
upslogx(LOG_ERR, "ConnectNamedPipe error");
553567
}
554568
}
555569

@@ -558,22 +572,31 @@ void pipe_connect()
558572
/* We have detected a connection on the opened pipe. So we start by saving its handle and create a new pipe for future connections */
559573
pipe_conn_t *conn;
560574

561-
conn = xcalloc(1,sizeof(*conn));
575+
/* TOTHINK: Here we seem to have assumptions about a general connection
576+
* via overlapped I/O being the signal to daemon (via named_pipe_name)...
577+
* might this conflict with other I/Os (driver/server sockets, dummy-ups
578+
* files, etc.)?
579+
*/
580+
upsdebugx(3, "%s: handle incoming connection on NAMED PIPE", __func__);
581+
conn = xcalloc(1, sizeof(*conn));
562582
conn->handle = pipe_connection_handle;
563583

564584
/* restart a new listening pipe */
565585
pipe_create(NULL);
566586

567587
/* A new pipe waiting for new client connection has been created. We could manage the current connection now */
568588
/* Start a read operation on the newly connected pipe so we could wait on the event associated to this IO */
569-
memset(&conn->overlapped,0,sizeof(conn->overlapped));
570-
memset(conn->buf,0,sizeof(conn->buf));
571-
conn->overlapped.hEvent = CreateEvent(NULL, /*Security*/
572-
FALSE, /* auto-reset*/
573-
FALSE, /* inital state = non signaled*/
574-
NULL /* no name*/);
575-
if(conn->overlapped.hEvent == NULL ) {
576-
upslogx(LOG_ERR,"Can't create event for reading event log");
589+
memset(&conn->overlapped, 0, sizeof(conn->overlapped));
590+
memset(conn->buf, 0, sizeof(conn->buf));
591+
conn->overlapped.hEvent = CreateEvent(
592+
NULL, /* Security */
593+
FALSE, /* auto-reset */
594+
FALSE, /* initial state = non signaled */
595+
NULL /* no name */
596+
);
597+
if (conn->overlapped.hEvent == NULL) {
598+
/* FIXME: Is this (still) about event log only? */
599+
upslog_with_errno(LOG_ERR, "Can't create event for reading event log");
577600
return;
578601
}
579602

@@ -591,19 +614,24 @@ void pipe_connect()
591614

592615
void pipe_disconnect(pipe_conn_t *conn)
593616
{
594-
if( conn->overlapped.hEvent != INVALID_HANDLE_VALUE) {
617+
upsdebugx(3, "%s: starting", __func__);
618+
619+
if (conn->overlapped.hEvent != INVALID_HANDLE_VALUE) {
620+
upsdebugx(4, "%s: calling CloseHandle() for conn->overlapped.hEvent", __func__);
595621
CloseHandle(conn->overlapped.hEvent);
596622
conn->overlapped.hEvent = INVALID_HANDLE_VALUE;
597623
}
598-
if( conn->handle != INVALID_HANDLE_VALUE) {
599-
if ( DisconnectNamedPipe(conn->handle) == 0 ) {
600-
upslogx(LOG_ERR,
601-
"DisconnectNamedPipe error : %d",
602-
(int)GetLastError());
624+
625+
if (conn->handle != INVALID_HANDLE_VALUE) {
626+
upsdebugx(4, "%s: calling DisconnectNamedPipe() for not-yet-invalid conn->handle", __func__);
627+
if (DisconnectNamedPipe(conn->handle) == 0) {
628+
upslog_with_errno(LOG_ERR, "DisconnectNamedPipe failed");
603629
}
630+
upsdebugx(4, "%s: calling CloseHandle() for conn->handle", __func__);
604631
CloseHandle(conn->handle);
605632
conn->handle = INVALID_HANDLE_VALUE;
606633
}
634+
607635
if (conn->prev) {
608636
conn->prev->next = conn->next;
609637
} else {
@@ -625,8 +653,8 @@ int pipe_ready(pipe_conn_t *conn)
625653
BOOL res;
626654

627655
res = GetOverlappedResult(conn->handle, &conn->overlapped, &bytesRead, FALSE);
628-
if( res == 0 ) {
629-
upslogx(LOG_ERR, "Pipe read error");
656+
if (res == 0) {
657+
upslog_with_errno(LOG_ERR, "Pipe read error");
630658
pipe_disconnect(conn);
631659
return 0;
632660
}
@@ -639,31 +667,37 @@ int send_to_named_pipe(const char * pipe_name, const char * data)
639667
HANDLE pipe;
640668
BOOL result = FALSE;
641669
DWORD bytesWritten = 0;
642-
char buf[SMALLBUF];
670+
char pipe_full_name[NUT_PATH_MAX + 1];
643671

644-
snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", pipe_name);
672+
snprintf(pipe_full_name, sizeof(pipe_full_name), "\\\\.\\pipe\\%s", pipe_name);
645673

674+
upsdebugx(6, "%s: posting to NAMED_PIPE: '%s'", __func__, pipe_full_name);
646675
pipe = CreateFile(
647-
buf,
648-
GENERIC_WRITE,
649-
0, /* no sharing */
650-
NULL, /* default security attributes FIXME */
651-
OPEN_EXISTING, /* opens existing pipe */
652-
FILE_FLAG_OVERLAPPED, /* enable async IO */
653-
NULL); /* no template file */
654-
676+
pipe_full_name,
677+
GENERIC_WRITE,
678+
0, /* no sharing */
679+
NULL, /* default security attributes FIXME */
680+
OPEN_EXISTING, /* opens existing pipe */
681+
FILE_FLAG_OVERLAPPED, /* enable async IO */
682+
NULL); /* no template file */
655683

656684
if (pipe == INVALID_HANDLE_VALUE) {
685+
upsdebug_with_errno(1,
686+
"%s: SKIP: can't open existing NAMED_PIPE: '%s'",
687+
__func__, pipe_full_name);
688+
657689
return 1;
658690
}
659691

660692
result = WriteFile (pipe,data,strlen(data)+1,&bytesWritten,NULL);
661693

662694
if (result == 0 || bytesWritten != strlen(data)+1 ) {
695+
upsdebug_with_errno(6, "%s: closing event log NAMED_PIPE, did not write as much as expected to", __func__);
663696
CloseHandle(pipe);
664697
return 1;
665698
}
666699

700+
upsdebugx(6, "%s: closing event log NAMED_PIPE", __func__);
667701
CloseHandle(pipe);
668702
return 0;
669703
}
@@ -723,7 +757,12 @@ int w32_getcomm ( serial_handler_t * h, int * flags )
723757
void overlapped_setup (serial_handler_t * sh)
724758
{
725759
memset (&sh->io_status, 0, sizeof (sh->io_status));
726-
sh->io_status.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
760+
sh->io_status.hEvent = CreateEvent (
761+
NULL, /* Security */
762+
TRUE, /* auto-reset */
763+
FALSE, /* initial state = non signaled */
764+
NULL /* no name */
765+
);
727766
sh->overlapped_armed = 0;
728767
}
729768

@@ -873,7 +912,12 @@ int w32_serial_write (serial_handler_t * sh, const void *ptr, size_t len)
873912
errno = 0;
874913

875914
memset (&write_status, 0, sizeof (write_status));
876-
write_status.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
915+
write_status.hEvent = CreateEvent (
916+
NULL, /* Security */
917+
TRUE, /* auto-reset */
918+
FALSE, /* initial state = non signaled */
919+
NULL /* no name */
920+
);
877921

878922
for (;;)
879923
{
@@ -923,7 +967,7 @@ serial_handler_t * w32_serial_open (const char *name, int flags)
923967
memset(sh,0,sizeof(serial_handler_t));
924968

925969
sh->handle = CreateFile(name,
926-
GENERIC_READ|GENERIC_WRITE,
970+
GENERIC_READ | GENERIC_WRITE,
927971
0, 0, OPEN_EXISTING,
928972
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
929973
0);

0 commit comments

Comments
 (0)