public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] repo/gentoo:master commit in: kde-plasma/kwallet-pam/, kde-plasma/kwallet-pam/files/
@ 2017-08-31 20:54 Andreas Sturmlechner
  0 siblings, 0 replies; 2+ messages in thread
From: Andreas Sturmlechner @ 2017-08-31 20:54 UTC (permalink / raw
  To: gentoo-commits

commit:     de57d49c49b3497e738dd0b32c4c0a00fb3e3f41
Author:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
AuthorDate: Thu Aug 31 19:50:00 2017 +0000
Commit:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
CommitDate: Thu Aug 31 20:53:51 2017 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=de57d49c

kde-plasma/kwallet-pam: Fix memleaks and dropping privileges

Package-Manager: Portage-2.3.8, Repoman-2.3.3

 .../files/kwallet-pam-5.10.5-check-graphical.patch |  87 +++++++++++
 .../files/kwallet-pam-5.10.5-cleanups.patch        | 173 +++++++++++++++++++++
 .../files/kwallet-pam-5.10.5-privileges.patch      |  49 ++++++
 .../kwallet-pam/kwallet-pam-5.10.5-r1.ebuild       |  59 +++++++
 4 files changed, 368 insertions(+)

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch
new file mode 100644
index 00000000000..61ea4604586
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch
@@ -0,0 +1,87 @@
+From f3b230f7f3bf39dc46b97a216aa7c28595d20a7a Mon Sep 17 00:00:00 2001
+From: Fabian Vogt <fabian@ritter-vogt.de>
+Date: Thu, 3 Aug 2017 09:50:30 +0200
+Subject: Check for a graphical session
+
+Summary:
+Avoid running if it detects a text session. This can be overridden by adding
+"force_run" as argument.
+
+Test Plan:
+Put pam_kwallet5.so as optional in a global common-session pam file
+that is included by all other services. It is not invoked when logging in from
+a tty with getty, sudo or su and still works when using SDDM. When adding
+force_run it runs in all cases.
+
+Reviewers: #plasma
+
+Subscribers: plasma-devel
+
+Tags: #plasma
+
+Differential Revision: https://phabricator.kde.org/D7125
+---
+ pam_kwallet.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index cba57e7..46720a5 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -72,6 +72,7 @@ const static char *kwalletd = NULL;
+ const static char *socketPath = NULL;
+ const static char *kwalletPamDataKey = NULL;
+ const static char *logPrefix = NULL;
++static int force_run = 0;
+ 
+ #ifdef KWALLET5
+ const static char *envVar = "PAM_KWALLET5_LOGIN";
+@@ -98,6 +99,8 @@ static void parseArguments(int argc, const char **argv)
+             kwalletd = argv[x] + 9;
+         } else if (strstr(argv[x], "socketPath=") != NULL) {
+             socketPath= argv[x] + 11;
++        } else if (strcmp(argv[x], "force_run") == 0) {
++            force_run = 1;
+         }
+     }
+ #ifdef KWALLET5
+@@ -246,6 +249,24 @@ static void cleanup_free(pam_handle_t *pamh, void *ptr, int error_status)
+     free(ptr);
+ }
+ 
++static int is_graphical_session(pam_handle_t *pamh)
++{
++    //Detect a graphical session
++    const char *pam_tty = NULL, *pam_xdisplay = NULL,
++               *xdg_session_type = NULL, *display = NULL;
++
++    pam_get_item(pamh, PAM_TTY, (const void**) &pam_tty);
++#ifdef PAM_XDISPLAY
++    pam_get_item(pamh, PAM_XDISPLAY, (const void**) &pam_xdisplay);
++#endif
++    xdg_session_type = get_env(pamh, "XDG_SESSION_TYPE");
++
++    return (pam_xdisplay && strlen(pam_xdisplay) != 0)
++           || (pam_tty && pam_tty[0] == ':')
++           || (xdg_session_type && strcmp(xdg_session_type, "x11") == 0)
++           || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0);
++}
++
+ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
+ {
+     pam_syslog(pamh, LOG_INFO, "%s: pam_sm_authenticate\n", logPrefix);
+@@ -537,6 +558,11 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, cons
+ 
+     parseArguments(argc, argv);
+ 
++    if (!force_run && !is_graphical_session(pamh)) {
++        pam_syslog(pamh, LOG_INFO, "%s: not a graphical session, skipping. Use force_run parameter to ignore this.", logPrefix);
++        return PAM_IGNORE;
++    }
++
+     int result;
+     result = pam_set_data(pamh, "sm_open_session", "1", NULL);
+     if (result != PAM_SUCCESS) {
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch
new file mode 100644
index 00000000000..38a333131e9
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch
@@ -0,0 +1,173 @@
+From a33ec22b96e837899528b05963eae8ea6b01171a Mon Sep 17 00:00:00 2001
+From: Fabian Vogt <fabian@ritter-vogt.de>
+Date: Thu, 3 Aug 2017 09:02:14 +0200
+Subject: Several cleanups
+
+Summary:
+- No cppcheck warnings anymore
+- Use snprintf everywhere
+- Avoid pointless multiplication with sizeof(char)
+- Avoid memory leaks
+
+Test Plan: Still builds, works the same as before.
+
+Reviewers: #plasma
+
+Subscribers: plasma-devel
+
+Tags: #plasma
+
+Differential Revision: https://phabricator.kde.org/D7123
+---
+ pam_kwallet.c | 44 ++++++++++++++++++++++++++++++++------------
+ 1 file changed, 32 insertions(+), 12 deletions(-)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index d88c5e0..cba57e7 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -151,13 +151,14 @@ static int set_env(pam_handle_t *pamh, const char *name, const char *value)
+         //We do not return because pam_putenv might work
+     }
+ 
+-    char *pamEnv = malloc(strlen(name) + strlen(value) + 2); //2 is for = and \0
++    size_t pamEnvSize = strlen(name) + strlen(value) + 2; //2 is for = and \0
++    char *pamEnv = malloc(pamEnvSize);
+     if (!pamEnv) {
+         pam_syslog(pamh, LOG_WARNING, "%s: Impossible to allocate memory for pamEnv", logPrefix);
+         return -1;
+     }
+ 
+-    sprintf (pamEnv, "%s=%s", name, value);
++    snprintf (pamEnv, pamEnvSize, "%s=%s", name, value);
+     int ret = pam_putenv(pamh, pamEnv);
+     free(pamEnv);
+ 
+@@ -240,6 +241,11 @@ cleanup:
+     return result;
+ }
+ 
++static void cleanup_free(pam_handle_t *pamh, void *ptr, int error_status)
++{
++    free(ptr);
++}
++
+ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
+ {
+     pam_syslog(pamh, LOG_INFO, "%s: pam_sm_authenticate\n", logPrefix);
+@@ -297,14 +303,17 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons
+         return PAM_IGNORE;
+     }
+ 
+-    char *key = malloc(sizeof(char) * KWALLET_PAM_KEYSIZE);
+-    if (kwallet_hash(password, userInfo, key) != 0) {
++    char *key = malloc(KWALLET_PAM_KEYSIZE);
++    if (!key || kwallet_hash(password, userInfo, key) != 0) {
++        free(key);
+         pam_syslog(pamh, LOG_ERR, "%s: Fail into creating the hash", logPrefix);
+         return PAM_IGNORE;
+     }
+ 
+-    result = pam_set_data(pamh, kwalletPamDataKey, key, NULL);
++    result = pam_set_data(pamh, kwalletPamDataKey, key, cleanup_free);
++
+     if (result != PAM_SUCCESS) {
++        free(key);
+         pam_syslog(pamh, LOG_ERR, "%s: Impossible to store the hashed password: %s", logPrefix
+             , pam_strerror(pamh, result));
+         return PAM_IGNORE;
+@@ -385,9 +394,8 @@ cleanup:
+ static int better_write(int fd, const char *buffer, int len)
+ {
+     size_t writtenBytes = 0;
+-    int result;
+     while(writtenBytes < len) {
+-        result = write(fd, buffer + writtenBytes, len - writtenBytes);
++        int result = write(fd, buffer + writtenBytes, len - writtenBytes);
+         if (result < 0) {
+             if (errno != EAGAIN && errno != EINTR) {
+                 return -1;
+@@ -450,6 +458,7 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+     if (result != PAM_SUCCESS) {
+         pam_syslog(pamh, LOG_ERR, "%s: Impossible to set %s env, %s",
+                    logPrefix, envVar, pam_strerror(pamh, result));
++        free(fullSocket);
+         return;
+     }
+ 
+@@ -459,12 +468,15 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+     if (strlen(fullSocket) > sizeof(local.sun_path)) {
+         pam_syslog(pamh, LOG_ERR, "%s: socket path %s too long to open",
+                    logPrefix, fullSocket);
++        free(fullSocket);
+         return;
+     }
+     strcpy(local.sun_path, fullSocket);
++    free(fullSocket);
++    fullSocket = NULL;
+     unlink(local.sun_path);//Just in case it exists from a previous login
+ 
+-    pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, fullSocket);
++    pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, local.sun_path);
+ 
+     size_t len = strlen(local.sun_path) + sizeof(local.sun_family);
+     if (bind(envSocket, (struct sockaddr *)&local, len) == -1) {
+@@ -477,7 +489,7 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+         return;
+     }
+ 
+-    if (chown(fullSocket, userInfo->pw_uid, userInfo->pw_gid) == -1) {
++    if (chown(local.sun_path, userInfo->pw_uid, userInfo->pw_gid) == -1) {
+         pam_syslog(pamh, LOG_INFO, "%s: Couldn't change ownership of the socket", logPrefix);
+         return;
+     }
+@@ -655,7 +667,8 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
+ #else
+     char *fixpath = "share/apps/kwallet/kdewallet.salt";
+ #endif
+-    char *path = (char*) malloc(strlen(userInfo->pw_dir) + strlen(kdehome) + strlen(fixpath) + 3);//3 == / and \0
++    size_t pathSize = strlen(userInfo->pw_dir) + strlen(kdehome) + strlen(fixpath) + 3;//3 == /, / and \0
++    char *path = (char*) malloc(pathSize);
+     sprintf(path, "%s/%s/%s", userInfo->pw_dir, kdehome, fixpath);
+ 
+     struct stat info;
+@@ -666,21 +679,26 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
+         FILE *fd = fopen(path, "r");
+         if (fd == NULL) {
+             syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
++            free(path);
+             return 1;
+         }
+-        salt = (char*) malloc(sizeof(char) * KWALLET_PAM_SALTSIZE);
++        salt = (char*) malloc(KWALLET_PAM_SALTSIZE);
+         memset(salt, '\0', KWALLET_PAM_SALTSIZE);
+         fread(salt, KWALLET_PAM_SALTSIZE, 1, fd);
+         fclose(fd);
+     }
++    free(path);
++
+     if (salt == NULL) {
+         syslog(LOG_ERR, "%s-kwalletd: Couldn't create or read the salt file", logPrefix);
+         return 1;
+     }
+ 
+     gcry_error_t error;
++
+     error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
+     if (error != 0) {
++        free(salt);
+         syslog(LOG_ERR, "%s-kwalletd: Can't get secure memory: %d", logPrefix, error);
+         return 1;
+     }
+@@ -691,5 +709,7 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
+                             GCRY_KDF_PBKDF2, GCRY_MD_SHA512,
+                             salt, KWALLET_PAM_SALTSIZE,
+                             KWALLET_PAM_ITERATIONS,KWALLET_PAM_KEYSIZE, key);
+-    return 0;
++
++    free(salt);
++    return (int) error; // gcry_kdf_derive returns 0 on success
+ }
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch
new file mode 100644
index 00000000000..8b45b293bbf
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch
@@ -0,0 +1,49 @@
+From 1a01e1eb870e1ab1d96a8641f1f3500af646c974 Mon Sep 17 00:00:00 2001
+From: Fabian Vogt <fabian@ritter-vogt.de>
+Date: Thu, 3 Aug 2017 09:27:10 +0200
+Subject: Avoid dropping privileges by initializing gcrypt secmem
+
+Summary:
+It's a documented side effect that initialization of secure memory in gcrypt
+drops privileges if getuid() != geteuid(). This results in breaking setuid
+callers, like sudo or su.
+
+Test Plan: Can use sudo again when pam_kwallet is involved.
+
+Reviewers: #plasma
+
+Subscribers: plasma-devel
+
+Tags: #plasma
+
+Differential Revision: https://phabricator.kde.org/D7124
+---
+ pam_kwallet.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index 46720a5..20d9603 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -722,12 +722,18 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
+ 
+     gcry_error_t error;
+ 
++    /* We cannot call GCRYCTL_INIT_SECMEM as it drops privileges if getuid() != geteuid().
++     * PAM modules are in many cases executed through setuid binaries, which this call
++     * would break.
++     * It was never effective anyway as neither key nor passphrase are in secure memory,
++     * which is a prerequisite for secure operation...
+     error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
+     if (error != 0) {
+         free(salt);
+         syslog(LOG_ERR, "%s-kwalletd: Can't get secure memory: %d", logPrefix, error);
+         return 1;
+     }
++    */
+ 
+     gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ 
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild b/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild
new file mode 100644
index 00000000000..5798e8eaed5
--- /dev/null
+++ b/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild
@@ -0,0 +1,59 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+inherit kde5
+
+DESCRIPTION="KWallet PAM module to not enter password again"
+LICENSE="LGPL-2.1"
+KEYWORDS="~amd64 ~arm ~x86"
+IUSE=""
+
+DEPEND="
+	dev-libs/libgcrypt:0=
+	virtual/pam
+"
+RDEPEND="${DEPEND}
+	net-misc/socat
+"
+
+PATCHES=(
+	"${FILESDIR}/${P}-cleanups.patch"
+	"${FILESDIR}/${P}-check-graphical.patch"
+	"${FILESDIR}/${P}-privileges.patch"
+)
+
+src_configure() {
+	local mycmakeargs=(
+		-DCMAKE_INSTALL_LIBDIR="/$(get_libdir)"
+		-DKWALLET4=0
+	)
+	kde5_src_configure
+}
+
+pkg_postinst() {
+	check_dm() {
+		if [[ -e "${ROOT}${2}" ]] ; then
+			if grep -Eq "auth\s+optional\s+pam_kwallet5.so" "${ROOT}${2}" && \
+				grep -Eq "session\s+optional\s+pam_kwallet5.so" "${ROOT}${2}" ; then
+				elog "    ${1} - ${2} ...GOOD"
+			else
+				ewarn "    ${1} - ${2} ...BAD"
+			fi
+		fi
+	}
+	elog "This package enables auto-unlocking of kde-frameworks/kwallet:5."
+	elog "List of things to make it work:"
+	elog "1.  Use standard blowfish encryption instead of GPG"
+	elog "2.  Use same password for login and kwallet"
+	elog "3.  A display manager with support for PAM"
+	elog "4.a Have the following lines in the display manager's pam.d file:"
+	elog "    -auth        optional        pam_kwallet5.so"
+	elog "    -session     optional        pam_kwallet5.so auto_start"
+	elog "4.b Checking installed DMs..."
+	has_version "x11-misc/sddm" && check_dm "SDDM" "/etc/pam.d/sddm"
+	has_version "x11-misc/lightdm" && check_dm "LightDM" "/etc/pam.d/lightdm"
+	elog
+	elog "See also: https://wiki.gentoo.org/wiki/KDE#KWallet_auto-unlocking"
+}


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [gentoo-commits] repo/gentoo:master commit in: kde-plasma/kwallet-pam/, kde-plasma/kwallet-pam/files/
@ 2018-05-05 11:28 Andreas Sturmlechner
  0 siblings, 0 replies; 2+ messages in thread
From: Andreas Sturmlechner @ 2018-05-05 11:28 UTC (permalink / raw
  To: gentoo-commits

commit:     f1744b94bb12908e35666a1322d06615b7f7657b
Author:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
AuthorDate: Sat May  5 11:16:14 2018 +0000
Commit:     Andreas Sturmlechner <asturm <AT> gentoo <DOT> org>
CommitDate: Sat May  5 11:16:14 2018 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=f1744b94

kde-plasma/kwallet-pam: Fix CVE-2018-10380

Bug: https://bugs.gentoo.org/654746
Package-Manager: Portage-2.3.32, Repoman-2.3.9

 .../kwallet-pam-5.11.5-CVE-2018-10380-1.patch      | 206 +++++++++++++++++++++
 .../kwallet-pam-5.11.5-CVE-2018-10380-2.patch      | 135 ++++++++++++++
 .../kwallet-pam-5.11.5-CVE-2018-10380-3.patch      |  54 ++++++
 .../kwallet-pam/kwallet-pam-5.11.5-r1.ebuild       |  35 ++++
 .../kwallet-pam/kwallet-pam-5.12.5-r1.ebuild       |  35 ++++
 5 files changed, 465 insertions(+)

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-1.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-1.patch
new file mode 100644
index 00000000000..70ade02a825
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-1.patch
@@ -0,0 +1,206 @@
+From 2134dec85ce19d6378d03cddfae9e5e464cb24c0 Mon Sep 17 00:00:00 2001
+From: Albert Astals Cid <aacid@kde.org>
+Date: Tue, 1 May 2018 12:29:02 +0200
+Subject: Move salt creation to an unprivileged process
+
+Opening files for writing as root is very tricky since through the power
+of symlinks we can get tricked to write in places we don't want to and
+we don't really need to be root to create the salt file
+---
+ pam_kwallet.c | 121 ++++++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 71 insertions(+), 50 deletions(-)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index 20d9603..083c9aa 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -82,7 +82,7 @@ const static char *envVar = "PAM_KWALLET_LOGIN";
+ 
+ static int argumentsParsed = -1;
+ 
+-int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key);
++int kwallet_hash(pam_handle_t *pamh, const char *passphrase, struct passwd *userInfo, char *key);
+ 
+ static void parseArguments(int argc, const char **argv)
+ {
+@@ -325,7 +325,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons
+     }
+ 
+     char *key = malloc(KWALLET_PAM_KEYSIZE);
+-    if (!key || kwallet_hash(password, userInfo, key) != 0) {
++    if (!key || kwallet_hash(pamh, password, userInfo, key) != 0) {
+         free(key);
+         pam_syslog(pamh, LOG_ERR, "%s: Fail into creating the hash", logPrefix);
+         return PAM_IGNORE;
+@@ -352,6 +352,26 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons
+     return PAM_SUCCESS;
+ }
+ 
++static int drop_privileges(struct passwd *userInfo)
++{
++    /* When dropping privileges from root, the `setgroups` call will
++    * remove any extraneous groups. If we don't call this, then
++    * even though our uid has dropped, we may still have groups
++    * that enable us to do super-user things. This will fail if we
++    * aren't root, so don't bother checking the return value, this
++    * is just done as an optimistic privilege dropping function.
++    */
++    setgroups(0, NULL);
++
++    //Change to the user in case we are not it yet
++    if (setgid (userInfo->pw_gid) < 0 || setuid (userInfo->pw_uid) < 0 ||
++        setegid (userInfo->pw_gid) < 0 || seteuid (userInfo->pw_uid) < 0) {
++        return -1;
++    }
++
++    return 0;
++}
++
+ static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toWalletPipe[2], int envSocket)
+ {
+     //In the child pam_syslog does not work, using syslog directly
+@@ -366,18 +386,8 @@ static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toW
+     //This is the side of the pipe PAM will send the hash to
+     close (toWalletPipe[1]);
+ 
+-    /* When dropping privileges from root, the `setgroups` call will
+-    * remove any extraneous groups. If we don't call this, then
+-    * even though our uid has dropped, we may still have groups
+-    * that enable us to do super-user things. This will fail if we
+-    * aren't root, so don't bother checking the return value, this
+-    * is just done as an optimistic privilege dropping function.
+-    */
+-    setgroups(0, NULL);
+-
+     //Change to the user in case we are not it yet
+-    if (setgid (userInfo->pw_gid) < 0 || setuid (userInfo->pw_uid) < 0 ||
+-        setegid (userInfo->pw_gid) < 0 || seteuid (userInfo->pw_uid) < 0) {
++    if (drop_privileges(userInfo) < 0) {
+         syslog(LOG_ERR, "%s: could not set gid/uid/euid/egit for kwalletd", logPrefix);
+         goto cleanup;
+     }
+@@ -619,7 +629,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const c
+     return PAM_SUCCESS;
+ }
+ 
+-int mkpath(char *path, struct passwd *userInfo)
++static int mkpath(char *path)
+ {
+     struct stat sb;
+     char *slash;
+@@ -639,10 +649,6 @@ int mkpath(char *path, struct passwd *userInfo)
+                 errno != EEXIST)) {
+                 syslog(LOG_ERR, "%s: Couldn't create directory: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
+                 return (-1);
+-            } else {
+-                if (chown(path, userInfo->pw_uid, userInfo->pw_gid) == -1) {
+-                    syslog(LOG_INFO, "%s: Couldn't change ownership of: %s", logPrefix, path);
+-                }
+             }
+         } else if (!S_ISDIR(sb.st_mode)) {
+             return (-1);
+@@ -654,34 +660,49 @@ int mkpath(char *path, struct passwd *userInfo)
+     return (0);
+ }
+ 
+-static char* createNewSalt(const char *path, struct passwd *userInfo)
++static void createNewSalt(pam_handle_t *pamh, const char *path, struct passwd *userInfo)
+ {
+-    unlink(path);//in case the file already exists
++    const int pid = fork();
++    if (pid == -1) {
++        pam_syslog(pamh, LOG_ERR, "%s: Couldn't fork to create salt file", logPrefix);
++    } else if (pid == 0) {
++        // Child process
++        if (drop_privileges(userInfo) < 0) {
++            syslog(LOG_ERR, "%s: could not set gid/uid/euid/egit for salt file creation", logPrefix);
++            exit(-1);
++        }
+ 
+-    char *dir = strdup(path);
+-    dir[strlen(dir) - 14] = '\0';//remove kdewallet.salt
+-    mkpath(dir, userInfo);//create the path in case it does not exists
+-    free(dir);
++        unlink(path);//in case the file already exists
+ 
+-    char *salt = gcry_random_bytes(KWALLET_PAM_SALTSIZE, GCRY_STRONG_RANDOM);
+-    FILE *fd = fopen(path, "w");
++        char *dir = strdup(path);
++        dir[strlen(dir) - 14] = '\0';//remove kdewallet.salt
++        mkpath(dir); //create the path in case it does not exists
++        free(dir);
+ 
+-    //If the file can't be created
+-    if (fd == NULL) {
+-        syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
+-        return NULL;
+-    }
++        char *salt = gcry_random_bytes(KWALLET_PAM_SALTSIZE, GCRY_STRONG_RANDOM);
++        FILE *fd = fopen(path, "w");
+ 
+-    fwrite(salt, KWALLET_PAM_SALTSIZE, 1, fd);
+-    fclose(fd);
++        //If the file can't be created
++        if (fd == NULL) {
++            syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
++            exit(-2);
++        }
+ 
+-    if (chown(path, userInfo->pw_uid, userInfo->pw_gid) == -1) {
+-        syslog(LOG_ERR, "%s: Couldn't change ownership of the created salt file", logPrefix);
+-    }
++        fwrite(salt, KWALLET_PAM_SALTSIZE, 1, fd);
++        fclose(fd);
+ 
+-    return salt;
++        exit(0); // success
++    } else {
++        // pam process, just wait for child to finish
++        int status;
++        waitpid(pid, &status, 0);
++        if (status != 0) {
++            pam_syslog(pamh, LOG_ERR, "%s: Couldn't create salt file", logPrefix);
++        }
++    }
+ }
+-int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
++
++int kwallet_hash(pam_handle_t *pamh, const char *passphrase, struct passwd *userInfo, char *key)
+ {
+     if (!gcry_check_version("1.5.0")) {
+         syslog(LOG_ERR, "%s-kwalletd: libcrypt version is too old", logPrefix);
+@@ -700,19 +721,19 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key)
+     struct stat info;
+     char *salt = NULL;
+     if (stat(path, &info) != 0 || info.st_size == 0) {
+-        salt = createNewSalt(path, userInfo);
+-    } else {
+-        FILE *fd = fopen(path, "r");
+-        if (fd == NULL) {
+-            syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
+-            free(path);
+-            return 1;
+-        }
+-        salt = (char*) malloc(KWALLET_PAM_SALTSIZE);
+-        memset(salt, '\0', KWALLET_PAM_SALTSIZE);
+-        fread(salt, KWALLET_PAM_SALTSIZE, 1, fd);
+-        fclose(fd);
++        createNewSalt(pamh, path, userInfo);
+     }
++
++    FILE *fd = fopen(path, "r");
++    if (fd == NULL) {
++        syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno));
++        free(path);
++        return 1;
++    }
++    salt = (char*) malloc(KWALLET_PAM_SALTSIZE);
++    memset(salt, '\0', KWALLET_PAM_SALTSIZE);
++    fread(salt, KWALLET_PAM_SALTSIZE, 1, fd);
++    fclose(fd);
+     free(path);
+ 
+     if (salt == NULL) {
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-2.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-2.patch
new file mode 100644
index 00000000000..2f88e0c3cea
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-2.patch
@@ -0,0 +1,135 @@
+From 01d4143fda5bddb6dca37b23304dc239a5fb38b5 Mon Sep 17 00:00:00 2001
+From: Albert Astals Cid <aacid@kde.org>
+Date: Tue, 1 May 2018 12:32:24 +0200
+Subject: Move socket creation to unprivileged codepath
+
+We don't need to be creating the socket as root, and doing so,
+specially having a chown is problematic security wise.
+---
+ pam_kwallet.c | 77 ++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 36 insertions(+), 41 deletions(-)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index 083c9aa..b9c984a 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -372,13 +372,13 @@ static int drop_privileges(struct passwd *userInfo)
+     return 0;
+ }
+ 
+-static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toWalletPipe[2], int envSocket)
++static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toWalletPipe[2], char *fullSocket)
+ {
+     //In the child pam_syslog does not work, using syslog directly
+     int x = 2;
+     //Close fd that are not of interest of kwallet
+     for (; x < 64; ++x) {
+-        if (x != toWalletPipe[0] && x != envSocket) {
++        if (x != toWalletPipe[0]) {
+             close (x);
+         }
+     }
+@@ -392,6 +392,39 @@ static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toW
+         goto cleanup;
+     }
+ 
++    int envSocket;
++    if ((envSocket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
++        pam_syslog(pamh, LOG_ERR, "%s: couldn't create socket", logPrefix);
++        return;
++    }
++
++    struct sockaddr_un local;
++    local.sun_family = AF_UNIX;
++
++    if (strlen(fullSocket) > sizeof(local.sun_path)) {
++        pam_syslog(pamh, LOG_ERR, "%s: socket path %s too long to open",
++                   logPrefix, fullSocket);
++        free(fullSocket);
++        return;
++    }
++    strcpy(local.sun_path, fullSocket);
++    free(fullSocket);
++    fullSocket = NULL;
++    unlink(local.sun_path);//Just in case it exists from a previous login
++
++    pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, local.sun_path);
++
++    size_t len = strlen(local.sun_path) + sizeof(local.sun_family);
++    if (bind(envSocket, (struct sockaddr *)&local, len) == -1) {
++        pam_syslog(pamh, LOG_INFO, "%s-kwalletd: Couldn't bind to local file\n", logPrefix);
++        return;
++    }
++
++    if (listen(envSocket, 5) == -1) {
++        pam_syslog(pamh, LOG_INFO, "%s-kwalletd: Couldn't listen in socket\n", logPrefix);
++        return;
++    }
++
+     // Fork twice to daemonize kwallet
+     setsid();
+     pid_t pid = fork();
+@@ -452,12 +485,6 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+         pam_syslog(pamh, LOG_ERR, "%s: Couldn't create pipes", logPrefix);
+     }
+ 
+-    int envSocket;
+-    if ((envSocket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+-        pam_syslog(pamh, LOG_ERR, "%s: couldn't create socket", logPrefix);
+-        return;
+-    }
+-
+ #ifdef KWALLET5
+     const char *socketPrefix = "kwallet5";
+ #else
+@@ -493,38 +520,6 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+         return;
+     }
+ 
+-    struct sockaddr_un local;
+-    local.sun_family = AF_UNIX;
+-
+-    if (strlen(fullSocket) > sizeof(local.sun_path)) {
+-        pam_syslog(pamh, LOG_ERR, "%s: socket path %s too long to open",
+-                   logPrefix, fullSocket);
+-        free(fullSocket);
+-        return;
+-    }
+-    strcpy(local.sun_path, fullSocket);
+-    free(fullSocket);
+-    fullSocket = NULL;
+-    unlink(local.sun_path);//Just in case it exists from a previous login
+-
+-    pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, local.sun_path);
+-
+-    size_t len = strlen(local.sun_path) + sizeof(local.sun_family);
+-    if (bind(envSocket, (struct sockaddr *)&local, len) == -1) {
+-        pam_syslog(pamh, LOG_INFO, "%s-kwalletd: Couldn't bind to local file\n", logPrefix);
+-        return;
+-    }
+-
+-    if (listen(envSocket, 5) == -1) {
+-        pam_syslog(pamh, LOG_INFO, "%s-kwalletd: Couldn't listen in socket\n", logPrefix);
+-        return;
+-    }
+-
+-    if (chown(local.sun_path, userInfo->pw_uid, userInfo->pw_gid) == -1) {
+-        pam_syslog(pamh, LOG_INFO, "%s: Couldn't change ownership of the socket", logPrefix);
+-        return;
+-    }
+-
+     pid_t pid;
+     int status;
+     switch (pid = fork ()) {
+@@ -534,7 +529,7 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha
+ 
+     //Child fork, will contain kwalletd
+     case 0:
+-        execute_kwallet(pamh, userInfo, toWalletPipe, envSocket);
++        execute_kwallet(pamh, userInfo, toWalletPipe, fullSocket);
+         /* Should never be reached */
+         break;
+ 
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-3.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-3.patch
new file mode 100644
index 00000000000..de882e45453
--- /dev/null
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.11.5-CVE-2018-10380-3.patch
@@ -0,0 +1,54 @@
+From 8da1a47035fc92bc1496059583772bc4bd6e8ba6 Mon Sep 17 00:00:00 2001
+From: Maximiliano Curia <maxy@gnuservers.com.ar>
+Date: Fri, 4 May 2018 22:06:06 +0200
+Subject: Avoid giving an stderr to kwallet
+
+Summary:
+The fixes for CVE-2018-10380 introduced a regression for most users not
+using kde, and some for kde sessions. In particular the reorder of the
+close calls and creating a new socket caused that the socket is always
+assigned the file descriptor 2, aka stderr.
+
+BUG: 393856
+
+Test Plan: It works
+
+Reviewers: #plasma, aacid
+
+Reviewed By: aacid
+
+Subscribers: asturmlechner, rdieter, davidedmundson, plasma-devel
+
+Tags: #plasma
+
+Differential Revision: https://phabricator.kde.org/D12702
+---
+ pam_kwallet.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/pam_kwallet.c b/pam_kwallet.c
+index b9c984a..661ed8d 100644
+--- a/pam_kwallet.c
++++ b/pam_kwallet.c
+@@ -375,7 +375,8 @@ static int drop_privileges(struct passwd *userInfo)
+ static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toWalletPipe[2], char *fullSocket)
+ {
+     //In the child pam_syslog does not work, using syslog directly
+-    int x = 2;
++    //keep stderr open so socket doesn't returns us that fd
++    int x = 3;
+     //Close fd that are not of interest of kwallet
+     for (; x < 64; ++x) {
+         if (x != toWalletPipe[0]) {
+@@ -424,6 +425,8 @@ static void execute_kwallet(pam_handle_t *pamh, struct passwd *userInfo, int toW
+         pam_syslog(pamh, LOG_INFO, "%s-kwalletd: Couldn't listen in socket\n", logPrefix);
+         return;
+     }
++    //finally close stderr
++    close(2);
+ 
+     // Fork twice to daemonize kwallet
+     setsid();
+-- 
+cgit v0.11.2
+

diff --git a/kde-plasma/kwallet-pam/kwallet-pam-5.11.5-r1.ebuild b/kde-plasma/kwallet-pam/kwallet-pam-5.11.5-r1.ebuild
new file mode 100644
index 00000000000..fdfa93bb219
--- /dev/null
+++ b/kde-plasma/kwallet-pam/kwallet-pam-5.11.5-r1.ebuild
@@ -0,0 +1,35 @@
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+inherit kde5
+
+DESCRIPTION="KWallet PAM module to not enter password again"
+LICENSE="LGPL-2.1"
+KEYWORDS="~amd64 ~arm ~x86"
+IUSE=""
+
+DEPEND="
+	dev-libs/libgcrypt:0=
+	virtual/pam
+"
+RDEPEND="${DEPEND}
+	net-misc/socat
+"
+
+PATCHES=( "${FILESDIR}"/${P}-CVE-2018-10380-{1,2,3}.patch )
+
+src_configure() {
+	local mycmakeargs=(
+		-DCMAKE_INSTALL_LIBDIR="/$(get_libdir)"
+		-DKWALLET4=0
+	)
+	kde5_src_configure
+}
+
+pkg_postinst() {
+	kde5_pkg_postinst
+	elog "This package enables auto-unlocking of kde-frameworks/kwallet:5."
+	elog "See also: https://wiki.gentoo.org/wiki/KDE#KWallet_auto-unlocking"
+}

diff --git a/kde-plasma/kwallet-pam/kwallet-pam-5.12.5-r1.ebuild b/kde-plasma/kwallet-pam/kwallet-pam-5.12.5-r1.ebuild
new file mode 100644
index 00000000000..46782411966
--- /dev/null
+++ b/kde-plasma/kwallet-pam/kwallet-pam-5.12.5-r1.ebuild
@@ -0,0 +1,35 @@
+# Copyright 1999-2018 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=6
+
+inherit kde5
+
+DESCRIPTION="KWallet PAM module to not enter password again"
+LICENSE="LGPL-2.1"
+KEYWORDS="~amd64 ~arm ~x86"
+IUSE=""
+
+DEPEND="
+	dev-libs/libgcrypt:0=
+	virtual/pam
+"
+RDEPEND="${DEPEND}
+	net-misc/socat
+"
+
+PATCHES=( "${FILESDIR}"/${PN}-5.11.5-CVE-2018-10380-{1,2,3}.patch )
+
+src_configure() {
+	local mycmakeargs=(
+		-DCMAKE_INSTALL_LIBDIR="/$(get_libdir)"
+		-DKWALLET4=0
+	)
+	kde5_src_configure
+}
+
+pkg_postinst() {
+	kde5_pkg_postinst
+	elog "This package enables auto-unlocking of kde-frameworks/kwallet:5."
+	elog "See also: https://wiki.gentoo.org/wiki/KDE#KWallet_auto-unlocking"
+}


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-05-05 11:29 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-31 20:54 [gentoo-commits] repo/gentoo:master commit in: kde-plasma/kwallet-pam/, kde-plasma/kwallet-pam/files/ Andreas Sturmlechner
  -- strict thread matches above, loose matches on Subject: below --
2018-05-05 11:28 Andreas Sturmlechner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox