Merge pull request #2719 from matt335672/log_xrdp_termination_signal

Log xrdp termination signals
This commit is contained in:
matt335672
2023-07-31 11:24:20 +01:00
committed by GitHub
9 changed files with 370 additions and 9 deletions
+145
View File
@@ -21,6 +21,7 @@
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
@@ -1143,3 +1144,147 @@ g_charstr_to_bitmask(const char *str, const struct bitmask_char bitdefs[],
return bitmask;
}
/*****************************************************************************/
/*
* Looks for a simple mapping of signal number to name
*/
static const char *
find_sig_name(int signum)
{
typedef struct
{
int num;
const char *name;
} sig_to_name_type;
// Map a string 'zzz' to { SIGzzz, "zzz"} for making
// typo-free sig_to_name_type objects
# define DEFSIG(sig) { SIG ## sig, # sig }
// Entries in this array are taken from
// The Single UNIX ® Specification, Version 2 (1997)
// plus additions from specific operating systems.
//
// The SUS requires these to be positive integer constants with a
// macro definition. Note that SIGRTMIN and SIGRTMAX on Linux are
// NOT constants, so have to be handled separately.
static const sig_to_name_type sigmap[] =
{
// Names from SUS v2, in the order they are listed in that document
// that *should* be defined everywhere
//
// Commented out definitions below are NOT used everywhere
DEFSIG(ABRT), DEFSIG(ALRM), DEFSIG(FPE), DEFSIG(HUP),
DEFSIG(ILL), DEFSIG(INT), DEFSIG(KILL), DEFSIG(PIPE),
DEFSIG(QUIT), DEFSIG(SEGV), DEFSIG(TERM), DEFSIG(USR1),
DEFSIG(USR2), DEFSIG(CHLD), DEFSIG(CONT), DEFSIG(STOP),
DEFSIG(TSTP), DEFSIG(TTIN), DEFSIG(TTOU), DEFSIG(BUS),
/* DEFSIG(POLL), */ /* DEFSIG(PROF), */ DEFSIG(SYS), DEFSIG(TRAP),
DEFSIG(URG), DEFSIG(VTALRM), DEFSIG(XCPU), DEFSIG(XFSZ),
// SIGPOLL and SIGPROF are marked as obselescent in 1003.1-2017,
// Also SIGPOLL isn't in *BSD operating systems which use SIGIO
#ifdef SIGPOLL
DEFSIG(POLL),
#endif
#ifdef SIGPROF
DEFSIG(PROF),
#endif
// BSD signals (from FreeBSD/OpenBSD sys/signal.h and
// Darwin/Illumos signal.h)
#ifdef SIGEMT
DEFSIG(EMT),
#endif
#ifdef SIGIO
DEFSIG(IO),
#endif
#ifdef SIGWINCH
DEFSIG(WINCH),
#endif
#ifdef SIGINFO
DEFSIG(INFO),
#endif
#ifdef SIGTHR
DEFSIG(THR),
#endif
#ifdef SIGLIBRT
DEFSIG(LIBRT),
#endif
#ifdef SIGPWR
DEFSIG(PWR),
#endif
#ifdef SIGWAITING
DEFSIG(WAITING),
#endif
#ifdef SIGLWP
DEFSIG(LWP),
#endif
// Linux additions to *BSD (signal(7))
#ifdef SIGLOST
DEFSIG(LOST),
#endif
#ifdef SIGSTKFLT
DEFSIG(STKFLT),
#endif
// Terminator
{0, NULL}
#undef DEFSIG
};
const sig_to_name_type *p;
for (p = &sigmap[0] ; p->name != NULL ; ++p)
{
if (p->num == signum)
{
return p->name;
}
}
// These aren't constants on Linux
#ifdef SIGRTMIN
if (signum == SIGRTMIN)
{
return "RTMIN";
}
#endif
#ifdef SIGRTMAX
if (signum == SIGRTMAX)
{
return "RTMAX";
}
#endif
return NULL;
}
/*****************************************************************************/
char *
g_sig2text(int signum, char sigstr[])
{
if (signum >= 0)
{
const char *name = find_sig_name(signum);
if (name != NULL)
{
g_snprintf(sigstr, MAXSTRSIGLEN, "SIG%s", name);
return sigstr;
}
#if defined(SIGRTMIN) && defined(SIGRTMAX)
if (signum > SIGRTMIN && signum < SIGRTMAX)
{
g_snprintf(sigstr, MAXSTRSIGLEN, "SIGRTMIN+%d", signum - SIGRTMIN);
return sigstr;
}
#endif
}
// If all else fails...
g_snprintf(sigstr, MAXSTRSIGLEN, "SIG#%d", signum);
return sigstr;
}
+34
View File
@@ -67,6 +67,26 @@ struct bitmask_char
#define BITMASK_CHAR_END_OF_LIST { 0, '\0' }
enum
{
// See g_sig2text()
// Must be able to hold "SIG#%d" for INT_MIN
//
// ((sizeof(int) * 5 + 1) / 2) provides a very slight overestimate of
// the bytes requires to store a decimal expansion of 'int':-
// sizeof INT_MAX display bytes ((sizeof(int) * 5 + 1)
// (int) needed / 2)
// ------ ------- ------------- ---------------------------
// 1 127 3 3
// 2 32767 5 5
// 3 8388607 7 8
// 4 2147483637 10 10
// 8 9*(10**18) 19 20
// 16 2*(10**38) 39 40
// 32 6*(10**76) 77 80
MAXSTRSIGLEN = (3 + 1 + 1 + ((sizeof(int) * 5 + 1) / 2) + 1)
};
/**
* Processes a format string for general info
*
@@ -266,6 +286,7 @@ int g_strncmp_d(const char *c1, const char *c2, const char delim, int len);
int g_strcasecmp(const char *c1, const char *c2);
int g_strncasecmp(const char *c1, const char *c2, int len);
int g_atoi(const char *str);
/**
* Extends g_atoi(), Converts decimal and hexadecimal number String to integer
*
@@ -283,4 +304,17 @@ char *g_strstr(const char *haystack, const char *needle);
int g_mbstowcs(twchar *dest, const char *src, int n);
int g_wcstombs(char *dest, const twchar *src, int n);
int g_strtrim(char *str, int trim_flags);
/**
* Maps a signal number to a string, i.e. SIGHUP -> "SIGHUP"
*
* @param signum Signal number
* @param sigstr buffer for result
* @return sigstr, for convenience
*
* Buffer is assumed to be at least MAXSTRSIGLEN
*
* The string "SIG#<num>" is returned for unrecognised signums
*/
char *g_sig2text(int signum, char sigstr[]);
#endif
+6 -2
View File
@@ -821,8 +821,12 @@ exit_status_to_str(const struct exit_status *e, char buff[], int bufflen)
break;
case E_XR_SIGNAL:
g_snprintf(buff, bufflen, "signal %d", e->val);
break;
{
char sigstr[MAXSTRSIGLEN];
g_snprintf(buff, bufflen, "signal %s",
g_sig2text(e->val, sigstr));
}
break;
default:
g_snprintf(buff, bufflen, "an unexpected error");
+6 -3
View File
@@ -155,10 +155,13 @@ wait_for_xserver(uid_t uid,
break;
case E_XR_SIGNAL:
{
char sigstr[MAXSTRSIGLEN];
LOG(LOG_LEVEL_ERROR,
"waitforx failed with unexpected signal %d",
e.val);
break;
"waitforx failed with unexpected signal %s",
g_sig2text(e.val, sigstr));
}
break;
default:
LOG(LOG_LEVEL_ERROR,
+80
View File
@@ -3,6 +3,10 @@
#include "config_ac.h"
#endif
#include <limits.h>
#include <signal.h>
#include "os_calls.h"
#include "string_calls.h"
#include "ms-rdpbcgr.h"
@@ -1036,6 +1040,76 @@ END_TEST
/******************************************************************************/
START_TEST(test_sigs__common)
{
char name[MAXSTRSIGLEN];
char *res;
// Check some common POSIX signals
res = g_sig2text(SIGHUP, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGHUP");
res = g_sig2text(SIGCHLD, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGCHLD");
res = g_sig2text(SIGXFSZ, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGXFSZ");
res = g_sig2text(SIGRTMIN, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGRTMIN");
res = g_sig2text(SIGRTMIN + 2, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGRTMIN+2");
res = g_sig2text(SIGRTMAX, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIGRTMAX");
// Should be invalid
res = g_sig2text(0, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIG#0");
res = g_sig2text(65535, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIG#65535");
// POSIX defines signals as ints, but insists they are positive. So
// we ought to trest we get sane behaviour for -ve numbers
res = g_sig2text(-1, name);
ck_assert_ptr_eq(res, name);
ck_assert_str_eq(res, "SIG#-1");
}
END_TEST
START_TEST(test_sigs__bigint)
{
char name[MAXSTRSIGLEN];
char name2[1024];
// Check that big integers aren't being truncated by the definition
// of MAXSTRSIGLEN
int i = INT_MAX;
g_sig2text(i, name);
g_snprintf(name2, sizeof(name2), "SIG#%d", i);
ck_assert_str_eq(name, name2);
i = INT_MIN;
g_sig2text(i, name);
g_snprintf(name2, sizeof(name2), "SIG#%d", i);
ck_assert_str_eq(name, name2);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_test_string(void)
{
@@ -1046,6 +1120,7 @@ make_suite_test_string(void)
TCase *tc_bm2char;
TCase *tc_char2bm;
TCase *tc_strtrim;
TCase *tc_sigs;
s = suite_create("String");
@@ -1118,5 +1193,10 @@ make_suite_test_string(void)
tcase_add_test(tc_strtrim, test_strtrim__trim_both);
tcase_add_test(tc_strtrim, test_strtrim__trim_through);
tc_sigs = tcase_create("signals");
suite_add_tcase(s, tc_sigs);
tcase_add_test(tc_sigs, test_sigs__common);
tcase_add_test(tc_sigs, test_sigs__bigint);
return s;
}
+12 -3
View File
@@ -102,9 +102,7 @@ xrdp_shutdown(int sig)
static void
xrdp_child(int sig)
{
while (g_waitchild(NULL) > 0)
{
}
g_set_sigchld(1);
}
/*****************************************************************************/
@@ -562,6 +560,14 @@ main(int argc, char **argv)
LOG(LOG_LEVEL_WARNING, "error creating g_term_event");
}
g_snprintf(text, 255, "xrdp_%8.8x_main_sigchld", pid);
g_set_sigchld_event(g_create_wait_obj(text));
if (g_get_sigchld() == 0)
{
LOG(LOG_LEVEL_WARNING, "error creating g_sigchld_event");
}
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
g_set_sync_event(g_create_wait_obj(text));
@@ -583,6 +589,9 @@ main(int argc, char **argv)
g_delete_wait_obj(g_get_term());
g_set_term_event(0);
g_delete_wait_obj(g_get_sigchld());
g_set_sigchld_event(0);
g_delete_wait_obj(g_get_sync_event());
g_set_sync_event(0);
+6
View File
@@ -55,6 +55,8 @@ g_set_sync1_mutex(long mutex);
void
g_set_term_event(tbus event);
void
g_set_sigchld_event(tbus event);
void
g_set_sync_event(tbus event);
long
g_get_threadid(void);
@@ -62,10 +64,14 @@ void
g_set_threadid(long id);
tbus
g_get_term(void);
tbus
g_get_sigchld(void);
int
g_is_term(void);
void
g_set_term(int in_val);
void
g_set_sigchld(int in_val);
tbus
g_get_sync_event(void);
void
+33
View File
@@ -846,6 +846,30 @@ xrdp_listen_conn_in(struct trans *self, struct trans *new_self)
return 0;
}
/*****************************************************************************/
/**
* Process pending SIGCHLD events in the listen process
*
* The main reason for this is to log children which fail
* on a signal. This should be investigated.
*/
static void
process_pending_sigchld_events(void)
{
struct exit_status e;
int pid;
while ((pid = g_waitchild(&e)) > 0)
{
if (e.reason == E_XR_SIGNAL)
{
char sigstr[MAXSTRSIGLEN];
LOG(LOG_LEVEL_ERROR,
"Child %d terminated unexpectedly with signal %s",
pid, g_sig2text(e.val, sigstr));
}
}
}
/*****************************************************************************/
/* wait for incoming connections
passes through trans_listen_address return value */
@@ -858,6 +882,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
int timeout;
intptr_t robjs[32];
intptr_t term_obj;
intptr_t sigchld_obj;
intptr_t sync_obj;
intptr_t done_obj;
struct trans *ltrans;
@@ -876,6 +901,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
return 1;
}
term_obj = g_get_term(); /*Global termination event */
sigchld_obj = g_get_sigchld();
sync_obj = g_get_sync_event();
done_obj = self->pro_done_event;
cont = 1;
@@ -884,6 +910,7 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
/* build the wait obj list */
robjs_count = 0;
robjs[robjs_count++] = term_obj;
robjs[robjs_count++] = sigchld_obj;
robjs[robjs_count++] = sync_obj;
robjs[robjs_count++] = done_obj;
timeout = -1;
@@ -918,6 +945,12 @@ xrdp_listen_main_loop(struct xrdp_listen *self)
break;
}
if (g_is_wait_obj_set(sigchld_obj)) /* SIGCHLD caught */
{
g_set_sigchld(0);
process_pending_sigchld_events();
}
/* some function must be processed by this thread */
if (g_is_wait_obj_set(sync_obj))
{
+48 -1
View File
@@ -39,6 +39,7 @@ static long g_threadid = 0; /* main threadid */
static long g_sync_mutex = 0;
static long g_sync1_mutex = 0;
static tbus g_term_event = 0;
static tbus g_sigchld_event = 0;
static tbus g_sync_event = 0;
/* synchronize stuff */
static int g_sync_command = 0;
@@ -104,6 +105,19 @@ g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
return sync_result;
}
/*****************************************************************************/
/* Signal handler for SIGCHLD in the child
* Note: only signal safe code (eg. setting wait event) should be executed in
* this function. For more details see `man signal-safety`
*/
static void
xrdp_child_sigchld_handler(int sig)
{
while (g_waitchild(NULL) > 0)
{
}
}
/*****************************************************************************/
/* called in child just after fork */
int
@@ -112,12 +126,17 @@ xrdp_child_fork(void)
int pid;
char text[256];
/* close, don't delete these */
/* SIGCHLD in the child is of no interest to us */
g_signal_child_stop(xrdp_child_sigchld_handler); /* SIGCHLD */
g_close_wait_obj(g_term_event);
g_close_wait_obj(g_sigchld_event);
g_close_wait_obj(g_sync_event);
pid = g_getpid();
g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid);
g_term_event = g_create_wait_obj(text);
g_sigchld_event = -1;
g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid);
g_sync_event = g_create_wait_obj(text);
return 0;
@@ -158,6 +177,13 @@ g_set_term_event(tbus event)
g_term_event = event;
}
/*****************************************************************************/
void
g_set_sigchld_event(tbus event)
{
g_sigchld_event = event;
}
/*****************************************************************************/
tbus
g_get_sync_event(void)
@@ -193,6 +219,13 @@ g_get_term(void)
return g_term_event;
}
/*****************************************************************************/
tbus
g_get_sigchld(void)
{
return g_sigchld_event;
}
/*****************************************************************************/
int
g_is_term(void)
@@ -214,6 +247,20 @@ g_set_term(int in_val)
}
}
/*****************************************************************************/
void
g_set_sigchld(int in_val)
{
if (in_val)
{
g_set_wait_obj(g_sigchld_event);
}
else
{
g_reset_wait_obj(g_sigchld_event);
}
}
/*****************************************************************************/
/*Some function must be called from the main thread.
if g_sync_command==THREAD_WAITING a function is waiting to be processed*/