94084c
commit f7a79879c0b2bef0dadd6caaaeeb0d26423e04e5
94084c
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
94084c
Date:   Thu Jan 13 11:28:36 2022 +0530
94084c
94084c
    realpath: Set errno to ENAMETOOLONG for result larger than PATH_MAX [BZ #28770]
94084c
    
94084c
    realpath returns an allocated string when the result exceeds PATH_MAX,
94084c
    which is unexpected when its second argument is not NULL.  This results
94084c
    in the second argument (resolved) being uninitialized and also results
94084c
    in a memory leak since the caller expects resolved to be the same as the
94084c
    returned value.
94084c
    
94084c
    Return NULL and set errno to ENAMETOOLONG if the result exceeds
94084c
    PATH_MAX.  This fixes [BZ #28770], which is CVE-2021-3998.
94084c
    
94084c
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
94084c
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
94084c
    (cherry picked from commit ee8d5e33adb284601c00c94687bc907e10aec9bb)
94084c
94084c
diff --git a/stdlib/Makefile b/stdlib/Makefile
94084c
index 9bb5c221e8be3288..a4ac30d1f6359561 100644
94084c
--- a/stdlib/Makefile
94084c
+++ b/stdlib/Makefile
94084c
@@ -109,6 +109,7 @@ tests := \
94084c
   tst-random \
94084c
   tst-random2 \
94084c
   tst-realpath \
94084c
+  tst-realpath-toolong \
94084c
   tst-secure-getenv \
94084c
   tst-setcontext \
94084c
   tst-setcontext2 \
94084c
diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c
94084c
index 698f9ede25570ef2..7a23a51b3a395eb3 100644
94084c
--- a/stdlib/canonicalize.c
94084c
+++ b/stdlib/canonicalize.c
94084c
@@ -400,8 +400,16 @@ realpath_stk (const char *name, char *resolved,
94084c
 
94084c
 error:
94084c
   *dest++ = '\0';
94084c
-  if (resolved != NULL && dest - rname <= get_path_max ())
94084c
-    rname = strcpy (resolved, rname);
94084c
+  if (resolved != NULL)
94084c
+    {
94084c
+      if (dest - rname <= get_path_max ())
94084c
+	rname = strcpy (resolved, rname);
94084c
+      else
94084c
+	{
94084c
+	  failed = true;
94084c
+	  __set_errno (ENAMETOOLONG);
94084c
+	}
94084c
+    }
94084c
 
94084c
 error_nomem:
94084c
   scratch_buffer_free (&extra_buffer);
94084c
diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c
94084c
new file mode 100644
94084c
index 0000000000000000..8bed772460b37571
94084c
--- /dev/null
94084c
+++ b/stdlib/tst-realpath-toolong.c
94084c
@@ -0,0 +1,49 @@
94084c
+/* Verify that realpath returns NULL with ENAMETOOLONG if the result exceeds
94084c
+   NAME_MAX.
94084c
+   Copyright The GNU Toolchain Authors.
94084c
+   This file is part of the GNU C Library.
94084c
+
94084c
+   The GNU C Library is free software; you can redistribute it and/or
94084c
+   modify it under the terms of the GNU Lesser General Public
94084c
+   License as published by the Free Software Foundation; either
94084c
+   version 2.1 of the License, or (at your option) any later version.
94084c
+
94084c
+   The GNU C Library is distributed in the hope that it will be useful,
94084c
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
94084c
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
94084c
+   Lesser General Public License for more details.
94084c
+
94084c
+   You should have received a copy of the GNU Lesser General Public
94084c
+   License along with the GNU C Library; if not, see
94084c
+   <https://www.gnu.org/licenses/>.  */
94084c
+
94084c
+#include <errno.h>
94084c
+#include <limits.h>
94084c
+#include <stdlib.h>
94084c
+#include <string.h>
94084c
+#include <unistd.h>
94084c
+#include <support/check.h>
94084c
+#include <support/temp_file.h>
94084c
+#include <sys/types.h>
94084c
+#include <sys/stat.h>
94084c
+
94084c
+#define BASENAME "tst-realpath-toolong."
94084c
+
94084c
+int
94084c
+do_test (void)
94084c
+{
94084c
+  char *base = support_create_and_chdir_toolong_temp_directory (BASENAME);
94084c
+
94084c
+  char buf[PATH_MAX + 1];
94084c
+  const char *res = realpath (".", buf);
94084c
+
94084c
+  /* canonicalize.c states that if the real path is >= PATH_MAX, then
94084c
+     realpath returns NULL and sets ENAMETOOLONG.  */
94084c
+  TEST_VERIFY (res == NULL);
94084c
+  TEST_VERIFY (errno == ENAMETOOLONG);
94084c
+
94084c
+  free (base);
94084c
+  return 0;
94084c
+}
94084c
+
94084c
+#include <support/test-driver.c>