diff --git a/SOURCES/0101-Fix-race-condition-in-ChownProblemDir.patch b/SOURCES/0101-Fix-race-condition-in-ChownProblemDir.patch new file mode 100644 index 0000000..952444f --- /dev/null +++ b/SOURCES/0101-Fix-race-condition-in-ChownProblemDir.patch @@ -0,0 +1,39 @@ +From 8085b4f1dfbee20df6276fbb0857f04b1c87ad29 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 7 Aug 2026 12:53:30 +0200 +Subject: [PATCH 1/5] Fix race condition in ChownProblemDir + +Resolves: CVE-2026-54229 + +A local attacker could call ChownProblemDir while post-create event handlers +are still processing a dump directory, seizing file ownership while privileged +scripts continue writing and processing those files. + +Co-Authored-By: Claude Opus 4.6 +--- + src/dbus/abrt-dbus.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c +index e68bce8..d152f8e 100644 +--- a/src/dbus/abrt-dbus.c ++++ b/src/dbus/abrt-dbus.c +@@ -499,6 +499,15 @@ static void handle_method_call(GDBusConnection *connection, + return; + } + ++ if (!problem_dump_dir_is_complete(dd)) ++ { ++ g_dbus_method_invocation_return_dbus_error(invocation, ++ "org.freedesktop.problems.InvalidProblemDir", ++ _("Problem directory is being processed")); ++ dd_close(dd); ++ return; ++ } ++ + int chown_res = dd_chown(dd, caller_uid); + if (chown_res != 0) + g_dbus_method_invocation_return_dbus_error(invocation, +-- +2.55.0 + diff --git a/SOURCES/0102-Fix-TOCTOU-in-SetElement-DeleteElement.patch b/SOURCES/0102-Fix-TOCTOU-in-SetElement-DeleteElement.patch new file mode 100644 index 0000000..8082ee5 --- /dev/null +++ b/SOURCES/0102-Fix-TOCTOU-in-SetElement-DeleteElement.patch @@ -0,0 +1,50 @@ +From 26e8fc810e8d498a67455a08f98a591f04f22008 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 7 Aug 2026 12:56:32 +0200 +Subject: [PATCH 2/5] Fix TOCTOU in SetElement/DeleteElement + +Resolves: CVE-2026-54228 + +This vulnerability allows any local user to call SetElement or DeleteElement +on a dump directory that is still being processed by post-create event handlers. +This lets an attacker write arbitrary text files into (or delete files from) +a root-owned dump directory, poisoning data consumed by privileged event scripts. + +Co-Authored-By: Claude Opus 4.6 +--- + src/dbus/abrt-dbus.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c +index d152f8e..119db3d 100644 +--- a/src/dbus/abrt-dbus.c ++++ b/src/dbus/abrt-dbus.c +@@ -291,8 +291,23 @@ static struct dump_dir *open_directory_for_modification_of_element( + } + } + +- return open_dump_directory(invocation, /*caller*/NULL, caller_uid, problem_id, /*Read/Write*/0, +- OPEN_AUTH_FAIL); ++ struct dump_dir *dd = open_dump_directory(invocation, /*caller*/NULL, caller_uid, problem_id, ++ /*Read/Write*/0, OPEN_AUTH_FAIL); ++ if (!dd) ++ return NULL; ++ ++ if (!problem_dump_dir_is_complete(dd)) ++ { ++ log_notice("Refusing modification of element '%s' in incomplete problem directory '%s'", ++ element, problem_id); ++ g_dbus_method_invocation_return_dbus_error(invocation, ++ "org.freedesktop.problems.InvalidProblemDir", ++ _("Problem directory is being processed")); ++ dd_close(dd); ++ return NULL; ++ } ++ ++ return dd; + } + + +-- +2.55.0 + diff --git a/SOURCES/0103-Fix-content-injection-in-journal-log-collection.patch b/SOURCES/0103-Fix-content-injection-in-journal-log-collection.patch new file mode 100644 index 0000000..2b33106 --- /dev/null +++ b/SOURCES/0103-Fix-content-injection-in-journal-log-collection.patch @@ -0,0 +1,52 @@ +From baf3d7482378cf19a2ef0a900db7e34d54fe0ebd Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 7 Aug 2026 12:59:15 +0200 +Subject: [PATCH 3/5] Fix content injection in journal log collection + +Resolves: CVE-2026-54231 + +The post-create event handler for CCpp crashes queries the systemd +journal for log entries matching the crashed process and writes the +results to var_log_messages in the dump directory. The journalctl +query filtered only by _COMM (process name) and _UID, both of which +a local attacker can match by using prctl(PR_SET_NAME). By embedding +newline characters in syslog messages, the attacker could inject +arbitrary content into the file that root writes to the dump directory. + +Add _PID filtering to the journalctl query. The dump directory already +contains a pid file with the crashed process's PID, and a local +attacker cannot predict or control the PID assigned to another user's +process. This prevents spoofed journal entries from being collected. + +Co-Authored-By: Claude Opus 4.6 +--- + src/plugins/ccpp_event.conf | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/plugins/ccpp_event.conf b/src/plugins/ccpp_event.conf +index f8338d2..e89e98b 100644 +--- a/src/plugins/ccpp_event.conf ++++ b/src/plugins/ccpp_event.conf +@@ -28,8 +28,9 @@ EVENT=post-create type=CCpp remote!=1 + executable=`cat executable` && + base_executable=${executable##*/} && + uid=`cat $DUMP_DIR/uid` && ++ pid=`cat pid` && + { +- user_log_full=`journalctl -q -b --since=-3m -n 99 _COMM="$base_executable" _UID="$uid"` && ++ user_log_full=`journalctl -q -b --since=-3m -n 99 _COMM="$base_executable" _UID="$uid" _PID="$pid"` && + while read line; do + if [[ $line != *" audit["* ]]; then + user_log=$user_log$line$'\n' +@@ -42,7 +43,7 @@ EVENT=post-create type=CCpp remote!=1 + # Remove the line below if you don't mind sharing data from the + # system logs with unprivileged users -> bugzilla.redhat.com/1212868 + false && +- system_log_full=$log`journalctl -q -b --since=-3m --system -n 99 _COMM="$base_executable"` && ++ system_log_full=$log`journalctl -q -b --since=-3m --system -n 99 _COMM="$base_executable" _PID="$pid"` && + while read line; do + if [[ $line != *" audit["* ]]; then + system_log=$system_log$line$'\n' +-- +2.55.0 + diff --git a/SOURCES/0104-Fix-symlink-following-in-event-handler-scripts.patch b/SOURCES/0104-Fix-symlink-following-in-event-handler-scripts.patch new file mode 100644 index 0000000..c72373d --- /dev/null +++ b/SOURCES/0104-Fix-symlink-following-in-event-handler-scripts.patch @@ -0,0 +1,484 @@ +From 23087aa718b3a21d17a5e22399769e183c3b3db9 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 7 Aug 2026 13:20:17 +0200 +Subject: [PATCH 4/5] Fix symlink following in event handler scripts + +Resolves: CVE-2026-54230 + +Event handler scripts write output files using shell redirections and +Python open() which follow symlinks. An attacker who controls the dump +directory can plant symlinks to redirect root-owned writes to arbitrary +files such as /var/spool/cron/root. + +Replace shell redirections with dd(1) using oflag=nofollow and conv=excl +flags, which mirror the O_NOFOLLOW|O_EXCL protection used by libreport's +dd_save_text()/create_new_file_at(). For Python scripts, use os.open() +with O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW via dir_fd for safe writes. + +Co-Authored-By: Claude Opus 4.6 +--- + src/daemon/abrt-handle-upload.in | 6 +++++- + src/daemon/abrt_event.conf | 9 +++++---- + src/plugins/abrt-action-analyze-core.in | 15 +++++++++++++++ + src/plugins/abrt-action-analyze-vmcore.in | 12 +++++++++++- + .../abrt-action-check-oops-for-alt-component.in | 16 ++++++++++++++++ + .../abrt-action-check-oops-for-hw-error.in | 16 ++++++++++++++++ + src/plugins/abrt-action-generate-machine-id | 17 +++++++++++++++-- + src/plugins/abrt-action-list-dsos | 15 +++++++++++++++ + src/plugins/ccpp_event.conf | 6 +++--- + src/plugins/gconf_event.conf | 2 +- + src/plugins/koops_event.conf | 2 +- + src/plugins/machine-id_event.conf | 2 +- + src/plugins/python3_event.conf | 2 +- + src/plugins/python_event.conf | 2 +- + src/plugins/smart_event.conf | 9 ++++++--- + src/plugins/sosreport_event.conf | 2 +- + src/plugins/vimrc_event.conf | 8 ++++---- + src/plugins/vmcore_event.conf | 4 ++-- + src/plugins/xorg_event.conf | 12 ++++++------ + 19 files changed, 125 insertions(+), 32 deletions(-) + +diff --git a/src/daemon/abrt-handle-upload.in b/src/daemon/abrt-handle-upload.in +index 469c2ae..53ac88d 100755 +--- a/src/daemon/abrt-handle-upload.in ++++ b/src/daemon/abrt-handle-upload.in +@@ -38,7 +38,11 @@ def init_gettext(): + import problem + + def write_bytes_to(filename, b, uid, gid, mode): +- fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode) ++ try: ++ os.unlink(filename) ++ except FileNotFoundError: ++ pass ++ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, mode) + if fd >= 0: + os.fchown(fd, uid, gid) + os.write(fd, b) +diff --git a/src/daemon/abrt_event.conf b/src/daemon/abrt_event.conf +index 9c75a4e..834a8c8 100644 +--- a/src/daemon/abrt_event.conf ++++ b/src/daemon/abrt_event.conf +@@ -67,20 +67,21 @@ EVENT=post-create remote!=1 + # uid file is missing for problems visible to all users + # (oops scanner is often set up to not create it). + # Record username only if uid element is present: +- if [ -f uid ]; then getent passwd "`cat uid`" | cut -d: -f1 >username; fi ++ if [ -f uid ]; then rm -f username && getent passwd "`cat uid`" | cut -d: -f1 | dd of=username oflag=nofollow conv=excl status=none; fi + # Save cpuinfo because crashes in some components are + # related to HW acceleration. The file must be captured for all crashes + # because of the library vs. executable problem. ++ rm -f "$DUMP_DIR/cpuinfo" + if command -v lscpu >/dev/null 2>&1; then + # use lscpu if installed +- lscpu > $DUMP_DIR/cpuinfo ++ lscpu | dd of="$DUMP_DIR/cpuinfo" oflag=nofollow conv=excl status=none + else +- cp /proc/cpuinfo $DUMP_DIR/cpuinfo ++ dd if=/proc/cpuinfo of="$DUMP_DIR/cpuinfo" oflag=nofollow conv=excl status=none + fi + + # Record runlevel (if not yet done) and don't return non-0 if it fails: + EVENT=post-create runlevel= remote!=1 +- runlevel >runlevel 2>&1 ++ rm -f runlevel && runlevel 2>&1 | dd of=runlevel oflag=nofollow conv=excl status=none + exit 0 + + # A dummy EVENT=post-create for uploaded problems. +diff --git a/src/plugins/abrt-action-analyze-core.in b/src/plugins/abrt-action-analyze-core.in +index 9aca379..c6f7b19 100644 +--- a/src/plugins/abrt-action-analyze-core.in ++++ b/src/plugins/abrt-action-analyze-core.in +@@ -35,8 +35,23 @@ def error_msg_and_die(s): + sys.stderr.write("%s\n" % s) + sys.exit(1) + ++def safe_open_for_write(filename): ++ dir_fd = os.open(".", os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink(filename, dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ return os.fdopen(fd, 'w') ++ + def xopen(name, mode): + try: ++ if mode == "w": ++ return safe_open_for_write(name) + r = open(name, mode) + except IOError as ex: + error_msg_and_die("Can't open '%s': %s" % (name, ex)) +diff --git a/src/plugins/abrt-action-analyze-vmcore.in b/src/plugins/abrt-action-analyze-vmcore.in +index c91737f..32b4ae2 100644 +--- a/src/plugins/abrt-action-analyze-vmcore.in ++++ b/src/plugins/abrt-action-analyze-vmcore.in +@@ -86,7 +86,17 @@ if __name__ == "__main__": + if crash.returncode != 0: + error_msg_and_die(_("Can't process {0}:\n{1}").format(vmcore, err)) + +- backtrace_file = open("backtrace", "w") ++ dir_fd = os.open(".", os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink("backtrace", dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ bt_fd = os.open("backtrace", os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ backtrace_file = os.fdopen(bt_fd, "w") + dump_oops = Popen(["abrt-dump-oops", "-u", ".", dmesg_log], stdout=backtrace_file, stderr=PIPE, bufsize=-1) + out, err = dump_oops.communicate() + backtrace_file.close() +diff --git a/src/plugins/abrt-action-check-oops-for-alt-component.in b/src/plugins/abrt-action-check-oops-for-alt-component.in +index 3e8d853..963d2c4 100644 +--- a/src/plugins/abrt-action-check-oops-for-alt-component.in ++++ b/src/plugins/abrt-action-check-oops-for-alt-component.in +@@ -45,8 +45,24 @@ def get_new_component(filename): + f.close() + return None + ++def safe_open_for_write(filename): ++ dir_fd = os.open(".", os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink(filename, dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ return os.fdopen(fd, 'w') ++ ++ + def open_or_die(filename, mode): + try: ++ if mode == "w": ++ return safe_open_for_write(filename) + f = open(filename, mode) + except IOError as e: + sys.stderr.write(str(e) + "\n") +diff --git a/src/plugins/abrt-action-check-oops-for-hw-error.in b/src/plugins/abrt-action-check-oops-for-hw-error.in +index f5e0afd..bc07767 100644 +--- a/src/plugins/abrt-action-check-oops-for-hw-error.in ++++ b/src/plugins/abrt-action-check-oops-for-hw-error.in +@@ -47,8 +47,24 @@ def tail_with_search(filename, string, maxlen): + return retval + + ++def safe_open_for_write(filename): ++ dir_fd = os.open(".", os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink(filename, dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ return os.fdopen(fd, 'w') ++ ++ + def open_or_die(filename, mode): + try: ++ if mode == "w": ++ return safe_open_for_write(filename) + f = open(filename, mode) + except IOError as e: + sys.stderr.write(str(e) + "\n") +diff --git a/src/plugins/abrt-action-generate-machine-id b/src/plugins/abrt-action-generate-machine-id +index 3cb145a..8d465f5 100644 +--- a/src/plugins/abrt-action-generate-machine-id ++++ b/src/plugins/abrt-action-generate-machine-id +@@ -25,7 +25,6 @@ import sys + from argparse import ArgumentParser + from subprocess import check_output + import logging +- + import hashlib + + def generate_machine_id_dmidecode(): +@@ -171,7 +170,21 @@ if __name__ == '__main__': + + if ARGS['output']: + try: +- with open(ARGS['output'], 'w') as fout: ++ output_path = ARGS['output'] ++ output_dir = os.path.dirname(output_path) or '.' ++ output_name = os.path.basename(output_path) ++ dir_fd = os.open(output_dir, os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink(output_name, dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ fd = os.open(output_name, ++ os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ with os.fdopen(fd, 'w') as fout: + print_result(machineids, fout, not ARGS['noprefix']) + except IOError as ex: + logging.error("Could not open output file: {0}".format(str(ex))) +diff --git a/src/plugins/abrt-action-list-dsos b/src/plugins/abrt-action-list-dsos +index 8bf5415..bf828e4 100644 +--- a/src/plugins/abrt-action-list-dsos ++++ b/src/plugins/abrt-action-list-dsos +@@ -17,8 +17,23 @@ def error_msg_and_die(s): + sys.stderr.write("%s\n" % s) + sys.exit(1) + ++def safe_open_for_write(filename): ++ dir_fd = os.open(".", os.O_DIRECTORY | os.O_NOFOLLOW) ++ try: ++ try: ++ os.unlink(filename, dir_fd=dir_fd) ++ except FileNotFoundError: ++ pass ++ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, ++ 0o640, dir_fd=dir_fd) ++ finally: ++ os.close(dir_fd) ++ return os.fdopen(fd, 'w') ++ + def xopen(name, mode): + try: ++ if mode == "w": ++ return safe_open_for_write(name) + r = open(name, mode) + except IOError as e: + error_msg_and_die("Can't open '%s': %s" % (name, e)) +diff --git a/src/plugins/ccpp_event.conf b/src/plugins/ccpp_event.conf +index e89e98b..a806609 100644 +--- a/src/plugins/ccpp_event.conf ++++ b/src/plugins/ccpp_event.conf +@@ -36,7 +36,7 @@ EVENT=post-create type=CCpp remote!=1 + user_log=$user_log$line$'\n' + fi + done <<< "$user_log_full" +- test -n "${user_log::-1}" && printf "User Logs:\n--%s--\n" "$user_log" >$DUMP_DIR/var_log_messages ++ test -n "${user_log::-1}" && rm -f "$DUMP_DIR/var_log_messages" && printf "User Logs:\n--%s--\n" "$user_log" | dd of="$DUMP_DIR/var_log_messages" oflag=nofollow conv=excl status=none + # Do not use '&&' here because if $user_log is the empty string + # then the script does not continue to get the system logs + { +@@ -49,7 +49,7 @@ EVENT=post-create type=CCpp remote!=1 + system_log=$system_log$line$'\n' + fi + done <<< "$system_log_full" +- test -n "${system_log::-1}" && printf "System Logs:\n--%s--\n" "$system_log" >$DUMP_DIR/var_log_messages ++ test -n "${system_log::-1}" && rm -f "$DUMP_DIR/var_log_messages" && printf "System Logs:\n--%s--\n" "$system_log" | dd of="$DUMP_DIR/var_log_messages" oflag=nofollow conv=excl status=none + # Always exit with true here, because the false at + # the beginning would cause the post-create hook to remove + # the current problem directory. +@@ -71,7 +71,7 @@ EVENT=collect_xsession_errors type=CCpp dso_list~=.*/libX11.* + test -r "$xsession_errors" || { echo "Can't read $xsession_errors"; exit 0; } + executable=`cat executable` && + base_executable=${executable##*/} && +- grep -F -e "$base_executable" "$xsession_errors" | tail -999 >xsession_errors && ++ rm -f xsession_errors && grep -F -e "$base_executable" "$xsession_errors" | tail -999 | dd of=xsession_errors oflag=nofollow conv=excl status=none && + echo "Element 'xsession_errors' saved" + + # TODO: can we still specify additional directories to search for debuginfos, +diff --git a/src/plugins/gconf_event.conf b/src/plugins/gconf_event.conf +index 2e1f8ae..1d37493 100644 +--- a/src/plugins/gconf_event.conf ++++ b/src/plugins/gconf_event.conf +@@ -6,7 +6,7 @@ EVENT=collect_GConf type=CCpp dso_list~=.*/libgconf-2.* + gconftool-2 --dir-exists=$gconfdir || + { echo "GConf directory $gconfdir does not exist"; exit 0; } + } && +- gconftool-2 --recursive-list $gconfdir >gconf_subtree && ++ rm -f gconf_subtree && gconftool-2 --recursive-list $gconfdir | dd of=gconf_subtree oflag=nofollow conv=excl status=none && + echo "Element 'gconf_subtree' saved" + + +diff --git a/src/plugins/koops_event.conf b/src/plugins/koops_event.conf +index 5e53723..a59eeee 100644 +--- a/src/plugins/koops_event.conf ++++ b/src/plugins/koops_event.conf +@@ -4,7 +4,7 @@ EVENT=post-create type=Kerneloops remote!=1 + if [ "$(cat /proc/sys/kernel/dmesg_restrict)" == "0" ]; then + # >> instead of > is due to bugzilla.redhat.com/854266 + # 'dmesg' file is required by check-oops-for-hw-error +- dmesg >>dmesg ++ dmesg | dd of=dmesg oflag=nofollow,append conv=notrunc status=none + abrt-action-check-oops-for-hw-error + fi + { +diff --git a/src/plugins/machine-id_event.conf b/src/plugins/machine-id_event.conf +index 2825911..76979ab 100644 +--- a/src/plugins/machine-id_event.conf ++++ b/src/plugins/machine-id_event.conf +@@ -1,3 +1,3 @@ + #if you want to include *machineid* in dump directories: + EVENT=post-create remote!=1 +- /usr/libexec/abrt-action-generate-machine-id -o $DUMP_DIR/machineid >>event_log 2>&1 || : ++ /usr/libexec/abrt-action-generate-machine-id -o $DUMP_DIR/machineid 2>&1 | dd of=event_log oflag=nofollow,append conv=notrunc status=none || : +diff --git a/src/plugins/python3_event.conf b/src/plugins/python3_event.conf +index 481a1c4..c317ec5 100644 +--- a/src/plugins/python3_event.conf ++++ b/src/plugins/python3_event.conf +@@ -10,7 +10,7 @@ EVENT=post-create type=Python3 remote!=1 + abrt-action-analyze-python + # save Python3 package version + for line in $(rpm -qf $(which $(cut -d' ' -f1 < cmdline)) 2>/dev/null); do +- echo -n $line > interpreter ++ rm -f interpreter && echo -n $line | dd of=interpreter oflag=nofollow conv=excl status=none + done + + EVENT=report_Bugzilla type=Python3 component!=anaconda +diff --git a/src/plugins/python_event.conf b/src/plugins/python_event.conf +index 1824364..2ec4cc7 100644 +--- a/src/plugins/python_event.conf ++++ b/src/plugins/python_event.conf +@@ -10,7 +10,7 @@ EVENT=post-create type=Python remote!=1 + abrt-action-analyze-python + # save Python2 package version + for line in $(rpm -qf $(which $(cut -d' ' -f1 < cmdline)) 2>/dev/null); do +- echo -n $line > interpreter ++ rm -f interpreter && echo -n $line | dd of=interpreter oflag=nofollow conv=excl status=none + done + + EVENT=report_Bugzilla type=Python component!=anaconda +diff --git a/src/plugins/smart_event.conf b/src/plugins/smart_event.conf +index 2a0efb5..75fc0fe 100644 +--- a/src/plugins/smart_event.conf ++++ b/src/plugins/smart_event.conf +@@ -9,24 +9,27 @@ + + EVENT=post-create component=gnome-disk-utility remote!=1 + which skdump >/dev/null 2>&1 || exit 0 ++ rm -f smart_data + for f in /dev/[sh]d[a-z]; do + test -e "$f" || continue + skdump "$f" + echo +- done >smart_data ++ done | dd of=smart_data oflag=nofollow conv=excl status=none + + EVENT=post-create component=libatasmart remote!=1 + which skdump >/dev/null 2>&1 || exit 0 ++ rm -f smart_data + for f in /dev/[sh]d[a-z]; do + test -e "$f" || continue + skdump "$f" + echo +- done >smart_data ++ done | dd of=smart_data oflag=nofollow conv=excl status=none + + EVENT=post-create component=udisks remote!=1 + which skdump >/dev/null 2>&1 || exit 0 ++ rm -f smart_data + for f in /dev/[sh]d[a-z]; do + test -e "$f" || continue + skdump "$f" + echo +- done >smart_data ++ done | dd of=smart_data oflag=nofollow conv=excl status=none +diff --git a/src/plugins/sosreport_event.conf b/src/plugins/sosreport_event.conf +index de5dfa7..988af6c 100644 +--- a/src/plugins/sosreport_event.conf ++++ b/src/plugins/sosreport_event.conf +@@ -11,7 +11,7 @@ EVENT=post-create remote!=1 + --only=cups --only=logs --only=grub2 --only=cron --only=pci \ + --only=auditd --only=selinux --only=lvm2 --only=sar \ + --only=processor \ +- >sosreport.log 2>&1 \ ++ 2>&1 | dd of=sosreport.log oflag=nofollow conv=excl status=none \ + && { + rm sosreport.log + rm sosreport*.md5 +diff --git a/src/plugins/vimrc_event.conf b/src/plugins/vimrc_event.conf +index cef991a..e011f29 100644 +--- a/src/plugins/vimrc_event.conf ++++ b/src/plugins/vimrc_event.conf +@@ -6,13 +6,13 @@ EVENT=collect_vimrc_user component=vim + gvimrc=~/.gvimrc + saved=none + if [ -r $vimrc -a -f $vimrc ]; then +- cp $vimrc user_vimrc || exit $? ++ rm -f user_vimrc && dd if="$vimrc" of=user_vimrc oflag=nofollow conv=excl status=none || exit $? + saved="$saved, user_vimrc" + else + echo "File $vimrc not found" + fi + if [ -r $gvimrc -a -f $gvimrc ]; then +- cp $gvimrc user_gvimrc || exit $? ++ rm -f user_gvimrc && dd if="$gvimrc" of=user_gvimrc oflag=nofollow conv=excl status=none || exit $? + saved="$saved, user_gvimrc" + else + echo "File $gvimrc not found" +@@ -24,13 +24,13 @@ EVENT=collect_vimrc_system component=vim + gvimrc=/etc/gvimrc + saved=none + if [ -r $vimrc -a -f $vimrc ]; then +- cp $vimrc system_vimrc || exit $? ++ rm -f system_vimrc && dd if="$vimrc" of=system_vimrc oflag=nofollow conv=excl status=none || exit $? + saved="$saved, system_vimrc" + else + echo "File $vimrc not found" + fi + if [ -r $gvimrc -a -f $gvimrc ]; then +- cp $gvimrc system_gvimrc || exit $? ++ rm -f system_gvimrc && dd if="$gvimrc" of=system_gvimrc oflag=nofollow conv=excl status=none || exit $? + saved="$saved, system_gvimrc" + else + echo "File $gvimrc not found" +diff --git a/src/plugins/vmcore_event.conf b/src/plugins/vmcore_event.conf +index 61bc9d1..6592a9f 100644 +--- a/src/plugins/vmcore_event.conf ++++ b/src/plugins/vmcore_event.conf +@@ -12,7 +12,7 @@ EVENT=post-create type=vmcore remote!=1 + # MCE oopses don't have kernel version in them, + # but it should be specified earlier in the log. + k=`sed -n '/Linux version/ s/.*Linux version \([^ ]*\) .*/\1/p' vmcore-dmesg.txt | tail -n1` +- test "$k" != "" && printf "%s" "$k" >kernel ++ test "$k" != "" && rm -f kernel && printf "%s" "$k" | dd of=kernel oflag=nofollow conv=excl status=none + else + # No vmcore-dmesg.txt, do it the hard way: + abrt-action-analyze-vmcore || exit $? +@@ -23,7 +23,7 @@ EVENT=post-create type=vmcore remote!=1 + # Try creating it from dmesg_log (created by abrt-action-analyze-vmcore): + test -f dmesg_log || exit 0 + k=`sed -n '/Linux version/ s/.*Linux version \([^ ]*\) .*/\1/p' dmesg_log | tail -n1` +- test "$k" != "" && printf "%s" "$k" >kernel ++ test "$k" != "" && rm -f kernel && printf "%s" "$k" | dd of=kernel oflag=nofollow conv=excl status=none + fi + ) + # Do not fail the event (->do not delete problem dir) +diff --git a/src/plugins/xorg_event.conf b/src/plugins/xorg_event.conf +index 8d0d585..d183070 100644 +--- a/src/plugins/xorg_event.conf ++++ b/src/plugins/xorg_event.conf +@@ -6,13 +6,13 @@ EVENT=post-create type=xorg remote!=1 + # Get versions of binaries listed in Xorg backtrace + abrt-action-list-dsos -m backtrace -o dso_list + # +- test -f /var/log/Xorg.0.log && cp /var/log/Xorg.0.log . +- test -f /etc/X11/xorg.conf && cp /etc/X11/xorg.conf . +- test -d /etc/X11/xorg.conf.d && tar czf etc_X11_xorg_conf_d.tar.gz /etc/X11/xorg.conf.d +- test -d /usr/share/X11/xorg.conf.d && tar czf usr_share_xorg_conf_d.tar.gz /usr/share/X11/xorg.conf.d ++ test -f /var/log/Xorg.0.log && rm -f Xorg.0.log && dd if=/var/log/Xorg.0.log of=Xorg.0.log oflag=nofollow conv=excl status=none ++ test -f /etc/X11/xorg.conf && rm -f xorg.conf && dd if=/etc/X11/xorg.conf of=xorg.conf oflag=nofollow conv=excl status=none ++ test -d /etc/X11/xorg.conf.d && rm -f etc_X11_xorg_conf_d.tar.gz && tar cz /etc/X11/xorg.conf.d | dd of=etc_X11_xorg_conf_d.tar.gz oflag=nofollow conv=excl status=none ++ test -d /usr/share/X11/xorg.conf.d && rm -f usr_share_xorg_conf_d.tar.gz && tar cz /usr/share/X11/xorg.conf.d | dd of=usr_share_xorg_conf_d.tar.gz oflag=nofollow conv=excl status=none + # +- # >> instead of > is due to bugzilla.redhat.com/show_bug.cgi?id=854266 +- dmesg >>dmesg ++ # append instead of overwrite is due to bugzilla.redhat.com/show_bug.cgi?id=854266 ++ dmesg | dd of=dmesg oflag=nofollow,append conv=notrunc status=none + # + # save lspci -vvv output? + +-- +2.55.0 + diff --git a/SOURCES/0105-Fix-journal-entry-spoofing-in-journal-dump-services.patch b/SOURCES/0105-Fix-journal-entry-spoofing-in-journal-dump-services.patch new file mode 100644 index 0000000..ca3e117 --- /dev/null +++ b/SOURCES/0105-Fix-journal-entry-spoofing-in-journal-dump-services.patch @@ -0,0 +1,62 @@ +From c58261630365a758d02d7560c61669d1ee2e7845 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 7 Aug 2026 13:28:15 +0200 +Subject: [PATCH 5/5] Fix journal entry spoofing in journal dump services + +Related: CVE-2026-54231 + +Filter journal messages on trusted fields (underscore-prefixed, set by +the kernel/journald) in addition to the user-settable SYSLOG_IDENTIFIER. +Without this, a local unprivileged user can inject fake journal entries +that ABRT processes as genuine crashes or kernel oopses. + +abrt-dump-journal-core: require _EXE=/usr/lib/systemd/systemd-coredump +and _COMM=systemd-coredum so only entries genuinely written by +systemd-coredump are processed. + +abrt-dump-journal-oops: require _TRANSPORT=kernel so only messages from +the kernel ring buffer are processed. + +Co-Authored-By: Claude Opus 4.6 +--- + src/plugins/abrt-dump-journal-core.c | 9 +++++++++ + src/plugins/abrt-dump-journal-oops.c | 3 +++ + 2 files changed, 12 insertions(+) + +diff --git a/src/plugins/abrt-dump-journal-core.c b/src/plugins/abrt-dump-journal-core.c +index 33ae3d6..7e4d9f4 100644 +--- a/src/plugins/abrt-dump-journal-core.c ++++ b/src/plugins/abrt-dump-journal-core.c +@@ -573,6 +573,15 @@ main(int argc, char *argv[]) + coredump_journal_filter = g_list_append(coredump_journal_filter, + (env_journal_filter ? (gpointer)env_journal_filter : (gpointer)"SYSLOG_IDENTIFIER=systemd-coredump")); + ++ if (!env_journal_filter) ++ { ++ /* Filter on trusted fields (set by the kernel, not spoofable) to ++ * ensure we only process genuine systemd-coredump entries. ++ * "systemd-coredum" is not a typo — the kernel truncates _COMM to 15 chars. */ ++ coredump_journal_filter = g_list_append(coredump_journal_filter, (gpointer)"_EXE=/usr/lib/systemd/systemd-coredump"); ++ coredump_journal_filter = g_list_append(coredump_journal_filter, (gpointer)"_COMM=systemd-coredum"); ++ } ++ + abrt_journal_t *journal = NULL; + if (abrt_journal_new(&journal)) + error_msg_and_die(_("Cannot open systemd-journal")); +diff --git a/src/plugins/abrt-dump-journal-oops.c b/src/plugins/abrt-dump-journal-oops.c +index b820438..886092f 100644 +--- a/src/plugins/abrt-dump-journal-oops.c ++++ b/src/plugins/abrt-dump-journal-oops.c +@@ -273,6 +273,9 @@ int main(int argc, char *argv[]) + kernel_journal_filter = g_list_append(kernel_journal_filter, + (env_journal_filter ? (gpointer)env_journal_filter : (gpointer)"SYSLOG_IDENTIFIER=kernel")); + ++ if (!env_journal_filter) ++ kernel_journal_filter = g_list_append(kernel_journal_filter, (gpointer)"_TRANSPORT=kernel"); ++ + abrt_journal_t *journal = NULL; + if ((opts & OPT_J)) + { +-- +2.55.0 + diff --git a/SPECS/abrt.spec b/SPECS/abrt.spec index 1f6663f..31094d2 100644 --- a/SPECS/abrt.spec +++ b/SPECS/abrt.spec @@ -55,7 +55,7 @@ Summary: Automatic bug detection and reporting tool Name: abrt Version: 2.10.9 -Release: 25%{?dist}.alma.1 +Release: 26%{?dist}.alma.1 License: GPLv2+ URL: https://abrt.readthedocs.org/ Source: https://github.com/abrt/%{name}/archive/%{version}/%{name}-%{version}.tar.gz @@ -164,6 +164,11 @@ Patch0091: 0091-plugins-Update-sosreport-event.patch Patch0092: 0092-abrt-dump-oops-Fix-vmcore-call-trace-parsing.patch # CVE-2025-12744 Patch0096: 0096-CVE-2025-12744.patch +Patch0101: 0101-Fix-race-condition-in-ChownProblemDir.patch +Patch0102: 0102-Fix-TOCTOU-in-SetElement-DeleteElement.patch +Patch0103: 0103-Fix-content-injection-in-journal-log-collection.patch +Patch0104: 0104-Fix-symlink-following-in-event-handler-scripts.patch +Patch0105: 0105-Fix-journal-entry-spoofing-in-journal-dump-services.patch # autogen.sh is need to regenerate all the Makefile files Patch1000: 1000-Add-autogen.sh.patch @@ -1375,12 +1380,24 @@ killall abrt-dbus >/dev/null 2>&1 || : %config(noreplace) %{_sysconfdir}/profile.d/abrt-console-notification.sh %changelog -* Wed Dec 10 2025 Andrei Lukoshko - 2.10.9-25.alma.1 +* Wed Aug 12 2026 Andrei Lukoshko - 2.10.9-26.alma.1 - Add support for GPG subkeys -* Wed Dec 10 2025 Sergey Fokin - 2.10.9-25.alma.1 +* Wed Aug 12 2026 Sergey Fokin - 2.10.9-26.alma.1 - apply debranding +* Thu Aug 07 2026 Michal Srb - 2.10.9-26 +- Fix race condition in ChownProblemDir +- Resolves: CVE-2026-54229 +- Fix TOCTOU in SetElement/DeleteElement +- Resolves: CVE-2026-54228 +- Fix content injection in journal log collection +- Resolves: CVE-2026-54231 +- Fix symlink following in event handler scripts +- Resolves: CVE-2026-54230 +- Fix journal entry spoofing in journal dump services +- Related: CVE-2026-54231 + * Tue Nov 18 2025 Michal Srb - 2.10.9-25 - a-a-save-container-data: validate input - Resolves: CVE-2025-12744