diff --git a/MANIFEST b/MANIFEST index 1754e5cc6..1f1c968da 100644 --- a/MANIFEST +++ b/MANIFEST @@ -172,6 +172,22 @@ lib/iolog/regress/fuzz/fuzz_iolog_json.dict lib/iolog/regress/fuzz/fuzz_iolog_legacy.c lib/iolog/regress/fuzz/fuzz_iolog_timing.c lib/iolog/regress/host_port/host_port_test.c +lib/iolog/regress/iolog_filter/check_iolog_filter.c +lib/iolog/regress/iolog_filter/test1/log +lib/iolog/regress/iolog_filter/test1/timing +lib/iolog/regress/iolog_filter/test1/ttyin +lib/iolog/regress/iolog_filter/test1/ttyin.filtered +lib/iolog/regress/iolog_filter/test1/ttyout +lib/iolog/regress/iolog_filter/test2/log +lib/iolog/regress/iolog_filter/test2/timing +lib/iolog/regress/iolog_filter/test2/ttyin +lib/iolog/regress/iolog_filter/test2/ttyin.filtered +lib/iolog/regress/iolog_filter/test2/ttyout +lib/iolog/regress/iolog_filter/test3/log +lib/iolog/regress/iolog_filter/test3/timing +lib/iolog/regress/iolog_filter/test3/ttyin +lib/iolog/regress/iolog_filter/test3/ttyin.filtered +lib/iolog/regress/iolog_filter/test3/ttyout lib/iolog/regress/iolog_json/check_iolog_json.c lib/iolog/regress/iolog_json/test1.in lib/iolog/regress/iolog_json/test2.in diff --git a/lib/iolog/Makefile.in b/lib/iolog/Makefile.in index 68587f0e5..c2759dbdd 100644 --- a/lib/iolog/Makefile.in +++ b/lib/iolog/Makefile.in @@ -78,7 +78,7 @@ PVS_IGNORE = 'V707,V011,V002,V536' PVS_LOG_OPTS = -a 'GA:1,2' -e -t errorfile -d $(PVS_IGNORE) # Regression tests -TEST_PROGS = check_iolog_json check_iolog_mkpath check_iolog_path check_iolog_timing host_port_test +TEST_PROGS = check_iolog_filter check_iolog_json check_iolog_mkpath check_iolog_path check_iolog_timing host_port_test TEST_LIBS = @LIBS@ TEST_LDFLAGS = @LDFLAGS@ @@ -117,6 +117,8 @@ CHECK_IOLOG_PATH_OBJS = check_iolog_path.lo CHECK_IOLOG_TIMING_OBJS = check_iolog_timing.lo +CHECK_IOLOG_FILTER_OBJS = check_iolog_filter.lo + CHECK_IOLOG_JSON_OBJS = check_iolog_json.lo HOST_PORT_TEST_OBJS = host_port_test.lo @@ -171,6 +173,9 @@ check_iolog_mkpath: $(CHECK_IOLOG_MKPATH_OBJS) libsudo_iolog.la check_iolog_timing: $(CHECK_IOLOG_TIMING_OBJS) libsudo_iolog.la $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_TIMING_OBJS) libsudo_iolog.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) +check_iolog_filter: $(CHECK_IOLOG_FILTER_OBJS) libsudo_iolog.la + $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_FILTER_OBJS) libsudo_iolog.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) + check_iolog_json: $(CHECK_IOLOG_JSON_OBJS) libsudo_iolog.la $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_IOLOG_JSON_OBJS) libsudo_iolog.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS) @@ -325,6 +330,7 @@ check: $(TEST_PROGS) check-fuzzer MALLOC_OPTIONS=S; export MALLOC_OPTIONS; \ MALLOC_CONF="abort:true,junk:true"; export MALLOC_CONF; \ rval=0; \ + ./check_iolog_filter $(srcdir)/regress/iolog_filter/test[1-9]* || rval=`expr $$rval + $$?`; \ ./check_iolog_json $(srcdir)/regress/iolog_json/*.in || rval=`expr $$rval + $$?`; \ ./check_iolog_path $(srcdir)/regress/iolog_path/data || rval=`expr $$rval + $$?`; \ ./check_iolog_mkpath || rval=`expr $$rval + $$?`; \ @@ -357,6 +363,20 @@ cleandir: realclean run-fuzz_iolog_timing # Autogenerated dependencies, do not modify +check_iolog_filter.lo: $(srcdir)/regress/iolog_filter/check_iolog_filter.c \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/iolog_filter/check_iolog_filter.c +check_iolog_filter.i: $(srcdir)/regress/iolog_filter/check_iolog_filter.c \ + $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_iolog.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +check_iolog_filter.plog: check_iolog_filter.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/iolog_filter/check_iolog_filter.c --i-file $< --output-file $@ check_iolog_json.lo: $(srcdir)/regress/iolog_json/check_iolog_json.c \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_json.h \ @@ -557,13 +577,15 @@ iolog_filter.lo: $(srcdir)/iolog_filter.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \ - $(incdir)/sudo_queue.h $(top_builddir)/config.h + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/iolog_filter.c iolog_filter.i: $(srcdir)/iolog_filter.c $(incdir)/compat/stdbool.h \ $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \ $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \ $(incdir)/sudo_iolog.h $(incdir)/sudo_plugin.h \ - $(incdir)/sudo_queue.h $(top_builddir)/config.h + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ + $(top_builddir)/config.h $(CC) -E -o $@ $(CPPFLAGS) $< iolog_filter.plog: iolog_filter.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/iolog_filter.c --i-file $< --output-file $@ diff --git a/lib/iolog/regress/iolog_filter/check_iolog_filter.c b/lib/iolog/regress/iolog_filter/check_iolog_filter.c new file mode 100644 index 000000000..8d711f03f --- /dev/null +++ b/lib/iolog/regress/iolog_filter/check_iolog_filter.c @@ -0,0 +1,190 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2022 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. + */ + +#include + +#include +#include +#include +#include +#include + +#define SUDO_ERROR_WRAP 0 + +#include "sudo_compat.h" +#include "sudo_util.h" +#include "sudo_fatal.h" + +#include "sudo_iolog.h" + +sudo_dso_public int main(int argc, char *argv[]); + +int +main(int argc, char *argv[]) +{ + int dfd = -1, ttyin_fd = -1, ttyout_fd = -1, ttyin_ok_fd = -1; + int i, tests = 0, errors = 0; + void *passprompt_regex = NULL; + + initprogname(argc > 0 ? argv[0] : "check_iolog_filter"); + + passprompt_regex = iolog_pwfilt_alloc(); + if (passprompt_regex == NULL) + sudo_fatalx("unable to allocate memory"); + if (!iolog_pwfilt_add(passprompt_regex, "(?i)password[: ]*")) + exit(1); + + for (i = 1; i < argc; i++) { + struct iolog_file iolog_timing = { true }; + struct timing_closure timing; + const char *logdir = argv[i]; + char tbuf[8192], fbuf[8192]; + ssize_t nread; + + tests++; + + /* I/O logs consist of multiple files in a directory. */ + dfd = open(logdir, O_RDONLY); + if (dfd == -1) { + sudo_warn("%s", logdir); + errors++; + continue; + } + + if (!iolog_open(&iolog_timing, dfd, IOFD_TIMING, "r")) { + sudo_warn("timing"); + errors++; + goto next; + } + + ttyout_fd = openat(dfd, "ttyout", O_RDONLY); + if (ttyout_fd == -1) { + sudo_warn("ttyout"); + errors++; + goto next; + } + + ttyin_fd = openat(dfd, "ttyin", O_RDONLY); + if (ttyin_fd == -1) { + sudo_warn("ttyin"); + errors++; + goto next; + } + + ttyin_ok_fd = openat(dfd, "ttyin.filtered", O_RDONLY); + if (ttyin_ok_fd == -1) { + sudo_warn("ttyin.filtered"); + errors++; + goto next; + } + + memset(&timing, 0, sizeof(timing)); + timing.decimal = "."; + for (;;) { + char *newbuf = NULL; + const char *name; + int fd; + + if (iolog_read_timing_record(&iolog_timing, &timing) != 0) + break; + + switch (timing.event) { + case IO_EVENT_TTYOUT: + fd = ttyout_fd; + name = "ttyout"; + break; + case IO_EVENT_TTYIN: + fd = ttyin_fd; + name = "ttyin"; + break; + default: + continue; + } + + if (timing.u.nbytes > sizeof(tbuf)) { + sudo_warn("buffer too small, %zu > %zu", timing.u.nbytes, + sizeof(tbuf)); + errors++; + continue; + } + + nread = read(fd, tbuf, timing.u.nbytes); + if ((size_t)nread != timing.u.nbytes) { + if (nread == -1) + sudo_warn("%s/%s", argv[i], name); + else + sudo_warnx("%s/%s: short read", argv[i], name); + errors++; + continue; + } + + /* Apply filter. */ + if (!iolog_pwfilt_run(passprompt_regex, timing.event, tbuf, + timing.u.nbytes, &newbuf)) { + errors++; + continue; + } + + if (timing.event == IO_EVENT_TTYIN) { + nread = read(ttyin_ok_fd, fbuf, timing.u.nbytes); + if (nread == -1) { + if (nread == -1) + sudo_warn("%s/ttyin.filtered", argv[i]); + else + sudo_warnx("%s/ttyin.filtered: short read", argv[i]); + errors++; + free(newbuf); + break; + } + if (memcmp(fbuf, newbuf ? newbuf : tbuf, timing.u.nbytes) != 0) { + sudo_warnx("%s: ttyin mismatch at byte %lld", argv[i], + (long long)lseek(fd, 0, SEEK_CUR)); + errors++; + free(newbuf); + break; + } + } + + free(newbuf); + } +next: + if (ttyin_fd != -1) { + close(ttyin_fd); + ttyin_fd = -1; + } + if (ttyin_ok_fd != -1) { + close(ttyin_ok_fd); + ttyin_ok_fd = -1; + } + if (dfd != -1) { + close(dfd); + dfd = -1; + } + if (iolog_timing.enabled) + iolog_close(&iolog_timing, NULL); + } + iolog_pwfilt_free(passprompt_regex); + + if (tests != 0) { + printf("%s: %d test%s run, %d errors, %d%% success rate\n", + getprogname(), tests, tests == 1 ? "" : "s", errors, + (tests - errors) * 100 / tests); + } + + exit(errors); +} diff --git a/lib/iolog/regress/iolog_filter/test1/log b/lib/iolog/regress/iolog_filter/test1/log new file mode 100644 index 000000000..551adfbf9 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test1/log @@ -0,0 +1,3 @@ +1645151020:millert:root::/dev/ttypb:24:80 +/home/millert +/usr/bin/passwd diff --git a/lib/iolog/regress/iolog_filter/test1/timing b/lib/iolog/regress/iolog_filter/test1/timing new file mode 100644 index 000000000..3a62388cf --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test1/timing @@ -0,0 +1,44 @@ +4 0.087089703 32 +4 0.000503221 13 +3 1.617732029 1 +3 0.671818399 1 +3 0.632182533 1 +3 0.135484597 1 +3 0.120171445 1 +3 0.120200768 1 +3 0.239782513 1 +3 0.064059449 1 +3 0.184048364 1 +3 0.135992479 1 +3 0.167905298 1 +3 0.087948033 1 +3 0.135913060 1 +3 0.136306311 1 +3 0.279830387 1 +3 0.280221744 1 +4 0.000453682 2 +4 0.001188404 20 +3 0.678534827 1 +3 1.912119627 1 +3 0.303804149 1 +3 0.071831900 1 +3 0.248608651 1 +3 0.088758738 1 +3 0.262821628 1 +3 0.111839737 1 +3 0.184326849 1 +3 0.119709565 1 +3 0.184446495 1 +3 0.089439595 1 +3 0.150353799 1 +3 0.152035883 1 +3 0.392237165 1 +3 0.183498720 1 +3 0.136099560 1 +3 0.256165394 1 +4 0.000392254 2 +4 0.000348360 35 +4 0.000330782 13 +3 0.871580665 1 +4 0.000434371 2 +4 0.001150945 23 diff --git a/lib/iolog/regress/iolog_filter/test1/ttyin b/lib/iolog/regress/iolog_filter/test1/ttyin new file mode 100644 index 000000000..5a2067d09 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test1/ttyin @@ -0,0 +1 @@ +A new password? A bad password...  \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test1/ttyin.filtered b/lib/iolog/regress/iolog_filter/test1/ttyin.filtered new file mode 100644 index 000000000..d4943b326 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test1/ttyin.filtered @@ -0,0 +1 @@ +*************** ***************** * \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test1/ttyout b/lib/iolog/regress/iolog_filter/test1/ttyout new file mode 100644 index 000000000..bac1f87e9 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test1/ttyout @@ -0,0 +1,7 @@ +Changing password for millert. +New password: +Retype new password: +Mismatch; try again, EOF to quit. +New password: + +Password unchanged. diff --git a/lib/iolog/regress/iolog_filter/test2/log b/lib/iolog/regress/iolog_filter/test2/log new file mode 100644 index 000000000..879057392 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test2/log @@ -0,0 +1,3 @@ +1645153850:millert:millert::/dev/ttypb:24:80 +/home/millert +/usr/bin/su testdude diff --git a/lib/iolog/regress/iolog_filter/test2/timing b/lib/iolog/regress/iolog_filter/test2/timing new file mode 100644 index 000000000..7e6b1cc9f --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test2/timing @@ -0,0 +1,73 @@ +4 0.077895153 9 +3 9.876530326 1 +3 0.191980568 1 +3 0.168017746 1 +3 0.088081740 1 +3 0.183886638 1 +3 0.071966892 1 +3 0.175772878 1 +3 0.672270691 1 +4 0.000336085 2 +4 0.022264031 8 +3 4.721817713 1 +4 0.001379444 1 +3 0.086406844 1 +4 0.000383615 1 +3 0.055583229 1 +4 0.000353543 1 +3 0.079726966 1 +4 0.000336390 1 +3 0.063626746 1 +4 0.000719018 1 +3 0.135204338 1 +4 0.000342720 1 +3 0.095976209 1 +4 0.000338049 1 +3 0.047259669 1 +4 0.000339501 1 +3 0.399809817 1 +4 0.000345392 1 +3 0.111587761 1 +4 0.000366589 1 +3 0.087582640 1 +4 0.000328160 1 +3 0.480159500 1 +4 0.000370778 3 +3 0.143285883 1 +4 0.000332529 3 +3 0.135841236 1 +4 0.000343729 3 +3 0.223401313 1 +4 0.000329496 1 +3 0.063760060 1 +4 0.000382349 1 +3 0.087442363 1 +4 0.000345787 1 +3 0.095598655 1 +4 0.000343712 1 +3 0.560106197 1 +4 0.000405183 3 +3 0.151363786 1 +4 0.000345085 3 +3 0.167809002 1 +4 0.000326037 3 +3 0.135471962 1 +4 0.000378004 3 +3 0.111681517 1 +4 0.000329093 1 +3 0.127537491 1 +4 0.000355403 1 +3 0.103896235 1 +4 0.000320608 1 +3 0.095563437 1 +4 0.000327463 1 +3 0.087808248 1 +4 0.000321244 1 +3 0.503531970 1 +4 0.000338699 1 +3 1.383887942 1 +4 0.000324499 3 +4 0.000334583 11 +4 0.000324866 8 +3 0.999440679 1 +4 0.000365851 5 diff --git a/lib/iolog/regress/iolog_filter/test2/ttyin b/lib/iolog/regress/iolog_filter/test2/ttyin new file mode 100644 index 000000000..29482c0af --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test2/ttyin @@ -0,0 +1 @@ +test123 echo hi ereherethere!  \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test2/ttyin.filtered b/lib/iolog/regress/iolog_filter/test2/ttyin.filtered new file mode 100644 index 000000000..e3c303d6f --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test2/ttyin.filtered @@ -0,0 +1 @@ +******* echo hi ereherethere!  \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test2/ttyout b/lib/iolog/regress/iolog_filter/test2/ttyout new file mode 100644 index 000000000..dbb7124d5 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test2/ttyout @@ -0,0 +1,4 @@ +Password: +xerxes$ echo hi ere   here    there! +hi there! +xerxes$ ^D diff --git a/lib/iolog/regress/iolog_filter/test3/log b/lib/iolog/regress/iolog_filter/test3/log new file mode 100644 index 000000000..f0500f44e --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test3/log @@ -0,0 +1,3 @@ +1645201461:millert:root::/dev/ttyp0:24:80 +/home/millert +/usr/bin/ssh -oPubkeyAuthentication=no localhost diff --git a/lib/iolog/regress/iolog_filter/test3/timing b/lib/iolog/regress/iolog_filter/test3/timing new file mode 100644 index 000000000..03b67f481 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test3/timing @@ -0,0 +1,54 @@ +4 0.158768144 1 +4 0.000406264 27 +3 4.390837642 1 +3 0.119705081 1 +3 0.175600726 1 +3 0.064357615 1 +3 0.239945395 1 +3 0.088142451 1 +3 0.143665762 1 +3 0.071941169 1 +3 0.208359675 1 +3 0.145706215 1 +3 0.302231926 1 +3 0.079805215 1 +3 0.112114024 1 +3 0.143802378 1 +3 0.160033289 1 +4 0.000416283 2 +4 0.042939142 40 +4 0.000399448 27 +3 1.084753026 1 +3 0.087720859 1 +3 0.215896027 1 +3 0.167921572 1 +3 0.304253899 1 +3 0.103807201 1 +3 0.191962088 1 +3 0.071989566 1 +3 0.296183440 1 +3 0.162262688 1 +3 0.125661454 1 +3 0.192164590 1 +4 0.000394039 2 +4 0.034617321 40 +4 0.000414822 27 +3 0.796676353 1 +3 0.119589531 1 +3 0.120189440 1 +3 0.080002264 1 +3 0.120104599 1 +3 0.087897523 1 +3 0.088072936 1 +3 0.111980459 1 +3 0.064099904 1 +3 0.440166638 1 +3 0.159957933 1 +3 0.063988834 1 +3 0.247906778 1 +3 0.167767797 1 +3 0.151961605 1 +3 0.176237322 1 +3 0.368288839 1 +4 0.000364019 2 +4 0.034413644 79 diff --git a/lib/iolog/regress/iolog_filter/test3/ttyin b/lib/iolog/regress/iolog_filter/test3/ttyin new file mode 100644 index 000000000..224e0b483 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test3/ttyin @@ -0,0 +1 @@ +not a password nope, sorry try again please \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test3/ttyin.filtered b/lib/iolog/regress/iolog_filter/test3/ttyin.filtered new file mode 100644 index 000000000..bc6dfb5ca --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test3/ttyin.filtered @@ -0,0 +1 @@ +************** *********** **************** \ No newline at end of file diff --git a/lib/iolog/regress/iolog_filter/test3/ttyout b/lib/iolog/regress/iolog_filter/test3/ttyout new file mode 100644 index 000000000..b6befb903 --- /dev/null +++ b/lib/iolog/regress/iolog_filter/test3/ttyout @@ -0,0 +1,6 @@ + root@localhost's password: +Permission denied, please try again. + root@localhost's password: +Permission denied, please try again. + root@localhost's password: +root@localhost: Permission denied (publickey,password,keyboard-interactive).