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