[packages/polkit] Rel 2; fix CVE-2026-4897 and CVE-2026-85498, agent session use-after-free

arekm arekm at pld-linux.org
Wed Sep 16 08:46:39 CEST 2026


commit 7cef6aab61b36937890edb29f6ce046916ad7beb
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Wed Sep 16 08:11:49 2026 +0200

    Rel 2; fix CVE-2026-4897 and CVE-2026-85498, agent session use-after-free

 CVE-2026-4897.patch                       | 88 +++++++++++++++++++++++++++++++
 CVE-2026-85498.patch                      | 34 ++++++++++++
 polkit-agent-session-use-after-free.patch | 80 ++++++++++++++++++++++++++++
 polkit.spec                               | 42 ++++++++++++---
 4 files changed, 238 insertions(+), 6 deletions(-)
---
diff --git a/polkit.spec b/polkit.spec
index af22efe..63f270d 100644
--- a/polkit.spec
+++ b/polkit.spec
@@ -3,6 +3,7 @@
 %bcond_without	apidocs		# build without apidocs
 %bcond_without	consolekit	# ConsoleKit fallback
 %bcond_without	systemd		# use systemd-login for session tracking (fallback to ConsoleKit on runtime)
+%bcond_without	tests		# test suite
 %bcond_with	elogind		# use elogind instead of systemd-login
 
 %if %{with elogind}
@@ -12,12 +13,15 @@ Summary:	A framework for defining policy for system-wide components
 Summary(pl.UTF-8):	Szkielet do definiowania polityki dla komponentów systemowych
 Name:		polkit
 Version:	127
-Release:	1
+Release:	2
 License:	LGPL v2+
 Group:		Libraries
 Source0:	https://github.com/polkit-org/polkit/archive/%{version}/%{name}-%{version}.tar.gz
 # Source0-md5:	2cc95f1b02fc1de6c9e52db986642ec4
 Patch0:		systemd-fallback.patch
+Patch1:		CVE-2026-4897.patch
+Patch2:		CVE-2026-85498.patch
+Patch3:		polkit-agent-session-use-after-free.patch
 URL:		https://github.com/polkit-org/polkit
 BuildRequires:	dbus-devel
 BuildRequires:	docbook-dtd412-xml
@@ -31,17 +35,28 @@ BuildRequires:	glib2-devel >= 1:2.44.0
 BuildRequires:	glibc-localedb-all
 %endif
 BuildRequires:	gobject-introspection-devel >= 0.6.2
-BuildRequires:	gtk-doc >= 1.3
-BuildRequires:	gtk-doc-automake >= 1.3
-BuildRequires:	libstdc++-devel >= 6:7
+%{?with_apidocs:BuildRequires:	gtk-doc >= 1.3}
 BuildRequires:	libxslt-progs
 BuildRequires:	meson >= 1.4.0
 BuildRequires:	ninja
 BuildRequires:	pam-devel >= 0.80
 BuildRequires:	pkgconfig
+%if %{with tests}
+BuildRequires:	/bin/mount
+BuildRequires:	python3-dbus
+BuildRequires:	python3-dbusmock
+%endif
 BuildRequires:	rpm-build >= 4.6
 BuildRequires:	rpmbuild(macros) >= 2.042
 %{?with_systemd:BuildRequires:	systemd-devel}
+Requires(postun):	/usr/sbin/groupdel
+Requires(postun):	/usr/sbin/userdel
+Requires(pre):	/bin/id
+Requires(pre):	/usr/bin/getgid
+Requires(pre):	/usr/lib/rpm/user_group.sh
+Requires(pre):	/usr/sbin/groupadd
+Requires(pre):	/usr/sbin/useradd
+Requires(pre):	/usr/sbin/usermod
 Requires:	%{name}-libs = %{version}-%{release}
 %if %{without systemd} && %{without elogind}
 Requires:	ConsoleKit >= 0.4.1
@@ -115,21 +130,29 @@ Pliki nagłówkowe PolicyKit.
 %if %{with consolekit} && (%{with systemd} || %{with elogind})
 %patch -P0 -p1
 %endif
+%patch -P1 -p1
+%patch -P2 -p1
+%patch -P3 -p1
 
 %build
 %meson \
 	-Dgtk_doc=%{__true_false apidocs} \
-	-Dtests=false \
+	-Dtests=%{__true_false tests} \
 	-Dsession_tracking=%{?with_systemd:logind}%{?with_elogind:elogind} \
 	-Dpam_include=system-auth \
 	-Dpam_module_dir=/%{_lib}/security \
 	-Dpolkitd_user=polkitd \
 	-Dpolkitd_uid=283 \
 	-Dexamples=true \
-	-Dman=true
+	-Dman=true \
+	-Dgettext=true
 
 %meson_build
 
+%if %{with tests}
+%meson_test
+%endif
+
 %install
 rm -rf $RPM_BUILD_ROOT
 
@@ -145,6 +168,13 @@ rm -rf $RPM_BUILD_ROOT
 %useradd -u 283 -s /bin/false -c "polkitd pseudo user" -g polkitd polkitd
 %addusertogroup polkitd proc
 
+%preun
+# The socket-activated helper needs SO_PEERPIDFD (kernel >= 6.5) and PolkitAgentSession
+# falls back to the setuid helper only when the connect fails, so on older kernels an
+# enabled socket breaks authentication outright; the socket is therefore never enabled
+# on install, only deregistered here. https://github.com/polkit-org/polkit/issues/639
+%{?with_systemd:%systemd_preun polkit-agent-helper.socket}
+
 %postun
 if [ "$1" = "0" ]; then
 	%userremove polkitd
diff --git a/CVE-2026-4897.patch b/CVE-2026-4897.patch
new file mode 100644
index 0000000..6cab4ea
--- /dev/null
+++ b/CVE-2026-4897.patch
@@ -0,0 +1,88 @@
+From 7e122c8a5120c2aae2d9d44a26796dc18f5b677c Mon Sep 17 00:00:00 2001
+From: Jan Rybar <jrybar at redhat.com>
+Date: Fri, 27 Mar 2026 15:57:01 +0100
+Subject: [PATCH] CVE-2026-4897 - getline() string overflow
+
+Report and fix by Aisle.com
+Pavel Kohout, Aisle Research
+
+Signed-off-by: Jan Rybar jrybar at redhat.com
+---
+ src/polkitagent/polkitagenthelperprivate.c | 23 +++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c
+index 35bca85a..7e4f94eb 100644
+--- a/src/polkitagent/polkitagenthelperprivate.c
++++ b/src/polkitagent/polkitagenthelperprivate.c
+@@ -24,6 +24,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
++#include <errno.h>
+ #include <unistd.h>
+ 
+ #ifndef HAVE_CLEARENV
+@@ -59,21 +60,25 @@ read_cookie (int argc, char **argv)
+     return strdup (argv[2]);
+   else
+     {
+-      char *ret = NULL;
+-      size_t n = 0;
+-      ssize_t r = getline (&ret, &n, stdin);
+-      if (r == -1)
++      #define POLKIT_AGENT_MAX_COOKIE 4096
++      char buf[POLKIT_AGENT_MAX_COOKIE + 2]; /* +1 for newline, +1 for NUL */
++      if (fgets (buf, sizeof(buf), stdin) == NULL)
+         {
+           if (!feof (stdin))
+-            perror ("getline");
+-          free (ret);
++            perror ("fgets");
+           return NULL;
+         }
+-      else
++      if (buf[strlen (buf) - 1] != '\n')
+         {
+-          g_strchomp (ret);
+-          return ret;
++          /* Cookie too long - drain remaining input and reject */
++          int c;
++          while ((c = getchar ()) != '\n' && c != EOF)
++            ;
++          errno = EOVERFLOW;
++          return NULL;
+         }
++      g_strchomp (buf);
++      return strdup (buf);
+     }
+ }
+ 
+From 39601309eb3e5e88a1c1fbda9a272ba8691f1bf3 Mon Sep 17 00:00:00 2001
+From: Jan Rybar <jrybar at redhat.com>
+Date: Wed, 13 May 2026 14:58:32 +0200
+Subject: [PATCH] Draining loop can keep polkit busy
+
+The draining loop is not really appropriate for pipe input, especially
+in a daemon.
+
+Co-authored-by: Frantisek Sumsal <fsumsal at redhat.com>
+---
+ src/polkitagent/polkitagenthelperprivate.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c
+index 7e4f94eb..c0a98251 100644
+--- a/src/polkitagent/polkitagenthelperprivate.c
++++ b/src/polkitagent/polkitagenthelperprivate.c
+@@ -70,10 +70,6 @@ read_cookie (int argc, char **argv)
+         }
+       if (buf[strlen (buf) - 1] != '\n')
+         {
+-          /* Cookie too long - drain remaining input and reject */
+-          int c;
+-          while ((c = getchar ()) != '\n' && c != EOF)
+-            ;
+           errno = EOVERFLOW;
+           return NULL;
+         }
diff --git a/CVE-2026-85498.patch b/CVE-2026-85498.patch
new file mode 100644
index 0000000..e65006d
--- /dev/null
+++ b/CVE-2026-85498.patch
@@ -0,0 +1,34 @@
+From eea172967848bb4c5a407329f40c0e45de0d187e Mon Sep 17 00:00:00 2001
+From: Jan Rybar <jrybar at redhat.com>
+Date: Thu, 27 Aug 2026 15:02:45 +0200
+Subject: [PATCH] CVE-2026-85498: Unsanitized underflow in cookie input
+
+Credits for the report:
+Sunwoo Lee, Korea Institute of Energy Technology (KENTECH)
+Daeyoung Kang, Korea Institute of Energy Technology (KENTECH)
+Haeryong Park, Korea Internet & Security Agency (KISA)
+Hyuk Lim, Korea Institute of Energy Technology (KENTECH)
+Seunghyun Yoon, Korea Institute of Energy Technology (KENTECH)
+Juthawong Naisanguansee
+
+Co-authored-by: Jan Rybar <jrybar at redhat.com>
+---
+ src/polkitagent/polkitagenthelperprivate.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c
+index c0a98251..e2d2c9be 100644
+--- a/src/polkitagent/polkitagenthelperprivate.c
++++ b/src/polkitagent/polkitagenthelperprivate.c
+@@ -68,6 +68,11 @@ read_cookie (int argc, char **argv)
+             perror ("fgets");
+           return NULL;
+         }
++      if (buf[0] == '\0')
++        {
++          errno = EINVAL;
++          return NULL;
++        }
+       if (buf[strlen (buf) - 1] != '\n')
+         {
+           errno = EOVERFLOW;
diff --git a/polkit-agent-session-use-after-free.patch b/polkit-agent-session-use-after-free.patch
new file mode 100644
index 0000000..43e23a6
--- /dev/null
+++ b/polkit-agent-session-use-after-free.patch
@@ -0,0 +1,80 @@
+From 6f3cec7f1cfd2b0a686ce53e97e5351c80fe4f32 Mon Sep 17 00:00:00 2001
+From: Jan Rybar <jrybar at redhat.com>
+Date: Wed, 12 Aug 2026 13:27:31 +0200
+Subject: [PATCH] polkitagent: Fix use-after-free in io_watch_have_data()
+
+complete_session() emits the "completed" signal, and handlers of that
+signal are explicitly documented (and, in the case of
+PolkitAgentTextListener, actually implemented) to be allowed to drop
+the last reference to the PolkitAgentSession.
+
+io_watch_have_data() can call complete_session() once from one of its
+error/success branches and then unconditionally call it a second time
+from its epilogue whenever the dispatch also carries G_IO_ERR or
+G_IO_HUP. If the first call already caused the session to be freed via
+its "completed" handler, that second call operates on freed memory.
+
+Fix this by NULLing out the local session pointer right after each
+complete_session() call, and skipping the epilogue's call when it is
+already NULL, so we never dereference a session that may have already
+been freed.
+
+Co-authored-by: Cursor <cursoragent at cursor.com>
+---
+ src/polkitagent/polkitagentsession.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/polkitagent/polkitagentsession.c b/src/polkitagent/polkitagentsession.c
+index bcf9e993..32b2a09b 100644
+--- a/src/polkitagent/polkitagentsession.c
++++ b/src/polkitagent/polkitagentsession.c
+@@ -444,6 +444,13 @@ io_watch_have_data (GIOChannel    *channel,
+       g_warning ("in io_watch_have_data() but helper is not supposed to be running");
+ 
+       complete_session (session, FALSE);
++      /* complete_session() emits ::completed, and handlers of that signal
++       * are documented to be allowed to drop the last reference to
++       * @session (see e.g. PolkitAgentTextListener's handler). NULL out
++       * our local pointer so we can never call complete_session() again
++       * on a possibly-freed @session below.
++       */
++      session = NULL;
+       goto out;
+     }
+ 
+@@ -461,6 +468,7 @@ io_watch_have_data (GIOChannel    *channel,
+       g_clear_error (&error);
+ 
+       complete_session (session, FALSE);
++      session = NULL;
+       goto out;
+     }
+ 
+@@ -504,15 +512,18 @@ io_watch_have_data (GIOChannel    *channel,
+   else if (g_str_has_prefix (unescaped, "SUCCESS"))
+     {
+       complete_session (session, TRUE);
++      session = NULL;
+     }
+   else if (g_str_has_prefix (unescaped, "FAILURE"))
+     {
+       complete_session (session, FALSE);
++      session = NULL;
+     }
+   else
+     {
+       g_warning ("Unknown line '%s' from helper", line);
+       complete_session (session, FALSE);
++      session = NULL;
+       goto out;
+     }
+ 
+@@ -520,7 +531,7 @@ io_watch_have_data (GIOChannel    *channel,
+   g_free (line);
+   g_free (unescaped);
+ 
+-  if (condition & (G_IO_ERR | G_IO_HUP))
++  if (session != NULL && (condition & (G_IO_ERR | G_IO_HUP)))
+     complete_session (session, FALSE);
+ 
+   /* keep the IOChannel around */
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/polkit.git/commitdiff/d4979ac65926c0ffecf087b3c7ddb9bc37a260cc



More information about the pld-cvs-commit mailing list