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