guix-commits
[Top][All Lists]
Advanced

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

01/01: gnu: sudo: Add fix for CVE-2015-5602.


From: Mark H. Weaver
Subject: 01/01: gnu: sudo: Add fix for CVE-2015-5602.
Date: Tue, 12 Jan 2016 16:23:12 +0000

mhw pushed a commit to branch master
in repository guix.

commit 16aa6491177c1f88ccc20597a9b649ce5eebea67
Author: Mark H Weaver <address@hidden>
Date:   Tue Jan 12 11:21:51 2016 -0500

    gnu: sudo: Add fix for CVE-2015-5602.
    
    * gnu/packages/patches/sudo-CVE-2015-5602.patch: New file.
    * gnu-system.am (dist_patch_DATA): Add it.
    * gnu/packages/admin.scm (sudo)[source]: Add patch.
---
 gnu-system.am                                 |    1 +
 gnu/packages/admin.scm                        |    3 +-
 gnu/packages/patches/sudo-CVE-2015-5602.patch |  372 +++++++++++++++++++++++++
 3 files changed, 375 insertions(+), 1 deletions(-)

diff --git a/gnu-system.am b/gnu-system.am
index 7105e13..45487a4 100644
--- a/gnu-system.am
+++ b/gnu-system.am
@@ -663,6 +663,7 @@ dist_patch_DATA =                                           
\
   gnu/packages/patches/slim-config.patch                       \
   gnu/packages/patches/slim-sigusr1.patch                      \
   gnu/packages/patches/soprano-find-clucene.patch              \
+  gnu/packages/patches/sudo-CVE-2015-5602.patch                        \
   gnu/packages/patches/superlu-dist-scotchmetis.patch          \
   gnu/packages/patches/synfig-build-fix.patch                  \
   gnu/packages/patches/tar-d_ino_in_dirent-fix.patch           \
diff --git a/gnu/packages/admin.scm b/gnu/packages/admin.scm
index fbdc26d..4d6bc70 100644
--- a/gnu/packages/admin.scm
+++ b/gnu/packages/admin.scm
@@ -700,7 +700,8 @@ system administrator.")
                                     version ".tar.gz")))
               (sha256
                (base32
-                "0263gi6i19fyzzc488n0qw3m518i39f6a7qmrfvahk9j10bkh5j3"))))
+                "0263gi6i19fyzzc488n0qw3m518i39f6a7qmrfvahk9j10bkh5j3"))
+              (patches (list (search-patch "sudo-CVE-2015-5602.patch")))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags
diff --git a/gnu/packages/patches/sudo-CVE-2015-5602.patch 
b/gnu/packages/patches/sudo-CVE-2015-5602.patch
new file mode 100644
index 0000000..36c90fb
--- /dev/null
+++ b/gnu/packages/patches/sudo-CVE-2015-5602.patch
@@ -0,0 +1,372 @@
+Based on the patch from https://www.sudo.ws/repos/sudo/raw-rev/c2e36a80a279
+Backported to 1.8.15 by Mark H Weaver <address@hidden>
+
+# HG changeset patch
+# User Todd C. Miller <address@hidden>
+# Date 1452475889 25200
+# Node ID c2e36a80a27927c32cba55afae78b8dc830cddc3
+# Parent  94ffd6b18431fa4b9ed0a0c3f0b7b9582a4f6bde
+Rewritten sudoedit_checkdir support that checks all the dirs in the
+path and refuses to follow symlinks in writable directories.
+This is a better fix for CVE-2015-5602.
+Adapted from a diff by Ben Hutchings.  Bug #707
+
+diff -r 94ffd6b18431 -r c2e36a80a279 doc/CONTRIBUTORS
+--- a/doc/CONTRIBUTORS Mon Jan 04 10:47:11 2016 -0700
++++ b/doc/CONTRIBUTORS Sun Jan 10 18:31:29 2016 -0700
+@@ -58,6 +58,7 @@
+     Holloway, Nick
+     Hoover, Adam
+     Hunter, Michael T.
++    Hutchings, Ben
+     Irrgang, Eric
+     Jackson, Brian
+     Jackson, John R.
+diff -r 94ffd6b18431 -r c2e36a80a279 doc/UPGRADE
+--- a/doc/UPGRADE      Mon Jan 04 10:47:11 2016 -0700
++++ b/doc/UPGRADE      Sun Jan 10 18:31:29 2016 -0700
+@@ -1,6 +1,15 @@
+ Notes on upgrading from an older release
+ ========================================
+ 
++o Upgrading from a version prior to the post-1.8.15 fix for CVE-2015-5602.
++
++    The meaning of the sudoedit_checkdir sudoers option has changed.
++    Previously, it would only check the parent directory
++    of the file to be edited.  After the CVE fix, all directories
++    in the path to be edited are checked and sudoedit will refuse
++    to follow a symbolic link in a directory that is writable by
++    the invoking user.
++
+ o Upgrading from a version prior to 1.8.15:
+ 
+     Prior to version 1.8.15, when env_reset was enabled (the default)
+diff -r 94ffd6b18431 -r c2e36a80a279 doc/sudoers.cat
+--- a/doc/sudoers.cat  Mon Jan 04 10:47:11 2016 -0700
++++ b/doc/sudoers.cat  Sun Jan 10 18:31:29 2016 -0700
+@@ -1275,12 +1275,15 @@
+                        system call.  This flag is _o_f_f by default.
+ 
+      sudoedit_checkdir
+-                       If set, ssuuddooeeddiitt will refuse to edit 
files located in a
+-                       directory that is writable by the invoking user unless
+-                       it is run by root.  On many systems, this option
+-                       requires that the parent directory of the file to be
+-                       edited be readable by the target user.  This flag is
+-                       _o_f_f by default.
++                       If set, ssuuddooeeddiitt will check 
directories in the path to
++                       be edited for writability by the invoking user.
++                       Symbolic links will not be followed in writable
++                       directories and ssuuddooeeddiitt will also 
refuse to edit a
++                       file located in a writable directory.  Theses
++                       restrictions are not enforced when 
ssuuddooeeddiitt is invoked
++                       as root.  On many systems, this option requires that
++                       all directories in the path to be edited be readable by
++                       the target user.  This flag is _o_f_f by default.
+ 
+      sudoedit_follow   By default, ssuuddooeeddiitt will not follow 
symbolic links
+                        when opening files.  The 
_s_u_d_o_e_d_i_t___f_o_l_l_o_w option can be
+diff -r 94ffd6b18431 -r c2e36a80a279 doc/sudoers.man.in
+--- a/doc/sudoers.man.in       Mon Jan 04 10:47:11 2016 -0700
++++ b/doc/sudoers.man.in       Sun Jan 10 18:31:29 2016 -0700
+@@ -2715,10 +2715,16 @@
+ .br
+ If set,
+ \fBsudoedit\fR
+-will refuse to edit files located in a directory that is writable
+-by the invoking user unless it is run by root.
+-On many systems, this option requires that the parent directory
+-of the file to be edited be readable by the target user.
++will check directories in the path to be edited for writability
++by the invoking user.
++Symbolic links will not be followed in writable directories and
++\fBsudoedit\fR
++will also refuse to edit a file located in a writable directory.
++Theses restrictions are not enforced when
++\fBsudoedit\fR
++is invoked as root.
++On many systems, this option requires that all directories
++in the path to be edited be readable by the target user.
+ This flag is
+ \fIoff\fR
+ by default.
+diff -r 94ffd6b18431 -r c2e36a80a279 doc/sudoers.mdoc.in
+--- a/doc/sudoers.mdoc.in      Mon Jan 04 10:47:11 2016 -0700
++++ b/doc/sudoers.mdoc.in      Sun Jan 10 18:31:29 2016 -0700
+@@ -2549,10 +2549,16 @@
+ .It sudoedit_checkdir
+ If set,
+ .Nm sudoedit
+-will refuse to edit files located in a directory that is writable
+-by the invoking user unless it is run by root.
+-On many systems, this option requires that the parent directory
+-of the file to be edited be readable by the target user.
++will check directories in the path to be edited for writability
++by the invoking user.
++Symbolic links will not be followed in writable directories and
++.Nm sudoedit
++will also refuse to edit a file located in a writable directory.
++Theses restrictions are not enforced when
++.Nm sudoedit
++is invoked as root.
++On many systems, this option requires that all directories
++in the path to be edited be readable by the target user.
+ This flag is
+ .Em off
+ by default.
+diff -r 94ffd6b18431 -r c2e36a80a279 include/sudo_compat.h
+--- a/include/sudo_compat.h    Mon Jan 04 10:47:11 2016 -0700
++++ b/include/sudo_compat.h    Sun Jan 10 18:31:29 2016 -0700
+@@ -182,6 +182,8 @@
+ # ifndef UTIME_NOW
+ #  define UTIME_NOW   -2L
+ # endif
++#endif
++#if !defined(HAVE_OPENAT) || (!defined(HAVE_FUTIMENS) && 
!defined(HAVE_UTIMENSAT))
+ # ifndef AT_FDCWD
+ #  define AT_FDCWD    -100
+ # endif
+diff -r 94ffd6b18431 -r c2e36a80a279 src/sudo_edit.c
+--- a/src/sudo_edit.c  Mon Jan 04 10:47:11 2016 -0700
++++ b/src/sudo_edit.c  Sun Jan 10 18:31:29 2016 -0700
+@@ -179,13 +179,15 @@
+ }
+ 
+ #ifndef HAVE_OPENAT
+-/* This does not support AT_FDCWD... */
+ static int
+ sudo_openat(int dfd, const char *path, int flags, mode_t mode)
+ {
+     int fd, odfd;
+     debug_decl(sudo_openat, SUDO_DEBUG_EDIT)
+ 
++    if (dfd == AT_FDCWD)
++      debug_return_int(open(path, flags, mode));
++
+     /* Save cwd */
+     if ((odfd = open(".", O_RDONLY)) == -1)
+       debug_return_int(-1);
+@@ -207,6 +209,64 @@
+ #define openat sudo_openat
+ #endif /* HAVE_OPENAT */
+ 
++#ifdef O_NOFOLLOW
++static int
++sudo_edit_openat_nofollow(int dfd, char *path, int oflags, mode_t mode)
++{
++    debug_decl(sudo_edit_open_nofollow, SUDO_DEBUG_EDIT)
++
++    debug_return_int(openat(dfd, path, oflags|O_NOFOLLOW, mode));
++}
++#else
++/*
++ * Returns true if fd and path don't match or path is a symlink.
++ * Used on older systems without O_NOFOLLOW.
++ */
++static bool
++sudo_edit_is_symlink(int fd, char *path)
++{
++    struct stat sb1, sb2;
++    debug_decl(sudo_edit_is_symlink, SUDO_DEBUG_EDIT)
++
++    /*
++     * Treat [fl]stat() failure like there was a symlink.
++     */
++    if (fstat(fd, &sb1) == -1 || lstat(path, &sb2) == -1)
++      debug_return_bool(true);
++
++    /*
++     * Make sure we did not open a link and that what we opened
++     * matches what is currently on the file system.
++     */
++    if (S_ISLNK(sb2.st_mode) ||
++      sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
++      debug_return_bool(true);
++    }
++
++    debug_return_bool(false);
++}
++
++static int
++sudo_edit_openat_nofollow(char *path, int oflags, mode_t mode)
++{
++    struct stat sb1, sb2;
++    int fd;
++    debug_decl(sudo_edit_openat_nofollow, SUDO_DEBUG_EDIT)
++
++    fd = openat(dfd, path, oflags, mode);
++    if (fd == -1)
++      debug_return_int(-1);
++
++    if (sudo_edit_is_symlink(fd, path)) {
++      close(fd);
++      fd = -1;
++      errno = ELOOP;
++    }
++
++    debug_return_int(fd);
++}
++#endif /* O_NOFOLLOW */
++
+ /*
+  * Returns true if the directory described by sb is writable
+  * by the user.  We treat directories with the sticky bit as
+@@ -245,49 +305,94 @@
+     debug_return_bool(false);
+ }
+ 
++/*
++ * Directory open flags for use with openat(2) and fstat(2).
++ * Use O_PATH and O_DIRECTORY where possible.
++ */
++#if defined(O_PATH) && defined(O_DIRECTORY)
++# define DIR_OPEN_FLAGS       (O_PATH|O_DIRECTORY)
++#elif defined(O_PATH) && !defined(O_DIRECTORY)
++# define DIR_OPEN_FLAGS       O_PATH
++#elif !defined(O_PATH) && defined(O_DIRECTORY)
++# define DIR_OPEN_FLAGS       (O_RDONLY|O_DIRECTORY)
++#else
++# define DIR_OPEN_FLAGS       (O_RDONLY|O_NONBLOCK)
++#endif
++
+ static int
+ sudo_edit_open_nonwritable(char *path, int oflags, mode_t mode)
+ {
+-    char *base, *dir;
++    int dfd, fd, dflags = DIR_OPEN_FLAGS;
++#if defined(__linux__) && defined(O_PATH)
++    char *opath = path;
++#endif
++    bool is_writable;
+     struct stat sb;
+-    int dfd, fd;
+     debug_decl(sudo_edit_open_nonwritable, SUDO_DEBUG_EDIT)
+ 
+-    base = strrchr(path, '/');
+-    if (base != NULL) {
+-      *base++ = '\0';
+-      dir = path;
++#if defined(__linux__) && defined(O_PATH)
++restart:
++#endif
++    if (path[0] == '/') {
++      dfd = open("/", dflags);
++      path++;
+     } else {
+-      base = path;
+-      dir = ".";
++      dfd = open(".", dflags);
++      if (path[0] == '.' && path[1] == '/')
++          path += 2;
+     }
+-#ifdef O_PATH
+-    if ((dfd = open(dir, O_PATH)) != -1) {
+-      /* Linux kernels < 3.6 can't do fstat on O_PATH fds. */
+-      if (fstat(dfd, &sb) == -1) {
+-          close(dfd);
+-          dfd = open(dir, O_RDONLY);
+-          if (fstat(dfd, &sb) == -1) {
+-              close(dfd);
+-              dfd = -1;
+-          }
+-      }
+-    }
+-#else
+-    if ((dfd = open(dir, O_RDONLY)) != -1) {
+-      if (fstat(dfd, &sb) == -1) {
+-          close(dfd);
+-          dfd = -1;
+-      }
+-    }
+-#endif
+-    if (base != path)
+-      base[-1] = '/';                 /* restore path */
+     if (dfd == -1)
+       debug_return_int(-1);
+ 
+-    if (dir_is_writable(&sb, user_details.uid, user_details.gid,
+-      user_details.ngroups, user_details.groups)) {
++    for (;;) {
++      char *slash;
++      int subdfd;
++
++      /*
++       * Look up one component at a time, avoiding symbolic links in
++       * writable directories.
++       */
++      if (fstat(dfd, &sb) == -1) {
++          close(dfd);
++#if defined(__linux__) && defined(O_PATH)
++          /* Linux prior to 3.6 can't fstat an O_PATH fd */
++          if (ISSET(dflags, O_PATH)) {
++              CLR(dflags, O_PATH);
++              path = opath;
++              goto restart;
++          }
++#endif
++          debug_return_int(-1);
++      }
++#ifndef O_DIRECTORY
++      if (!S_ISDIR(sb.st_mode)) {
++          close(dfd);
++          errno = ENOTDIR;
++          debug_return_int(-1);
++      }
++#endif
++      is_writable = dir_is_writable(&sb, user_details.uid, user_details.gid,
++          user_details.ngroups, user_details.groups);
++
++      while (path[0] == '/')
++          path++;
++      slash = strchr(path, '/');
++      if (slash == NULL)
++          break;
++      *slash = '\0';
++      if (is_writable)
++          subdfd = sudo_edit_openat_nofollow(dfd, path, dflags, 0);
++      else
++          subdfd = openat(dfd, path, dflags, 0);
++      *slash = '/';                   /* restore path */
++      close(dfd);
++      if (subdfd == -1)
++          debug_return_int(-1);
++      path = slash + 1;
++      dfd = subdfd;
++    }
++
++    if (is_writable) {
+       close(dfd);
+       errno = EISDIR;
+       debug_return_int(-1);
+@@ -332,27 +437,10 @@
+     if (!ISSET(oflags, O_NONBLOCK))
+       (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
+ 
+-    /*
+-     * Treat [fl]stat() failure like an open() failure.
+-     */
+-    if (fstat(fd, &sb1) == -1 || lstat(path, &sb2) == -1) {
+-      const int serrno = errno;
++    if (!ISSET(sflags, CD_SUDOEDIT_FOLLOW) && sudo_edit_is_symlink(fd, path)) 
{
+       close(fd);
+-      errno = serrno;
+-      debug_return_int(-1);
+-    }
+-
+-    /*
+-     * Make sure we did not open a link and that what we opened
+-     * matches what is currently on the file system.
+-     */
+-    if (!ISSET(sflags, CD_SUDOEDIT_FOLLOW)) {
+-      if (S_ISLNK(sb2.st_mode) ||
+-          sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
+-          close(fd);
+-          errno = ELOOP;
+-          debug_return_int(-1);
+-      }
++      fd = -1;
++      errno = ELOOP;
+     }
+ 
+     debug_return_int(fd);
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]