diff --git a/0003-sedispatch-improve-performance.patch b/0003-sedispatch-improve-performance.patch new file mode 100644 index 0000000..ad08b41 --- /dev/null +++ b/0003-sedispatch-improve-performance.patch @@ -0,0 +1,163 @@ +From 46369d08223e06fb7884a4e65ff47a3b0b828f25 Mon Sep 17 00:00:00 2001 +From: Steve Grubb +Date: Thu, 15 Jul 2021 13:22:59 +0200 +Subject: [PATCH] sedispatch: improve performance + +sedispatch is pretty much the slowest audit relatedplugin. It was mixing +descriptors (select) and FILE functions (fgets) which is not a good recipe. + +It's reworked to only use descriptors. Also the flow is updated to +follow the latest plugin recommendations. This makes it run almost twice +as fast. The call to auparse_set_eoe_timeout() requires audit 3.0.1. +--- + src/sedispatch.c | 72 +++++++++++++++++++++++++----------------------- + 1 file changed, 38 insertions(+), 34 deletions(-) + +diff --git a/framework/src/sedispatch.c b/framework/src/sedispatch.c +index 2fa94fd85cc3..49c2fce2a333 100644 +--- a/framework/src/sedispatch.c ++++ b/framework/src/sedispatch.c +@@ -1,5 +1,5 @@ + /* sedispatch.c -- +- * Copyright 2009 Red Hat Inc., Durham, North Carolina. ++ * Copyright 2009,2021 Red Hat Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify +@@ -30,14 +30,14 @@ + * + */ + +-#define _GNU_SOURCE +-#include + #include + #include + #include + #include + #include + #include ++#include ++#include + #include "libaudit.h" + #include "auparse.h" + #include "sedbus.h" +@@ -101,8 +101,6 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) + { + char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; + struct sigaction sa; +- fd_set rfds; +- struct timeval tv; + + /* Register sighandlers */ + sa.sa_flags = 0; +@@ -113,6 +111,9 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) + sa.sa_handler = hup_handler; + sigaction(SIGHUP, &sa, NULL); + ++ /* Set STDIN non-blocking */ ++ fcntl(0, F_SETFL, O_NONBLOCK); ++ + /* Initialize the auparse library */ + au = auparse_init(AUSOURCE_FEED, 0); + if (au == NULL) { +@@ -120,37 +121,49 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) + return -1; + } + ++ auparse_set_eoe_timeout(2); + auparse_add_callback(au, handle_event, NULL, NULL); ++ + #ifdef HAVE_LIBCAP_NG + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); + #endif ++ + do { ++ fd_set rfds; ++ int retval; ++ int read_size = 1; /* Set to 1 so it's not EOF */ ++ + /* Load configuration */ + if (hup) { + reload_config(); + } + +- /* Now the event loop */ +- while (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, stdin) && +- hup==0 && stop==0) { +- auparse_feed(au, tmp, strnlen(tmp, +- MAX_AUDIT_MESSAGE_LENGTH)); +- +- /* Wait for 3 seconds and if nothing has happen expect that the event +- * is complete and flush parser's feed +- * FIXME: in future, libaudit will provide a better mechanism for aging +- * events +- */ ++ do { + FD_ZERO(&rfds); + FD_SET(0, &rfds); +- tv.tv_sec = 3; +- tv.tv_usec = 0; +- if (select(1, &rfds, NULL, NULL, &tv) == 0) +- /* The timeout occurred, the event is probably complete */ +- auparse_flush_feed(au); ++ ++ if (auparse_feed_has_data(au)) { ++ // We'll do a 1 second timeout to try to ++ // age events as quick as possible ++ struct timeval tv; ++ tv.tv_sec = 1; ++ tv.tv_usec = 0; ++ retval = select(1, &rfds, NULL, NULL, &tv); ++ } else ++ retval = select(1, &rfds, NULL, NULL, NULL); ++ ++ /* If we timed out & have events, shake them loose */ ++ if (retval == 0 && auparse_feed_has_data(au)) ++ auparse_feed_age_events(au); ++ } while (retval == -1 && errno == EINTR && !hup && !stop); ++ ++ /* Handle the event */ ++ if (!hup && !stop && retval > 0) { ++ read_size = read(0, tmp, MAX_AUDIT_MESSAGE_LENGTH); ++ auparse_feed(au, tmp, read_size); + } +- if (feof(stdin)) ++ if (read_size == 0) /* EOF */ + break; + } while (stop == 0); + +@@ -178,7 +191,6 @@ static void dump_whole_record(auparse_state_t *au, void *conn) + { + size_t size = 1; + char *tmp = NULL, *end=NULL; +- int i = 0; + const char * rec = NULL; + const char *scon = auparse_find_field(au, "scontext"); + const char *tcon = auparse_find_field(au, "tcontext"); +@@ -234,19 +246,11 @@ static void handle_event(auparse_state_t *au, + move the cursor accidentally skipping a record. */ + while (auparse_goto_record_num(au, num) > 0) { + type = auparse_get_type(au); +- /* Now we can branch based on what record type we find. +- This is just a few suggestions, but it could be anything. */ ++ /* Only handle AVCs. */ + switch (type) { + case AUDIT_AVC: +- dump_whole_record(au, conn); +- break; +- case AUDIT_SYSCALL: +- break; +- case AUDIT_USER_LOGIN: +- break; +- case AUDIT_ANOM_ABEND: +- break; +- case AUDIT_MAC_STATUS: ++ dump_whole_record(au, conn); ++ return; + break; + default: + break; +-- +2.32.0 + diff --git a/0004-sedispatch-improve-performance-using-cache-friendly-.patch b/0004-sedispatch-improve-performance-using-cache-friendly-.patch new file mode 100644 index 0000000..8d7b836 --- /dev/null +++ b/0004-sedispatch-improve-performance-using-cache-friendly-.patch @@ -0,0 +1,83 @@ +From ed6c940c8b05baaf8a4318beccde896893cc32dd Mon Sep 17 00:00:00 2001 +From: Steve Grubb +Date: Thu, 15 Jul 2021 13:29:32 +0200 +Subject: [PATCH] sedispatch: improve performance using cache friendly api + +It turns out that using auparse_goto_record_num() is not cache friendly. +Since it is only processing AVC events, there is no chance of seeking +around and missing the AVC record. So, that part of the program is +switched out to use auparse_next_record() which only moves through the +event once. + +Also unused variables were remove and the loop simplified. + +This change gets about 9% more speed. For reference, this +is how I checked the speed: + +time ./sedispatch < /var/log/audit/audit.log >/dev/null +--- + src/sedispatch.c | 36 +++++++++++------------------------- + 1 file changed, 11 insertions(+), 25 deletions(-) + +diff --git a/framework/src/sedispatch.c b/framework/src/sedispatch.c +index 49c2fce2a333..f2e9fbaf0743 100644 +--- a/framework/src/sedispatch.c ++++ b/framework/src/sedispatch.c +@@ -187,7 +187,7 @@ static int is_setroubleshoot(const char *context) { + } + + /* This function shows how to dump a whole record's text */ +-static void dump_whole_record(auparse_state_t *au, void *conn) ++static void dump_whole_record(auparse_state_t *au) + { + size_t size = 1; + char *tmp = NULL, *end=NULL; +@@ -228,35 +228,21 @@ static void dump_whole_record(auparse_state_t *au, void *conn) + } + + +-/* This function receives a single complete event at a time from the auparse +- * library. This is where the main analysis code would be added. */ ++/* This function receives a single complete event from auparse. Internal ++ * cursors are on the first record. This is where the analysis occurs. */ + static void handle_event(auparse_state_t *au, + auparse_cb_event_t cb_event_type, void *user_data) + { +- int type, num=0; +- +- DBusConnection* conn = +- (DBusConnection*) user_data; +- +- if (cb_event_type != AUPARSE_CB_EVENT_READY) +- return; +- +- /* Loop through the records in the event looking for one to process. +- We use physical record number because we may search around and +- move the cursor accidentally skipping a record. */ +- while (auparse_goto_record_num(au, num) > 0) { +- type = auparse_get_type(au); ++ /* Loop through the records looking for an AVC. If we ever process ++ * other record types without directly returning, we may need to use ++ * auparse_goto_record_num() to ensure seeing each record. */ ++ do { + /* Only handle AVCs. */ +- switch (type) { +- case AUDIT_AVC: +- dump_whole_record(au, conn); +- return; +- break; +- default: +- break; ++ if (auparse_get_type(au) == AUDIT_AVC) { ++ dump_whole_record(au); ++ return; + } +- num++; +- } ++ } while (auparse_next_record(au) > 0); + } + + #ifdef NOTUSED +-- +2.32.0 + diff --git a/0005-auparse_set_eoe_timeout-requires-audit-libauparse-3..patch b/0005-auparse_set_eoe_timeout-requires-audit-libauparse-3..patch new file mode 100644 index 0000000..dbb5446 --- /dev/null +++ b/0005-auparse_set_eoe_timeout-requires-audit-libauparse-3..patch @@ -0,0 +1,25 @@ +From 4041744bc94ee94a5d6ba59dd398e2eaae790b97 Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Fri, 16 Jul 2021 11:03:47 +0200 +Subject: [PATCH] auparse_set_eoe_timeout() requires audit / libauparse 3.0.1 + +--- + configure.ac | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/framework/configure.ac b/framework/configure.ac +index d1d01766e4a0..0fba58dca9d2 100644 +--- a/framework/configure.ac ++++ b/framework/configure.ac +@@ -13,6 +13,8 @@ PKG_CHECK_MODULES([NOTIFY], [libnotify]) + PKG_CHECK_MODULES([SEAPPLETLEGACY], [gtk+-2.0 gio-unix-2.0 libnotify dbus-glib-1], + [seappletlegacy=yes], [seappletlegacy=no]) + PKG_CHECK_MODULES([SEAPPLET], [gtk+-3.0]) ++# auparse_set_eoe_timeout() requires libauparse 3.0.1 ++PKG_CHECK_MODULES([SEDISPATCH], [auparse >= 3.0.1]) + + # make sure we keep ACLOCAL_FLAGS around for maintainer builds to work + AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}") +-- +2.32.0 + diff --git a/0006-Considerably-simplify-html_util-for-Python-3.10-comp.patch b/0006-Considerably-simplify-html_util-for-Python-3.10-comp.patch new file mode 100644 index 0000000..57e8928 --- /dev/null +++ b/0006-Considerably-simplify-html_util-for-Python-3.10-comp.patch @@ -0,0 +1,161 @@ +From 838f53a97ce44ea0f8f4d361afcb62a441f8633f Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Mon, 26 Jul 2021 13:11:17 -0700 +Subject: [PATCH] Considerably simplify html_util for Python 3.10 compatibility + (#58) + +As reported in #58 and RHBZ #1972391, `formatter` was removed +from the Python standard library in Python 3.10. This heavily +simplifies `html_util.html_to_text()` by using the stdlib +`HTMLParser` class, which avoids the use of `formatter`. + +Signed-off-by: Adam Williamson +--- + src/setroubleshoot/html_util.py | 110 ++++---------------------------- + 1 file changed, 12 insertions(+), 98 deletions(-) + +diff --git a/framework/src/setroubleshoot/html_util.py b/framework/src/setroubleshoot/html_util.py +index 5c6d07ab29dd..095eaeb8c4d4 100644 +--- a/framework/src/setroubleshoot/html_util.py ++++ b/framework/src/setroubleshoot/html_util.py +@@ -28,110 +28,29 @@ __all__ = [ + + import syslog + import sys ++import textwrap + if sys.version_info > (3,): + import html +- import html.parser + import html.entities +- from io import StringIO ++ from html.parser import HTMLParser + else: + import htmllib +- from StringIO import StringIO +-import formatter as Formatter ++ from HTMLParser import HTMLParser + import string + from types import * + + #------------------------------------------------------------------------------ + ++class HTMLFilter(HTMLParser): ++ def __init__(self): ++ HTMLParser.__init__(self) ++ self.text = "" + +-class TextWriter(Formatter.DumbWriter): +- +- def __init__(self, file=None, maxcol=80, indent_width=4): +- Formatter.DumbWriter.__init__(self, file, maxcol) +- self.indent_level = 0 +- self.indent_width = indent_width +- self._set_indent() +- +- def _set_indent(self): +- self.indent_col = self.indent_level * self.indent_width +- self.indent = ' ' * self.indent_col +- +- def new_margin(self, margin, level): +- self.indent_level = level +- self._set_indent() +- +- def send_label_data(self, data): +- data = data + ' ' +- if len(data) > self.indent_col: +- self.send_literal_data(data) +- else: +- offset = self.indent_col - len(data) +- self.send_literal_data(' ' * offset + data) +- +- def send_flowing_data(self, data): +- if not data: +- return +- atbreak = self.atbreak or data[0] in string.whitespace +- col = self.col +- maxcol = self.maxcol +- write = self.file.write +- col = self.col +- if col == 0: +- write(self.indent) +- col = self.indent_col +- for word in data.split(): +- if atbreak: +- if col + len(word) >= maxcol: +- write('\n' + self.indent) +- col = self.indent_col +- else: +- write(' ') +- col = col + 1 +- write(word) +- col = col + len(word) +- atbreak = 1 +- self.col = col +- self.atbreak = data[-1] in string.whitespace +- +-if sys.version_info > (3,): +- class HTMLParserAnchor(html.parser.HTMLParser): +- +- def __init__(self, formatter, strict=False, convert_charrefs=False): +- super(HTMLParserAnchor, self).__init__() +- self.formatter = formatter +- self.anchor_href = None +- +- def handle_starttag(self, tag, attrs): +- if tag == 'a': +- for key, value in attrs: +- if key == 'href': +- self.anchor_href = value +- +- def handle_endtag(self, tag): +- if tag == 'a': +- if self.anchor_href != None: +- self.formatter.writer.send_flowing_data('(' + self.anchor_href + ')') +- self.anchor_href = None +- +- def handle_data(self, data): +- self.formatter.writer.send_flowing_data(data) +- +-else: +- class HTMLParserAnchor(htmllib.HTMLParser): +- +- def __init__(self, formatter, verbose=0): +- htmllib.HTMLParser.__init__(self, formatter, verbose) +- +- def anchor_bgn(self, href, name, type): +- self.anchor = href +- +- def anchor_end(self): +- if self.anchor: +- self.handle_data(' (%s) ' % self.anchor) +- self.anchor = None ++ def handle_data(self, data): ++ self.text += data + + #------------------------------------------------------------------------------ + +- + def escape_html(s): + if s is None: + return None +@@ -161,14 +80,9 @@ def unescape_html(s): + + def html_to_text(html, maxcol=80): + try: +- buffer = StringIO() +- formatter = Formatter.AbstractFormatter(TextWriter(buffer, maxcol)) +- parser = HTMLParserAnchor(formatter) +- parser.feed(html) +- parser.close() +- text = buffer.getvalue() +- buffer.close() +- return text ++ filter = HTMLFilter() ++ filter.feed(html) ++ return textwrap.fill(filter.text, width=maxcol) + except Exception as e: + syslog.syslog(syslog.LOG_ERR, 'cannot convert html to text: %s' % e) + return None +-- +2.32.0 + diff --git a/0007-html_util-drop-various-unnecessary-imports.patch b/0007-html_util-drop-various-unnecessary-imports.patch new file mode 100644 index 0000000..42b5ad8 --- /dev/null +++ b/0007-html_util-drop-various-unnecessary-imports.patch @@ -0,0 +1,34 @@ +From 4722407e107911d448b47a9beeb8240c4df833fa Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Mon, 26 Jul 2021 13:16:27 -0700 +Subject: [PATCH] html_util: drop various unnecessary imports + +None of these actually seem to be used any more. + +Signed-off-by: Adam Williamson +--- + src/setroubleshoot/html_util.py | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/framework/src/setroubleshoot/html_util.py b/framework/src/setroubleshoot/html_util.py +index 095eaeb8c4d4..d24632b7e44c 100644 +--- a/framework/src/setroubleshoot/html_util.py ++++ b/framework/src/setroubleshoot/html_util.py +@@ -30,14 +30,9 @@ import syslog + import sys + import textwrap + if sys.version_info > (3,): +- import html +- import html.entities + from html.parser import HTMLParser + else: +- import htmllib + from HTMLParser import HTMLParser +-import string +-from types import * + + #------------------------------------------------------------------------------ + +-- +2.32.0 + diff --git a/0008-html_util-remove-html_document.patch b/0008-html_util-remove-html_document.patch new file mode 100644 index 0000000..005cd14 --- /dev/null +++ b/0008-html_util-remove-html_document.patch @@ -0,0 +1,68 @@ +From 15c8f55d85fc5b314b8a00cd5e9432e8d2726d7a Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Mon, 26 Jul 2021 13:18:29 -0700 +Subject: [PATCH] html_util: remove html_document + +I suspect this can safely be removed, because I don't think it +has worked for six years. Since dbaaf0f it uses `six.string_types` +but does not `import six`; if the function were ever called, it +would crash immediately. I suggest this is reasonable proof that +it's useless. Nothing in setroubleshoot itself calls it. + +Signed-off-by: Adam Williamson +--- + src/setroubleshoot/html_util.py | 34 --------------------------------- + 1 file changed, 34 deletions(-) + +diff --git a/framework/src/setroubleshoot/html_util.py b/framework/src/setroubleshoot/html_util.py +index d24632b7e44c..d16b78934c85 100644 +--- a/framework/src/setroubleshoot/html_util.py ++++ b/framework/src/setroubleshoot/html_util.py +@@ -22,8 +22,6 @@ __all__ = [ + 'escape_html', + 'unescape_html', + 'html_to_text', +- +- 'html_document', + ] + + import syslog +@@ -81,35 +79,3 @@ def html_to_text(html, maxcol=80): + except Exception as e: + syslog.syslog(syslog.LOG_ERR, 'cannot convert html to text: %s' % e) + return None +- +- +-def html_document(*body_components): +- '''Wrap the body components in a HTML document structure with a valid header. +- Accepts a variable number of arguments of of which canb be: +- * string +- * a sequences of strings (tuple or list). +- * a callable object taking no parameters and returning a string or sequence of strings. +- ''' +- head = '\n \n \n \n \n' +- tail = '\n \n' +- +- doc = head +- +- for body_component in body_components: +- if isinstance(body_component, six.string_types): +- doc += body_component +- elif isinstance(body_component, (tuple, list)): +- for item in body_component: +- doc += item +- elif callable(body_component): +- result = body_component() +- if isinstance(result, (tuple, list)): +- for item in result: +- doc += item +- else: +- doc += result +- else: +- doc += body_component +- +- doc += tail +- return doc +-- +2.32.0 + diff --git a/setroubleshoot.spec b/setroubleshoot.spec index 4a421c3..55b35d2 100644 --- a/setroubleshoot.spec +++ b/setroubleshoot.spec @@ -4,7 +4,7 @@ Summary: Helps troubleshoot SELinux problems Name: setroubleshoot Version: 3.3.26 -Release: 4%{?dist} +Release: 5%{?dist} License: GPLv2+ URL: https://pagure.io/setroubleshoot Source0: https://releases.pagure.org/setroubleshoot/%{name}-%{version}.tar.gz @@ -13,11 +13,18 @@ Source1: %{name}.tmpfiles # i=1; for j in 00*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done Patch0001: 0001-Stop-SetroubleshootFixit-after-10-seconds-of-inactiv.patch Patch0002: 0002-Do-not-use-Python-slip-package.patch +Patch0003: 0003-sedispatch-improve-performance.patch +Patch0004: 0004-sedispatch-improve-performance-using-cache-friendly-.patch +Patch0005: 0005-auparse_set_eoe_timeout-requires-audit-libauparse-3..patch +Patch0006: 0006-Considerably-simplify-html_util-for-Python-3.10-comp.patch +Patch0007: 0007-html_util-drop-various-unnecessary-imports.patch +Patch0008: 0008-html_util-remove-html_document.patch BuildRequires: gcc BuildRequires: make BuildRequires: libcap-ng-devel BuildRequires: intltool gettext python3 python3-devel -BuildRequires: desktop-file-utils dbus-glib-devel gtk2-devel libnotify-devel audit-libs-devel libselinux-devel polkit-devel +BuildRequires: desktop-file-utils dbus-glib-devel gtk2-devel libnotify-devel libselinux-devel polkit-devel +BuildRequires: audit-libs-devel >= 3.0.1 BuildRequires: python3-libselinux python3-dasbus python3-gobject gtk3-devel Requires: %{name}-server = %{version}-%{release} Requires: gtk3, libnotify @@ -89,7 +96,7 @@ install -m644 -D %{SOURCE1} $RPM_BUILD_ROOT%{_tmpfilesdir}/%{name}.conf Summary: SELinux troubleshoot server Requires: %{name}-plugins >= 3.3.10 -Requires: audit >= 3 +Requires: audit >= 3.0.1 Requires: audit-libs-python3 Requires: libxml2-python3 Requires: rpm-python3 @@ -190,6 +197,11 @@ chown -R setroubleshoot:setroubleshoot %{pkgvardatadir} %doc AUTHORS COPYING ChangeLog DBUS.md NEWS README TODO %changelog +* Tue Jul 27 2021 Petr Lautrbach - 3.3.26-5 +- Improve sedispatch performance +- Improve Python 3.10 compatibility + https://pagure.io/setroubleshoot/issue/58 + * Fri Jul 23 2021 Fedora Release Engineering - 3.3.26-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild