From 3e56be3564115287bf000cc5bde58bae56a06224 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 5 Aug 2019 16:30:58 -0600 Subject: [PATCH] Store signal name, not number in I/O log timing file. The "SIG" prefix is not used so, e.g. SIGTERM -> "TERM". This makes the I/O log files portable from one system to another. Older I/O log files with signal numbers can still be replayed. --- MANIFEST | 3 +- config.h.in | 3 + configure | 40 +++++++-- configure.ac | 16 +++- doc/sudoers.man.in | 4 +- doc/sudoers.mdoc.in | 4 +- include/sudo_compat.h | 5 ++ lib/util/Makefile.in | 6 ++ lib/util/str2sig.c | 154 +++++++++++++++++++++++++++++++++++ plugins/sudoers/iolog.c | 7 +- plugins/sudoers/iolog_util.c | 8 +- 11 files changed, 225 insertions(+), 25 deletions(-) create mode 100644 lib/util/str2sig.c diff --git a/MANIFEST b/MANIFEST index 47c645b93..060d9aac7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -96,10 +96,10 @@ lib/util/fatal.c lib/util/fnmatch.c lib/util/getaddrinfo.c lib/util/getcwd.c +lib/util/getdelim.c lib/util/getentropy.c lib/util/getgrouplist.c lib/util/gethostname.c -lib/util/getdelim.c lib/util/getopt_long.c lib/util/gettime.c lib/util/gidlist.c @@ -173,6 +173,7 @@ lib/util/sha2.c lib/util/sig2str.c lib/util/siglist.in lib/util/snprintf.c +lib/util/str2sig.c lib/util/strlcat.c lib/util/strlcpy.c lib/util/strndup.c diff --git a/config.h.in b/config.h.in index d89420611..2ffb3c2db 100644 --- a/config.h.in +++ b/config.h.in @@ -718,6 +718,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `str2sig' function. */ +#undef HAVE_STR2SIG + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H diff --git a/configure b/configure index b9634e651..e0f802b9f 100755 --- a/configure +++ b/configure @@ -22728,7 +22728,6 @@ _ACEOF if test $ac_have_decl = 1; then : HAVE_SIGLIST="true" - break fi ac_fn_c_check_decl "$LINENO" "_sys_siglist" "ac_cv_have_decl__sys_siglist" " @@ -22748,7 +22747,6 @@ _ACEOF if test $ac_have_decl = 1; then : HAVE_SIGLIST="true" - break fi @@ -22801,6 +22799,38 @@ esac " done + +fi +done + +for ac_func in str2sig +do : + ac_fn_c_check_func "$LINENO" "str2sig" "ac_cv_func_str2sig" +if test "x$ac_cv_func_str2sig" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STR2SIG 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" str2sig.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS str2sig.$ac_objext" + ;; +esac + + + for _sym in sudo_str2sig; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + +fi +done + + +if test x"${ac_cv_func_sig2str}${ac_cv_func_str2sig}" != x"yesyes"; then HAVE_SIGNAME="false" ac_fn_c_check_decl "$LINENO" "sys_signame" "ac_cv_have_decl_sys_signame" " $ac_includes_default @@ -22819,7 +22849,6 @@ _ACEOF if test $ac_have_decl = 1; then : HAVE_SIGNAME="true" - break fi ac_fn_c_check_decl "$LINENO" "_sys_signame" "ac_cv_have_decl__sys_signame" " @@ -22839,7 +22868,6 @@ _ACEOF if test $ac_have_decl = 1; then : HAVE_SIGNAME="true" - break fi ac_fn_c_check_decl "$LINENO" "sys_sigabbrev" "ac_cv_have_decl_sys_sigabbrev" " @@ -22859,7 +22887,6 @@ _ACEOF if test $ac_have_decl = 1; then : HAVE_SIGNAME="true" - break fi @@ -22905,10 +22932,7 @@ esac fi fi - fi -done - OLIBS="$LIBS" LIBS="$LIBS $lt_cv_dlopen_libs" diff --git a/configure.ac b/configure.ac index 65b145049..8b2debbc8 100644 --- a/configure.ac +++ b/configure.ac @@ -3264,7 +3264,6 @@ AC_CHECK_FUNCS([strsignal], [], [ HAVE_SIGLIST="false" AC_CHECK_DECLS([sys_siglist, _sys_siglist], [ HAVE_SIGLIST="true" - break ], [ ], [ AC_INCLUDES_DEFAULT #include @@ -3275,7 +3274,7 @@ AC_INCLUDES_DEFAULT ]) dnl -dnl Check for sig2str(), sys_signame or sys_sigabbrev +dnl Check for sig2str() and str2sig(), sys_signame or sys_sigabbrev dnl AC_CHECK_FUNCS([sig2str], [ AC_CHECK_DECLS(SIG2STR_MAX, [], [], [ @@ -3283,10 +3282,19 @@ AC_CHECK_FUNCS([sig2str], [ ])], [ AC_LIBOBJ(sig2str) SUDO_APPEND_COMPAT_EXP(sudo_sig2str) +]) +AC_CHECK_FUNCS([str2sig], [], [ + AC_LIBOBJ(str2sig) + SUDO_APPEND_COMPAT_EXP(sudo_str2sig) +]) + +dnl +dnl Check for sys_signame or sys_sigabbrev if missing sig2str() or str2sig(). +dnl +if test x"${ac_cv_func_sig2str}${ac_cv_func_str2sig}" != x"yesyes"; then HAVE_SIGNAME="false" AC_CHECK_DECLS([sys_signame, _sys_signame, sys_sigabbrev], [ HAVE_SIGNAME="true" - break ], [ ], [ AC_INCLUDES_DEFAULT #include @@ -3307,7 +3315,7 @@ AC_INCLUDES_DEFAULT AC_LIBOBJ(signame) fi fi -]) +fi dnl dnl Check for dl_iterate_phdr, may require -ldl diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index 8f5f5be71..06915cb09 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "July 19, 2019" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "August 5, 2019" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -4886,7 +4886,7 @@ bug compatibility for 1.8.7 terminal output .TP 6n 7 -command suspend or resume, signal number received +command suspend or resume, signal received .PP .RE .PD diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index f2c37b767..89d0ae035 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -24,7 +24,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd July 19, 2019 +.Dd August 5, 2019 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -4550,7 +4550,7 @@ bug compatibility for .Nm sudo 1.8.7 terminal output .It 7 -command suspend or resume, signal number received +command suspend or resume, signal received .El .It Pa ttyin Raw input from the user's terminal, exactly as it was received. diff --git a/include/sudo_compat.h b/include/sudo_compat.h index c987174d5..90327b043 100644 --- a/include/sudo_compat.h +++ b/include/sudo_compat.h @@ -500,6 +500,11 @@ __dso_public int sudo_sig2str(int signo, char *signame); # undef sig2str # define sig2str(_a, _b) sudo_sig2str((_a), (_b)) #endif /* HAVE_SIG2STR */ +#ifndef HAVE_STR2SIG +__dso_public int sudo_str2sig(const char *signame, int *signum); +# undef str2sig +# define str2sig(_a, _b) sudo_str2sig((_a), (_b)) +#endif /* HAVE_STR2SIG */ #if !defined(HAVE_INET_NTOP) && defined(SUDO_NET_IFS_C) __dso_public char *sudo_inet_ntop(int af, const void *src, char *dst, socklen_t size); # undef inet_ntop diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index ce2be3928..0ee4c1038 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -938,6 +938,12 @@ snprintf.i: $(srcdir)/snprintf.c $(incdir)/sudo_compat.h \ $(CC) -E -o $@ $(CPPFLAGS) $< snprintf.plog: snprintf.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/snprintf.c --i-file $< --output-file $@ +str2sig.lo: $(srcdir)/str2sig.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/str2sig.c +str2sig.i: $(srcdir)/str2sig.c $(incdir)/sudo_compat.h $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +str2sig.plog: str2sig.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/str2sig.c --i-file $< --output-file $@ strlcat.lo: $(srcdir)/strlcat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/strlcat.c strlcat.i: $(srcdir)/strlcat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h diff --git a/lib/util/str2sig.c b/lib/util/str2sig.c new file mode 100644 index 000000000..236348b6a --- /dev/null +++ b/lib/util/str2sig.c @@ -0,0 +1,154 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2019 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#ifndef HAVE_STR2SIG + +#include + +#include +#include +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include + +#include "sudo_compat.h" + +#if defined(HAVE_DECL_SYS_SIGNAME) && HAVE_DECL_SYS_SIGNAME == 1 +# define sudo_sys_signame sys_signame +#elif defined(HAVE_DECL__SYS_SIGNAME) && HAVE_DECL__SYS_SIGNAME == 1 +# define sudo_sys_signame _sys_signame +#elif defined(HAVE_DECL_SYS_SIGABBREV) && HAVE_DECL_SYS_SIGABBREV == 1 +# define sudo_sys_signame sys_sigabbrev +#else +# ifdef HAVE_SYS_SIGABBREV + /* sys_sigabbrev is not declared by glibc */ +# define sudo_sys_signame sys_sigabbrev +# endif +extern const char *const sudo_sys_signame[NSIG]; +#endif + +/* + * Translate signal name to number. + */ +int +sudo_str2sig(const char *signame, int *result) +{ + int signo; + const char *errstr; + + /* Could be a signal number encoded as a string. */ + if (isdigit((unsigned char)signame[0])) { + signo = strtonum(signame, 0, NSIG - 1, &errstr); + if (errstr != NULL) + return -1; + *result = signo; + return 0; + } + + /* Special cases. */ + switch (signame[0]) { + case 'C': + /* support both SIGCLD and SIGCHLD */ +#ifdef SIGCLD + if (strcmp(signame, "CLD") == 0) { + *result = SIGCLD; + return 0; + } +#endif +#ifdef SIGCHLD + if (strcmp(signame, "CHLD") == 0) { + *result = SIGCHLD; + return 0; + } +#endif + break; +#ifdef SIGIO + case 'I': + /* support both SIGIO and SIGPOLL */ + if (strcmp(signame, "IO") == 0) { + *result = SIGIO; + return 0; + } + break; +#endif +#ifdef SIGPOLL + case 'P': + /* support both SIGIO and SIGPOLL */ + if (strcmp(signame, "POLL") == 0) { + *result = SIGPOLL; + return 0; + } + break; +#endif + case 'R': + /* real-time signals */ +#if defined(SIGRTMIN) + if (strncmp(signame, "RTMIN", 5) == 0) { + if (signame[5] == '\0') { + *result = SIGRTMIN; + return 0; + } + if (signame[5] == '+') { + if (signame[6] == '1' || signame[6] == '2' || signame[6] == '3') { + *result = SIGRTMIN + (signame[6] - '0'); + return 0; + } + } + } +#endif +#if defined(SIGRTMAX) + if (strncmp(signame, "RTMAX", 5) == 0) { + if (signame[5] == '\0') { + *result = SIGRTMAX; + return 0; + } + if (signame[5] == '-') { + if (signame[6] == '1' || signame[6] == '2' || signame[6] == '3') { + *result = SIGRTMAX - (signame[6] - '0'); + return 0; + } + } + } +#endif + break; + } + + for (signo = 0; signo < NSIG; signo++) { + if (strcmp(signame, sudo_sys_signame[signo]) == 0) { + *result = signo; + return 0; + } + } + + errno = EINVAL; + return -1; +} +#endif /* HAVE_STR2SIG */ diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 2fd52dee8..53c8094ed 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -1221,12 +1221,13 @@ sudoers_io_suspend(int signo) { struct timespec now, delay; unsigned int len; + char signame[SIG2STR_MAX]; char tbuf[1024]; const char *errstr = NULL; int ret = -1; debug_decl(sudoers_io_suspend, SUDOERS_DEBUG_PLUGIN) - if (signo <= 0) { + if (signo <= 0 || sig2str(signo, signame) == -1) { sudo_warnx(U_("%s: internal error, invalid signal %d"), __func__, signo); debug_return_int(-1); @@ -1241,8 +1242,8 @@ sudoers_io_suspend(int signo) /* Write suspend event to the timing file. */ sudo_timespecsub(&now, &last_time, &delay); - len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %d\n", - IO_EVENT_SUSPEND, (long long)delay.tv_sec, delay.tv_nsec, signo); + len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %lld.%09ld %s\n", + IO_EVENT_SUSPEND, (long long)delay.tv_sec, delay.tv_nsec, signame); if (len >= sizeof(tbuf)) { /* Not actually possible due to the size of tbuf[]. */ errstr = strerror(EOVERFLOW); diff --git a/plugins/sudoers/iolog_util.c b/plugins/sudoers/iolog_util.c index bdf553c08..d3f11edfb 100644 --- a/plugins/sudoers/iolog_util.c +++ b/plugins/sudoers/iolog_util.c @@ -37,6 +37,7 @@ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ +#include #include #include #include @@ -333,12 +334,9 @@ parse_timing(const char *buf, struct timespec *delay, switch (timing->event) { case IO_EVENT_SUSPEND: - ulval = strtoul(cp, &ep, 10); - if (ep == cp || *ep != '\0') - goto bad; - if (ulval > INT_MAX) + /* Signal name (no leading SIG prefix) or number. */ + if (str2sig(cp, &timing->u.signo) == -1) goto bad; - timing->u.signo = (int)ulval; break; case IO_EVENT_WINSIZE: ulval = strtoul(cp, &ep, 10); -- 2.40.0