[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#932522: buster-pu: package pam-u2f/1.0.7-1



Control: tags -1 - moreinfo

Hi Adam,

Sorry for the slow reply, I got my other -pu uploads through the finish
line and forgot I had another one inflight  >_>'


On Fri, Jul 26, 2019 at 04:13:20PM -0300, Adam D. Barratt wrote:
> On 2019-07-20 11:15, Nicolas Braud-Santoni wrote:
> > Here is an updated debdiff; the only modification is in the changelog,
> > as I forgot to close #930047 there.
> 
> +  * Backport a reliability fix
> +    pam-u2f could previously segfault following a failure to allocate a
> buffer.
> 
> I assume this is backported from the version of the package currently in
> unstable?

Yes, all the fixes are backported from upstream's 1.0.8, which is currently in
sid and bullseye.

The backporting itself was simply cherry-picking the correct commits: upstream's
latest release mostly just included those changes (plus a huge diff due to
regenerating the build system with a more recent version of autotools; obviously
I didn't include that).


> +pam-u2f (1.0.7-1+deb10u1) buster-proposed-updates; urgency=high
> 
> Just "buster", please.

Fixed, thanks for the catch.
May I go ahead and upload?  Updated debdiff attached.


Best,

  nicoo
diff -Nru pam-u2f-1.0.7/debian/changelog pam-u2f-1.0.7/debian/changelog
--- pam-u2f-1.0.7/debian/changelog	2018-05-29 14:33:06.000000000 +0200
+++ pam-u2f-1.0.7/debian/changelog	2019-08-13 01:06:31.000000000 +0200
@@ -1,3 +1,15 @@
+pam-u2f (1.0.7-1+deb10u1) buster; urgency=high
+
+  * Backport multiple security fixes
+     + Fix insecure debug file handling CVE-2019-12209. (Closes: #930021)
+     + Fix debug file descriptor leak CVE-2019-12210. (Closes: #930023)
+     + Fix a non-critical buffer out-of-bounds access. (Closes: #930047)
+
+  * Backport a reliability fix
+    pam-u2f could previously segfault following a failure to allocate a buffer.
+
+ -- Nicolas Braud-Santoni <nicoo@debian.org>  Tue, 13 Aug 2019 01:06:31 +0200
+
 pam-u2f (1.0.7-1) unstable; urgency=high
 
   * New upstream version 1.0.7 (2018-05-15)
diff -Nru pam-u2f-1.0.7/debian/patches/0001-Do-not-leak-file-descriptor-when-doing-exec.patch pam-u2f-1.0.7/debian/patches/0001-Do-not-leak-file-descriptor-when-doing-exec.patch
--- pam-u2f-1.0.7/debian/patches/0001-Do-not-leak-file-descriptor-when-doing-exec.patch	1970-01-01 01:00:00.000000000 +0100
+++ pam-u2f-1.0.7/debian/patches/0001-Do-not-leak-file-descriptor-when-doing-exec.patch	2019-08-13 01:06:31.000000000 +0200
@@ -0,0 +1,164 @@
+Subject: Do not leak file descriptor when doing exec
+
+When opening a custom debug file, the descriptor would stay
+open when calling exec and leak to the child process.
+
+Make sure all files are opened with close-on-exec.
+
+This fixes CVE-2019-12210.
+
+Thanks to Matthias Gerstner of the SUSE Security Team for reporting
+the issue.
+---
+ pam-u2f.c | 35 +++++++++++++++++++++++++----------
+ util.c    | 10 +++++++---
+ util.h    |  3 ++-
+ 3 files changed, 34 insertions(+), 14 deletions(-)
+
+diff --git a/pam-u2f.c b/pam-u2f.c
+index 55d5708..071d005 100644
+Origin: commit:18b1914e32b74ff52000f10e97067e841e5fff62
+Bug: 930023
+From: Gabriel Kihlman <g.kihlman@yubico.com>
+Reviewed-by: Nicolas Braud-Santoni <nicoo@debian.org>
+Last-Update: 2019-07-20
+Applied-Upstream: b0c6b7216f064e051c1dd42629ca062f721eea5f
+
+--- a/pam-u2f.c
++++ b/pam-u2f.c
+@@ -1,5 +1,5 @@
+ /*
+- *  Copyright (C) 2014-2018 Yubico AB - See COPYING
++ *  Copyright (C) 2014-2019 Yubico AB - See COPYING
+  */
+ 
+ /* Define which PAM interfaces we provide */
+@@ -31,7 +31,11 @@ char *secure_getenv(const char *name) {
+ #endif
+ 
+ static void parse_cfg(int flags, int argc, const char **argv, cfg_t *cfg) {
++  struct stat st;
++  FILE *file = NULL;
++  int fd = -1;
+   int i;
++
+   memset(cfg, 0, sizeof(cfg_t));
+   cfg->debug_file = stderr;
+ 
+@@ -76,14 +80,14 @@ static void parse_cfg(int flags, int argc, const char **argv, cfg_t *cfg) {
+         cfg->debug_file = (FILE *)-1;
+       }
+       else {
+-        struct stat st;
+-        FILE *file;
+-        if(lstat(filename, &st) == 0) {
+-          if(S_ISREG(st.st_mode)) {
+-            file = fopen(filename, "a");
+-            if(file != NULL) {
+-              cfg->debug_file = file;
+-            }
++        fd = open(filename, O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY);
++        if (fd >= 0 && (fstat(fd, &st) == 0) && S_ISREG(st.st_mode)) {
++          file = fdopen(fd, "a");
++          if(file != NULL) {
++            cfg->debug_file = file;
++            cfg->is_custom_debug_file = 1;
++            file = NULL;
++            fd = -1;
+           }
+         }
+       }
+@@ -111,6 +115,12 @@ static void parse_cfg(int flags, int argc, const char **argv, cfg_t *cfg) {
+     D(cfg->debug_file, "appid=%s", cfg->appid ? cfg->appid : "(null)");
+     D(cfg->debug_file, "prompt=%s", cfg->prompt ? cfg->prompt : "(null)");
+   }
++
++  if (fd != -1)
++    close(fd);
++
++  if (file != NULL)
++    fclose(file);
+ }
+ 
+ #ifdef DBG
+@@ -317,7 +327,8 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+     DBG("Using file '%s' for emitting touch request notifications", cfg->authpending_file);
+ 
+     // Open (or create) the authpending_file to indicate that we start waiting for a touch
+-    authpending_file_descriptor = open(cfg->authpending_file, O_RDONLY | O_CREAT, 0664);
++    authpending_file_descriptor =
++      open(cfg->authpending_file, O_RDONLY | O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY, 0664);
+     if (authpending_file_descriptor < 0) {
+       DBG("Unable to emit 'authentication started' notification by opening the file '%s', (%s)",
+           cfg->authpending_file, strerror(errno));
+@@ -385,6 +396,10 @@ done:
+   }
+   DBG("done. [%s]", pam_strerror(pamh, retval));
+ 
++  if (cfg->is_custom_debug_file) {
++    fclose(cfg->debug_file);
++  }
++
+   return retval;
+ }
+ 
+diff --git a/util.c b/util.c
+index e7d8ecc..c17a0e6 100644
+--- a/util.c
++++ b/util.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2014-2018 Yubico AB - See COPYING
++ * Copyright (C) 2014-2019 Yubico AB - See COPYING
+  */
+ 
+ #include "util.h"
+@@ -36,7 +36,7 @@ int get_devices_from_authfile(const char *authfile, const char *username,
+   /* Ensure we never return uninitialized count. */
+   *n_devs = 0;
+ 
+-  fd = open(authfile, O_RDONLY, 0);
++  fd = open(authfile, O_RDONLY | O_CLOEXEC | O_NOCTTY);
+   if (fd < 0) {
+     if (verbose)
+       D(debug_file, "Cannot open file: %s (%s)", authfile, strerror(errno));
+@@ -83,6 +83,8 @@ int get_devices_from_authfile(const char *authfile, const char *username,
+     if (verbose)
+       D(debug_file, "fdopen: %s", strerror(errno));
+     goto err;
++  } else {
++    fd = -1; /* fd belongs to opwfile */
+   }
+ 
+   buf = malloc(sizeof(char) * (DEVSIZE * max_devs));
+@@ -211,8 +213,10 @@ out:
+ 
+   if (opwfile)
+     fclose(opwfile);
+-  else if (fd >= 0)
++
++  if (fd != -1)
+     close(fd);
++
+   return retval;
+ }
+ 
+diff --git a/util.h b/util.h
+index 82c3542..d2e7a4d 100644
+--- a/util.h
++++ b/util.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2014-2018 Yubico AB - See COPYING
++ * Copyright (C) 2014-2019 Yubico AB - See COPYING
+  */
+ 
+ #ifndef UTIL_H
+@@ -45,6 +45,7 @@ typedef struct {
+   const char *appid;
+   const char *prompt;
+   FILE *debug_file;
++  int is_custom_debug_file;
+ } cfg_t;
+ 
+ typedef struct {
diff -Nru pam-u2f-1.0.7/debian/patches/0002-Drop-privileges-by-default-when-opening-user-related.patch pam-u2f-1.0.7/debian/patches/0002-Drop-privileges-by-default-when-opening-user-related.patch
--- pam-u2f-1.0.7/debian/patches/0002-Drop-privileges-by-default-when-opening-user-related.patch	1970-01-01 01:00:00.000000000 +0100
+++ pam-u2f-1.0.7/debian/patches/0002-Drop-privileges-by-default-when-opening-user-related.patch	2019-08-13 01:06:31.000000000 +0200
@@ -0,0 +1,407 @@
+Subject: Drop privileges by default when opening user-related files
+
+The module is typically executed as root and would sometimes
+open files or follow symlinks that could be controlled from the
+outside.
+
+Drop privileges to the target user before opening any files.
+
+Fixes CVE-2019-12209.
+
+Thanks to Matthias Gerstner of the SUSE Security Team for reporting
+the issue.
+---
+ Makefile.am  |   1 +
+ README       |  18 +++++++++
+ configure.ac |   4 ++
+ drop_privs.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ drop_privs.h |  64 +++++++++++++++++++++++++++++
+ pam-u2f.c    |  31 +++++++++-----
+ 6 files changed, 238 insertions(+), 9 deletions(-)
+ create mode 100644 drop_privs.c
+ create mode 100644 drop_privs.h
+
+diff --git a/Makefile.am b/Makefile.am
+index c0d2d1e..d761939 100644
+Origin: commit:7db3386fcdb454e33a3ea30dcfb8e8960d4c3aa3
+Bug: 930021
+From: Gabriel Kihlman <g.kihlman@yubico.com>
+Reviewed-by: Nicolas Braud-Santoni <nicoo@debian.org>
+Last-Update: 2019-07-20
+Applied-Upstream: b0c6b7216f064e051c1dd42629ca062f721eea5f
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -13,6 +13,7 @@ lib_LTLIBRARIES = pam_u2f.la
+ 
+ pam_u2f_la_SOURCES = pam-u2f.c
+ pam_u2f_la_SOURCES += util.c util.h
++pam_u2f_la_SOURCES += drop_privs.h drop_privs.c
+ 
+ pam_u2f_la_LIBADD = -lpam
+ pam_u2f_la_LIBADD += $(LIBU2FHOST_LIBS) $(LIBU2FSERVER_LIBS)
+diff --git a/README b/README
+index 1589f7e..ac2cae2 100644
+--- a/README
++++ b/README
+@@ -114,6 +114,8 @@ openasuser::
+ Setuid to the authenticating user when opening the authfile. Useful when the
+ user's home is stored on an NFS volume mounted with the root_squash option
+ (which maps root to nobody which will not be able to read the file).
++Note that after release 1.0.8 this is done by default when no global
++authfile or XDG_CONFIG_HOME environment variable has been set.
+ 
+ alwaysok::
+ Set to enable all authentication attempts to succeed (aka presentation mode).
+@@ -164,6 +166,11 @@ mappings will not be used and the opposite applies if user home directory
+ mappings are being used, the central authorization mappings file will not
+ be used.
+ 
++By default the mapping file inside a home directory will be opened as
++the target user, whereas the central file will be opened as `root`. If
++the `XDG_CONFIG_HOME` variable is set, privileges will not be dropped
++unless the `openasuser` configuration setting is set.
++
+ IMPORTANT: Using pam-u2f to secure the login to a computer while
+ storing the mapping file in an encrypted home directory, will result
+ in the impossibility of logging into the system. The partition is
+@@ -184,6 +191,10 @@ looks like:
+ 
+  auth sufficient pam_u2f.so authfile=/etc/u2f_mappings
+ 
++If you do not set the `openasuser` setting, the authfile will be opened
++and parsed as `root` so make sure it has the correct owner and
++permissions set.
++
+ IMPORTANT: On dynamics networks (e.g. where hostnames are set by DHCP),
+ users should not rely on the default origin and appid ("pam://$HOSTNAME")
+ but set those parameters explicitly to the same value.
+@@ -197,6 +208,13 @@ line:
+ 
+ This is much the same concept as the SSH authorized_keys file.
+ 
++In this case, pam-u2f will drop privileges and read the mapping file
++as that user. This happens regardless of the `openasuser` option being
++set.
++
++Note that if you set the XDG_CONFIG_HOME variable, privileges will not
++be dropped by default. Consider also setting `openasuser` in that case.
++
+ [[registration]]
+ Obtaining key-handles and public keys
+ -------------------------------------
+diff --git a/configure.ac b/configure.ac
+index 63be054..d4b090e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -37,6 +37,8 @@ AC_CHECK_HEADERS([security/pam_modules.h security/_pam_macros.h security/pam_mod
+    #include <security/pam_appl.h>])
+ AC_CHECK_LIB([pam], [pam_start])
+ 
++AC_SEARCH_LIBS([pam_modutil_drop_priv], ["pam"], [AC_DEFINE([HAVE_PAM_MODUTIL_DROP_PRIV], [1])])
++
+ case "$host" in
+      *darwin*)  PAMDIR="/usr/lib/pam";;
+      *linux*)   PAMDIR="/lib/x86_64-linux-gnu/security";;
+@@ -71,6 +73,8 @@ AC_ARG_VAR([CWFLAGS], [Warning flags])
+ AX_CHECK_COMPILE_FLAG([-Wall], [CWFLAGS="-Wall"])
+ AX_CHECK_COMPILE_FLAG([-Wextra], [CWFLAGS="$CWFLAGS -Wextra"])
+ AX_CHECK_COMPILE_FLAG([-Wconversion], [CWFLAGS="$CWFLAGS -Wconversion"])
++# Because pam headers are doing sign-conversion, see PAM_MODUTIL_DEF_PRIVS in pam_modutil.h
++AX_CHECK_COMPILE_FLAG([-Wconversion], [CWFLAGS="$CWFLAGS -Wno-sign-conversion"])
+ AX_CHECK_COMPILE_FLAG([-Wpedantic], [CWFLAGS="$CWFLAGS -Wpedantic"])
+ AX_CHECK_COMPILE_FLAG([-Wformat=2], [CWFLAGS="$CWFLAGS -Wformat=2"])
+ AX_CHECK_COMPILE_FLAG([-Wstrict-prototypes], [CWFLAGS="$CWFLAGS -Wstrict-prototypes"])
+diff --git a/drop_privs.c b/drop_privs.c
+new file mode 100644
+index 0000000..7fe35c5
+--- /dev/null
++++ b/drop_privs.c
+@@ -0,0 +1,129 @@
++/* Written by Ricky Zhou <ricky@fedoraproject.org>
++ * Fredrik Thulin <fredrik@yubico.com> implemented pam_modutil_drop_priv
++ *
++ * Copyright (c) 2011-2014 Yubico AB
++ * Copyright (c) 2011 Ricky Zhou <ricky@fedoraproject.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *
++ *     * Redistributions in binary form must reproduce the above
++ *       copyright notice, this list of conditions and the following
++ *       disclaimer in the documentation and/or other materials provided
++ *       with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef HAVE_PAM_MODUTIL_DROP_PRIV
++
++#include <unistd.h>
++#include <pwd.h>
++#include <grp.h>
++#include <errno.h>
++#include <string.h>
++#include <stdlib.h>
++
++#include "drop_privs.h"
++#include "util.h"
++
++#ifdef HAVE_SECURITY_PAM_APPL_H
++#include <security/pam_appl.h>
++#endif
++#ifdef HAVE_SECURITY_PAM_MODULES_H
++#include <security/pam_modules.h>
++#endif
++
++
++int pam_modutil_drop_priv(pam_handle_t *pamh, struct _ykpam_privs *privs, struct passwd *pw) {
++    privs->saved_euid = geteuid();
++    privs->saved_egid = getegid();
++
++    if ((privs->saved_euid == pw->pw_uid) && (privs->saved_egid == pw->pw_gid)) {
++        D (privs->debug_file, "Privilges already dropped, pretend it is all right");
++        return 0;
++    }
++
++    privs->saved_groups_length = getgroups(0, NULL);
++    if (privs->saved_groups_length < 0) {
++        D (privs->debug_file, "getgroups: %s", strerror(errno));
++        return -1;
++    }
++
++    if (privs->saved_groups_length > SAVED_GROUPS_MAX_LEN) {
++        D (privs->debug_file, "too many groups, limiting.");
++        privs->saved_groups_length = SAVED_GROUPS_MAX_LEN;
++    }
++
++    if (privs->saved_groups_length > 0) {
++        if (getgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
++            D (privs->debug_file, "getgroups: %s", strerror(errno));
++            goto free_out;
++        }
++    }
++
++    if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
++        D (privs->debug_file, "initgroups: %s", strerror(errno));
++        goto free_out;
++    }
++
++    if (setegid(pw->pw_gid) < 0) {
++        D (privs->debug_file, "setegid: %s", strerror(errno));
++        goto free_out;
++    }
++
++    if (seteuid(pw->pw_uid) < 0) {
++        D (privs->debug_file, "seteuid: %s", strerror(errno));
++        goto free_out;
++    }
++
++    return 0;
++free_out:
++    return -1;
++}
++
++int pam_modutil_regain_priv(pam_handle_t *pamh, struct _ykpam_privs *privs) {
++    if ((privs->saved_euid == geteuid()) && (privs->saved_egid == getegid())) {
++        D (privs->debug_file, "Privilges already as requested, pretend it is all right");
++        return 0;
++    }
++
++    if (seteuid(privs->saved_euid) < 0) {
++        D (privs->debug_file, "seteuid: %s", strerror(errno));
++        return -1;
++    }
++
++    if (setegid(privs->saved_egid) < 0) {
++        D (privs->debug_file, "setegid: %s", strerror(errno));
++        return -1;
++    }
++
++    if (setgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
++        D (privs->debug_file, "setgroups: %s", strerror(errno));
++        return -1;
++    }
++
++    return 0;
++}
++
++#else
++
++// drop_privs.c:124: warning: ISO C forbids an empty translation unit [-Wpedantic]
++typedef int make_iso_compilers_happy;
++
++#endif // HAVE_PAM_MODUTIL_DROP_PRIV
+diff --git a/drop_privs.h b/drop_privs.h
+new file mode 100644
+index 0000000..2d25a19
+--- /dev/null
++++ b/drop_privs.h
+@@ -0,0 +1,64 @@
++/* Copyright (c) 2011-2014 Yubico AB
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ *     * Redistributions of source code must retain the above copyright
++ *       notice, this list of conditions and the following disclaimer.
++ *
++ *     * Redistributions in binary form must reproduce the above
++ *       copyright notice, this list of conditions and the following
++ *       disclaimer in the documentation and/or other materials provided
++ *       with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __PAM_U2F_DROP_PRIVS_H_INCLUDED__
++#define __PAM_U2F_DROP_PRIVS_H_INCLUDED__
++
++#ifdef HAVE_PAM_MODUTIL_DROP_PRIV
++#include <security/pam_modutil.h>
++#else
++
++#include <pwd.h>
++#include <stdio.h>
++
++#ifdef HAVE_SECURITY_PAM_APPL_H
++#include <security/pam_appl.h>
++#endif
++#ifdef HAVE_SECURITY_PAM_MODULES_H
++#include <security/pam_modules.h>
++#endif
++
++#define SAVED_GROUPS_MAX_LEN 64 /* as pam_modutil.. */
++
++struct _ykpam_privs {
++  uid_t saved_euid;
++  gid_t saved_egid;
++  gid_t *saved_groups;
++  int saved_groups_length;
++  FILE *debug_file;
++};
++
++#define PAM_MODUTIL_DEF_PRIVS(n) \
++  gid_t n##_saved_groups[SAVED_GROUPS_MAX_LEN]; \
++  struct _ykpam_privs n = {-1, -1, n##_saved_groups, SAVED_GROUPS_MAX_LEN, cfg->debug_file}
++
++int pam_modutil_drop_priv(pam_handle_t *, struct _ykpam_privs *, struct passwd *);
++int pam_modutil_regain_priv(pam_handle_t *, struct _ykpam_privs *);
++
++#endif
++#endif
+diff --git a/pam-u2f.c b/pam-u2f.c
+index 071d005..b01697c 100644
+--- a/pam-u2f.c
++++ b/pam-u2f.c
+@@ -20,6 +20,7 @@
+ #include <errno.h>
+ 
+ #include "util.h"
++#include "drop_privs.h"
+ 
+ /* If secure_getenv is not defined, define it here */
+ #ifndef HAVE_SECURE_GETENV
+@@ -148,11 +149,12 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+   int retval = PAM_IGNORE;
+   device_t *devices = NULL;
+   unsigned n_devices = 0;
+-  int openasuser;
++  int openasuser = 0;
+   int should_free_origin = 0;
+   int should_free_appid = 0;
+   int should_free_auth_file = 0;
+   int should_free_authpending_file = 0;
++  PAM_MODUTIL_DEF_PRIVS(privs);
+ 
+   parse_cfg(flags, argc, argv, cfg);
+ 
+@@ -235,6 +237,9 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+         goto done;
+       }
+ 
++      /* Opening a file in a users $HOME, need to drop privs for security */
++      openasuser = geteuid() == 0 ? 1 : 0;
++
+       snprintf(buf, authfile_dir_len,
+                "%s/.config%s", pw->pw_dir, DEFAULT_AUTHFILE);
+     } else {
+@@ -250,9 +255,14 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ 
+       snprintf(buf, authfile_dir_len,
+                "%s%s", authfile_dir, DEFAULT_AUTHFILE);
++
++      if (!openasuser) {
++	DBG("WARNING: not dropping privileges when reading %s, please "
++	    "consider setting openasuser=1 in the module configuration", buf);
++      }
+     }
+ 
+-    DBG("Using default authentication file %s", buf);
++    DBG("Using authentication file %s", buf);
+ 
+     cfg->auth_file = buf; /* cfg takes ownership */
+     should_free_auth_file = 1;
+@@ -261,25 +271,28 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+     DBG("Using authentication file %s", cfg->auth_file);
+   }
+ 
+-  openasuser = geteuid() == 0 && cfg->openasuser;
++  if (!openasuser) {
++    openasuser = geteuid() == 0 && cfg->openasuser;
++  }
+   if (openasuser) {
+-    if (seteuid(pw_s.pw_uid)) {
+-      DBG("Unable to switch user to uid %i", pw_s.pw_uid);
++    DBG("Dropping privileges");
++    if (pam_modutil_drop_priv(pamh, &privs, pw)) {
++      DBG("Unable to switch user to uid %i", pw->pw_uid);
+       retval = PAM_IGNORE;
+       goto done;
+     }
+-    DBG("Switched to uid %i", pw_s.pw_uid);
++    DBG("Switched to uid %i", pw->pw_uid);
+   }
+   retval = get_devices_from_authfile(cfg->auth_file, user, cfg->max_devs,
+                                      cfg->debug, cfg->debug_file,
+                                      devices, &n_devices);
+   if (openasuser) {
+-    if (seteuid(0)) {
+-      DBG("Unable to switch back to uid 0");
++    if (pam_modutil_regain_priv(pamh, &privs)) {
++      DBG("could not restore privileges");
+       retval = PAM_IGNORE;
+       goto done;
+     }
+-    DBG("Switched back to uid 0");
++    DBG("Restored privileges");
+   }
+ 
+   if (retval != 1) {
diff -Nru pam-u2f-1.0.7/debian/patches/0003-Fix-out-of-bound-accesses.patch pam-u2f-1.0.7/debian/patches/0003-Fix-out-of-bound-accesses.patch
--- pam-u2f-1.0.7/debian/patches/0003-Fix-out-of-bound-accesses.patch	1970-01-01 01:00:00.000000000 +0100
+++ pam-u2f-1.0.7/debian/patches/0003-Fix-out-of-bound-accesses.patch	2019-08-13 01:06:31.000000000 +0200
@@ -0,0 +1,52 @@
+Subject: Fix out-of-bound accesses
+
+---
+ util.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/util.c b/util.c
+index c17a0e6..de48963 100644
+Origin: commit:aab0c31a3bfed8912a271685d6ec909f61380155
+From: Gabriel Kihlman <g.kihlman@yubico.com>
+Reviewed-by: Nicolas Braud-Santoni <nicoo@debian.org>
+Last-Update: 2019-07-20
+Applied-Upstream: b0c6b7216f064e051c1dd42629ca062f721eea5f
+
+--- a/util.c
++++ b/util.c
+@@ -97,8 +97,9 @@ int get_devices_from_authfile(const char *authfile, const char *username,
+   retval = -2;
+   while (fgets(buf, (int)(DEVSIZE * (max_devs - 1)), opwfile)) {
+     char *saveptr = NULL;
+-    if (buf[strlen(buf) - 1] == '\n')
+-      buf[strlen(buf) - 1] = '\0';
++    size_t len = strlen(buf);
++    if (len > 0 && buf[len - 1] == '\n')
++      buf[len - 1] = '\0';
+ 
+     if (verbose)
+       D(debug_file, "Authorization line: %s", buf);
+@@ -121,17 +122,17 @@ int get_devices_from_authfile(const char *authfile, const char *username,
+ 
+       i = 0;
+       while ((s_token = strtok_r(NULL, ",", &saveptr))) {
+-        devices[i].keyHandle = NULL;
+-        devices[i].publicKey = NULL;
+-
+-        if ((*n_devs)++ > MAX_DEVS - 1) {
+-          *n_devs = MAX_DEVS;
++        if ((*n_devs)++ > max_devs - 1) {
++          *n_devs = max_devs;
+           if (verbose)
+             D(debug_file, "Found more than %d devices, ignoring the remaining ones",
+-               MAX_DEVS);
++               max_devs);
+           break;
+         }
+ 
++        devices[i].keyHandle = NULL;
++        devices[i].publicKey = NULL;
++
+         if (verbose)
+           D(debug_file, "KeyHandle for device number %d: %s", i + 1, s_token);
+ 
diff -Nru pam-u2f-1.0.7/debian/patches/0004-Handle-malloc-failing-when-logging.patch pam-u2f-1.0.7/debian/patches/0004-Handle-malloc-failing-when-logging.patch
--- pam-u2f-1.0.7/debian/patches/0004-Handle-malloc-failing-when-logging.patch	1970-01-01 01:00:00.000000000 +0100
+++ pam-u2f-1.0.7/debian/patches/0004-Handle-malloc-failing-when-logging.patch	2019-08-13 01:06:31.000000000 +0200
@@ -0,0 +1,38 @@
+Subject: Handle malloc failing when logging
+
+If the size of string to log was bigger than BUFSIZE we use malloc
+but if malloc fails we should try and handle it gracefully by
+logging that we failed to allocate instead of segfaulting.
+---
+ util.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/util.c b/util.c
+index de48963..6e2b311 100644
+Origin: commit:525aacfb821e86ffef3c960ba13173dab825fd3c
+From: Gabriel Kihlman <g.kihlman@yubico.com>
+Reviewed-by: Nicolas Braud-Santoni <nicoo@debian.org>
+Last-Update: 2019-07-20
+Applied-Upstream: db86a442a624b9e13d9f833c518e92abf354827e
+
+--- a/util.c
++++ b/util.c
+@@ -565,9 +565,15 @@ void _debug(FILE *debug_file, const char *file, int line, const char *func, cons
+     out = malloc(size);
+   }
+ 
+-  size = (unsigned int)sprintf(out, DEBUG_STR, file, line, func);
+-  vsprintf(&out[size], fmt, ap);
+-  va_end(ap);
++  if (out) {
++    size = (unsigned int)sprintf(out, DEBUG_STR, file, line, func);
++    vsprintf(&out[size], fmt, ap);
++    va_end(ap);
++  }
++  else {
++    out = buffer;
++    sprintf(out, "debug(pam_u2f): malloc failed when trying to log\n");
++  }
+ 
+   if (debug_file == (FILE *)-1) {
+     syslog(LOG_AUTHPRIV | LOG_DEBUG, "%s", out);
diff -Nru pam-u2f-1.0.7/debian/patches/series pam-u2f-1.0.7/debian/patches/series
--- pam-u2f-1.0.7/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ pam-u2f-1.0.7/debian/patches/series	2019-08-13 01:06:31.000000000 +0200
@@ -0,0 +1,4 @@
+0001-Do-not-leak-file-descriptor-when-doing-exec.patch
+0002-Drop-privileges-by-default-when-opening-user-related.patch
+0003-Fix-out-of-bound-accesses.patch
+0004-Handle-malloc-failing-when-logging.patch

Attachment: signature.asc
Description: PGP signature


Reply to: