fa3bfd
commit 52a713fdd0a30e1bd79818e2e3c4ab44ddca1a94
fa3bfd
Author: Dmitry V. Levin <ldv@altlinux.org>
fa3bfd
Date:   Sun Jan 7 02:03:41 2018 +0000
fa3bfd
fa3bfd
    linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679]
fa3bfd
    
fa3bfd
    Currently getcwd(3) can succeed without returning an absolute path
fa3bfd
    because the underlying getcwd syscall, starting with linux commit
fa3bfd
    v2.6.36-rc1~96^2~2, may succeed without returning an absolute path.
fa3bfd
    
fa3bfd
    This is a conformance issue because "The getcwd() function shall
fa3bfd
    place an absolute pathname of the current working directory
fa3bfd
    in the array pointed to by buf, and return buf".
fa3bfd
    
fa3bfd
    This is also a security issue because a non-absolute path returned
fa3bfd
    by getcwd(3) causes a buffer underflow in realpath(3).
fa3bfd
    
fa3bfd
    Fix this by checking the path returned by getcwd syscall and falling
fa3bfd
    back to generic_getcwd if the path is not absolute, effectively making
fa3bfd
    getcwd(3) fail with ENOENT.  The error code is chosen for consistency
fa3bfd
    with the case when the current directory is unlinked.
fa3bfd
    
fa3bfd
    [BZ #22679]
fa3bfd
    CVE-2018-1000001
fa3bfd
    * sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Fall back to
fa3bfd
    generic_getcwd if the path returned by getcwd syscall is not absolute.
fa3bfd
    * io/tst-getcwd-abspath.c: New test.
fa3bfd
    * io/Makefile (tests): Add tst-getcwd-abspath.
fa3bfd
fa3bfd
Index: glibc-2.17-c758a686/io/Makefile
fa3bfd
===================================================================
fa3bfd
--- glibc-2.17-c758a686.orig/io/Makefile
fa3bfd
+++ glibc-2.17-c758a686/io/Makefile
fa3bfd
@@ -70,7 +70,8 @@ tests		:= test-utime test-stat test-stat
fa3bfd
 		   tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
fa3bfd
 		   tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
fa3bfd
 		   tst-posix_fallocate \
fa3bfd
-		   tst-open-tmpfile
fa3bfd
+		   tst-open-tmpfile \
fa3bfd
+		   tst-getcwd-abspath
fa3bfd
 
fa3bfd
 include ../Rules
fa3bfd
 
fa3bfd
Index: glibc-2.17-c758a686/io/tst-getcwd-abspath.c
fa3bfd
===================================================================
fa3bfd
--- /dev/null
fa3bfd
+++ glibc-2.17-c758a686/io/tst-getcwd-abspath.c
fa3bfd
@@ -0,0 +1,66 @@
fa3bfd
+/* BZ #22679 getcwd(3) should not succeed without returning an absolute path.
fa3bfd
+
fa3bfd
+   Copyright (C) 2018 Free Software Foundation, Inc.
fa3bfd
+   This file is part of the GNU C Library.
fa3bfd
+
fa3bfd
+   The GNU C Library is free software; you can redistribute it and/or
fa3bfd
+   modify it under the terms of the GNU Lesser General Public
fa3bfd
+   License as published by the Free Software Foundation; either
fa3bfd
+   version 2.1 of the License, or (at your option) any later version.
fa3bfd
+
fa3bfd
+   The GNU C Library is distributed in the hope that it will be useful,
fa3bfd
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
fa3bfd
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
fa3bfd
+   Lesser General Public License for more details.
fa3bfd
+
fa3bfd
+   You should have received a copy of the GNU Lesser General Public
fa3bfd
+   License along with the GNU C Library; if not, see
fa3bfd
+   <https://www.gnu.org/licenses/>.  */
fa3bfd
+
fa3bfd
+#include <errno.h>
fa3bfd
+#include <stdio.h>
fa3bfd
+#include <stdlib.h>
fa3bfd
+#include <support/check.h>
fa3bfd
+#include <support/namespace.h>
fa3bfd
+#include <support/support.h>
fa3bfd
+#include <support/temp_file.h>
fa3bfd
+#include <support/test-driver.h>
fa3bfd
+#include <support/xunistd.h>
fa3bfd
+#include <unistd.h>
fa3bfd
+
fa3bfd
+static char *chroot_dir;
fa3bfd
+
fa3bfd
+/* The actual test.  Run it in a subprocess, so that the test harness
fa3bfd
+   can remove the temporary directory in --direct mode.  */
fa3bfd
+static void
fa3bfd
+getcwd_callback (void *closure)
fa3bfd
+{
fa3bfd
+  xchroot (chroot_dir);
fa3bfd
+
fa3bfd
+  errno = 0;
fa3bfd
+  char *cwd = getcwd (NULL, 0);
fa3bfd
+  TEST_COMPARE (errno, ENOENT);
fa3bfd
+  TEST_VERIFY (cwd == NULL);
fa3bfd
+
fa3bfd
+  errno = 0;
fa3bfd
+  cwd = realpath (".", NULL);
fa3bfd
+  TEST_COMPARE (errno, ENOENT);
fa3bfd
+  TEST_VERIFY (cwd == NULL);
fa3bfd
+
fa3bfd
+  _exit (0);
fa3bfd
+}
fa3bfd
+
fa3bfd
+static int
fa3bfd
+do_test (void)
fa3bfd
+{
fa3bfd
+  support_become_root ();
fa3bfd
+  if (!support_can_chroot ())
fa3bfd
+    return EXIT_UNSUPPORTED;
fa3bfd
+
fa3bfd
+  chroot_dir = support_create_temp_directory ("tst-getcwd-abspath-");
fa3bfd
+  support_isolate_in_subprocess (getcwd_callback, NULL);
fa3bfd
+
fa3bfd
+  return 0;
fa3bfd
+}
fa3bfd
+
fa3bfd
+#include <support/test-driver.c>
fa3bfd
Index: glibc-2.17-c758a686/sysdeps/unix/sysv/linux/getcwd.c
fa3bfd
===================================================================
fa3bfd
--- glibc-2.17-c758a686.orig/sysdeps/unix/sysv/linux/getcwd.c
fa3bfd
+++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/getcwd.c
fa3bfd
@@ -79,7 +79,7 @@ __getcwd (char *buf, size_t size)
fa3bfd
   int retval;
fa3bfd
 
fa3bfd
   retval = INLINE_SYSCALL (getcwd, 2, CHECK_STRING (path), alloc_size);
fa3bfd
-  if (retval >= 0)
fa3bfd
+  if (retval >= 0 && path[0] == '/')
fa3bfd
     {
fa3bfd
 #ifndef NO_ALLOCATION
fa3bfd
       if (buf == NULL && size == 0)
fa3bfd
@@ -95,10 +95,10 @@ __getcwd (char *buf, size_t size)
fa3bfd
       return buf;
fa3bfd
     }
fa3bfd
 
fa3bfd
-  /* The system call cannot handle paths longer than a page.
fa3bfd
-     Neither can the magic symlink in /proc/self.  Just use the
fa3bfd
+  /* The system call either cannot handle paths longer than a page
fa3bfd
+     or can succeed without returning an absolute path.  Just use the
fa3bfd
      generic implementation right away.  */
fa3bfd
-  if (errno == ENAMETOOLONG)
fa3bfd
+  if (retval >= 0 || errno == ENAMETOOLONG)
fa3bfd
     {
fa3bfd
 #ifndef NO_ALLOCATION
fa3bfd
       if (buf == NULL && size == 0)