From 1d43c4ae818052a72c616311a99b3d1ca3bf1cfb Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 11 Sep 2009 13:31:06 -0600 Subject: [PATCH] canonicalize-lgpl: reject non-directory with trailing slash This synchronizes glibc to gnulib. For gnulib to glibc, see: http://sources.redhat.com/bugzilla/show_bug.cgi?id=10635 * lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc. * tests/test-canonicalize-lgpl.c (main): Enhance test. This catches failures in glibc 2.3.5. * tests/test-canonicalize.c (main): Likewise. Signed-off-by: Eric Blake --- ChangeLog | 6 +++++ lib/canonicalize-lgpl.c | 47 +++++++++++++++++------------------ tests/test-canonicalize-lgpl.c | 36 +++++++++++++++++++++++++++ tests/test-canonicalize.c | 56 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 681fc4876..2e406a6e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-09-17 Eric Blake + canonicalize-lgpl: reject non-directory with trailing slash + * lib/canonicalize-lgpl.c (__realpath): Synchronize with glibc. + * tests/test-canonicalize-lgpl.c (main): Enhance test. This + catches failures in glibc 2.3.5. + * tests/test-canonicalize.c (main): Likewise. + canonicalize-lgpl: use native realpath if it works * lib/canonicalize-lgpl.c (realpath): Guard with FUNC_REALPATH_WORKS. diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index edf91e25f..63aecb52b 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -1,5 +1,5 @@ /* Return the canonical absolute name of a given file. - Copyright (C) 1996-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 1996-2009 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -15,38 +15,25 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include +#ifndef _LIBC +# include +#endif #if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC -#include - /* Specification. */ #include -#include +#include #include #include - #include - #if HAVE_SYS_PARAM_H || defined _LIBC # include #endif -#ifndef MAXSYMLINKS -# ifdef SYMLOOP_MAX -# define MAXSYMLINKS SYMLOOP_MAX -# else -# define MAXSYMLINKS 20 -# endif -#endif - #include - #include -#ifndef _LIBC -# define __set_errno(e) errno = (e) -#endif +#include #ifdef _LIBC # include @@ -70,6 +57,14 @@ # define __getcwd(buf, max) getwd (buf) # endif # define __readlink readlink +# define __set_errno(e) errno = (e) +# ifndef MAXSYMLINKS +# ifdef SYMLOOP_MAX +# define MAXSYMLINKS SYMLOOP_MAX +# else +# define MAXSYMLINKS 20 +# endif +# endif #endif #if !FUNC_REALPATH_WORKS || defined _LIBC @@ -155,6 +150,7 @@ __realpath (const char *name, char *resolved) #else struct stat st; #endif + int n; /* Skip sequence of multiple path-separators. */ while (*start == '/') @@ -232,7 +228,6 @@ __realpath (const char *name, char *resolved) { char *buf; size_t len; - int n; if (++num_links > MAXSYMLINKS) { @@ -287,6 +282,11 @@ __realpath (const char *name, char *resolved) if (dest > rpath + 1) while ((--dest)[-1] != '/'); } + else if (!S_ISDIR (st.st_mode) && *end != '\0') + { + __set_errno (ENOTDIR); + goto error; + } } } if (dest > rpath + 1 && dest[-1] == '/') @@ -296,16 +296,14 @@ __realpath (const char *name, char *resolved) if (extra_buf) freea (extra_buf); - return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; + return rpath; error: { int saved_errno = errno; if (extra_buf) freea (extra_buf); - if (resolved) - strcpy (resolved, rpath); - else + if (resolved == NULL) free (rpath); errno = saved_errno; } @@ -317,6 +315,7 @@ versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) char * +attribute_compat_text_section __old_realpath (const char *name, char *resolved) { if (resolved == NULL) diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c index 704c0ecc5..f2c4e7a04 100644 --- a/tests/test-canonicalize-lgpl.c +++ b/tests/test-canonicalize-lgpl.c @@ -82,6 +82,24 @@ main () ASSERT (errno == EINVAL); } + /* Check that a non-directory with trailing slash yields NULL. */ + { + char *result; + errno = 0; + result = canonicalize_file_name (BASE "/tra/"); + ASSERT (result == NULL); + ASSERT (errno == ENOTDIR); + } + + /* Check that a missing directory yields NULL. */ + { + char *result; + errno = 0; + result = canonicalize_file_name (BASE "/zzz/.."); + ASSERT (result == NULL); + ASSERT (errno == ENOENT); + } + /* From here on out, tests involve symlinks. */ if (symlink (BASE "/ket", "ise") != 0) { @@ -137,6 +155,24 @@ main () ASSERT (errno == ENOENT); } + /* Check that a non-directory symlink with trailing slash yields NULL. */ + { + char *result; + errno = 0; + result = canonicalize_file_name (BASE "/huk/"); + ASSERT (result == NULL); + ASSERT (errno == ENOTDIR); + } + + /* Check that a missing directory via symlink yields NULL. */ + { + char *result; + errno = 0; + result = canonicalize_file_name (BASE "/ouk/.."); + ASSERT (result == NULL); + ASSERT (errno == ENOENT); + } + /* Check that a loop of symbolic links is detected. */ { char *result; diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c index 66144221d..010ca701d 100644 --- a/tests/test-canonicalize.c +++ b/tests/test-canonicalize.c @@ -90,6 +90,34 @@ main () ASSERT (errno == EINVAL); } + /* Check that a non-directory with trailing slash yields NULL. */ + { + char *result1; + char *result2; + errno = 0; + result1 = canonicalize_file_name (BASE "/tra/"); + ASSERT (result1 == NULL); + ASSERT (errno == ENOTDIR); + errno = 0; + result2 = canonicalize_filename_mode (BASE "/tra/", CAN_EXISTING); + ASSERT (result2 == NULL); + ASSERT (errno == ENOTDIR); + } + + /* Check that a missing directory yields NULL. */ + { + char *result1; + char *result2; + errno = 0; + result1 = canonicalize_file_name (BASE "/zzz/.."); + ASSERT (result1 == NULL); + ASSERT (errno == ENOENT); + errno = 0; + result2 = canonicalize_filename_mode (BASE "/zzz/..", CAN_EXISTING); + ASSERT (result2 == NULL); + ASSERT (errno == ENOENT); + } + /* From here on out, tests involve symlinks. */ if (symlink (BASE "/ket", "ise") != 0) { @@ -163,6 +191,34 @@ main () ASSERT (errno == ENOENT); } + /* Check that a non-directory symlink with trailing slash yields NULL. */ + { + char *result1; + char *result2; + errno = 0; + result1 = canonicalize_file_name (BASE "/huk/"); + ASSERT (result1 == NULL); + ASSERT (errno == ENOTDIR); + errno = 0; + result2 = canonicalize_filename_mode (BASE "/huk/", CAN_EXISTING); + ASSERT (result2 == NULL); + ASSERT (errno == ENOTDIR); + } + + /* Check that a missing directory via symlink yields NULL. */ + { + char *result1; + char *result2; + errno = 0; + result1 = canonicalize_file_name (BASE "/ouk/.."); + ASSERT (result1 == NULL); + ASSERT (errno == ENOENT); + errno = 0; + result2 = canonicalize_filename_mode (BASE "/ouk/..", CAN_EXISTING); + ASSERT (result2 == NULL); + ASSERT (errno == ENOENT); + } + /* Check that a loop of symbolic links is detected. */ { char *result1; -- 2.11.0