>From 1a41f6578623ba0203514e4a6519d3cf7ad8ec51 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 24 Dec 2020 11:38:48 -0800 Subject: [PATCH 04/10] faccessat: work around F_OK EOVERFLOW bug Also, tune when LSTAT_FOLLOWS_SLASHED_SYMLINK. * doc/posix-functions/faccessat.texi: Mention the problem. * lib/faccessat.c (FACCESSAT_NEVER_EOVERFLOWS) (LSTAT_FOLLOWS_SLASHED_SYMLINK): Default to 0. (rpl_faccessat): If !FACCESSAT_NEVER_EOVERFLOWS, check for F_OK and EOVERFLOW, which means we can return 0. If LSTAT_FOLLOWS_SLASHED_SYMLINK, don't worry about file names ending in slashes, as faccessat should already do the right thing for them. * m4/faccessat.m4 (gl_FUNC_FACCESSAT_EOVERFLOW): New macro. (gl_FUNC_FACCESSAT): Use it. --- ChangeLog | 8 ++++++++ doc/posix-functions/faccessat.texi | 14 ++++++++++--- lib/faccessat.c | 14 ++++++++++++- m4/faccessat.m4 | 33 +++++++++++++++++++++++++++--- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3d2186fb9..551059e35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2020-12-24 Paul Eggert + faccessat: work around F_OK EOVERFLOW bug + * doc/posix-functions/faccessat.texi: Mention the problem. + * lib/faccessat.c (FACCESSAT_NEVER_EOVERFLOWS): Default to 0. + (rpl_faccessat): If !FACCESSAT_NEVER_EOVERFLOWS, check + for F_OK and EOVERFLOW, which means we can return 0. + * m4/faccessat.m4 (gl_FUNC_FACCESSAT_EOVERFLOW): New macro. + (gl_FUNC_FACCESSAT): Use it. + stat failing with EOVERFLOW implies existence * lib/euidaccess.c (euidaccess): * lib/file-has-acl.c (file_has_acl): diff --git a/doc/posix-functions/faccessat.texi b/doc/posix-functions/faccessat.texi index 5d5165e47..07ea8e7bf 100644 --- a/doc/posix-functions/faccessat.texi +++ b/doc/posix-functions/faccessat.texi @@ -15,6 +15,12 @@ glibc 2.3.6, macOS 10.12, FreeBSD 7.4, NetBSD 6.1.5, OpenBSD 4.9, Minix 3.1.8, A On some platforms, @code{faccessat (dfd, "file/", amode, flag)} succeeds instead of failing when @file{file} is not a directory. macOS 10.13. +@item +On some platforms, @code{faccessat} can incorrectly fail with +@code{EOVERFLOW} when the mode is @code{F_OK}: +GNU/Linux with glibc 2.32, or with Linux kernel 5.7. +@c This bug should be fixed in glibc 2.33 and kernel 5.8. See: +@c https://sourceware.org/bugzilla/show_bug.cgi?id=18683 @end itemize Portability problems not fixed by Gnulib: @@ -30,9 +36,11 @@ The replacement does not support the @code{AT_SYMLINK_NOFOLLOW} flag, which is supported by GNU @code{faccessat}. @item On some platforms, @code{faccessat} can mishandle @code{AT_EACCESS} -after a process starts as root and then becomes non-root: -GNU/Linux with glibc 2.32. -@c This bug should be fixed in glibc 2.33. See: +after a process starts as root and then becomes non-root, +or can incorrectly fail with @code{EOVERFLOW} when the mode +is not @code{F_OK}: +GNU/Linux with glibc 2.32, or with Linux kernel 5.7. +@c These bugs should be fixed in glibc 2.33 and kernel 5.8. See: @c https://sourceware.org/bugzilla/show_bug.cgi?id=18683 @end itemize diff --git a/lib/faccessat.c b/lib/faccessat.c index 9f6a11bf6..330c54a0b 100644 --- a/lib/faccessat.c +++ b/lib/faccessat.c @@ -32,6 +32,13 @@ #include #undef _GL_INCLUDING_UNISTD_H +#ifndef FACCESSAT_NEVER_EOVERFLOWS +# define FACCESSAT_NEVER_EOVERFLOWS 0 +#endif +#ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK +# define LSTAT_FOLLOWS_SLASHED_SYMLINK 0 +#endif + #if HAVE_FACCESSAT static int orig_faccessat (int fd, char const *name, int mode, int flag) @@ -59,7 +66,12 @@ rpl_faccessat (int fd, char const *file, int mode, int flag) { int result = orig_faccessat (fd, file, mode, flag); - if (result == 0 && file[strlen (file) - 1] == '/') + if (result != 0) + { + if (!FACCESSAT_NEVER_EOVERFLOWS && mode == F_OK && errno == EOVERFLOW) + return 0; + } + else if (!LSTAT_FOLLOWS_SLASHED_SYMLINK && file[strlen (file) - 1] == '/') { struct stat st; result = fstatat (fd, file, &st, 0); diff --git a/m4/faccessat.m4 b/m4/faccessat.m4 index 7a8b979f8..a4ad31a46 100644 --- a/m4/faccessat.m4 +++ b/m4/faccessat.m4 @@ -1,4 +1,4 @@ -# serial 8 +# serial 9 # See if we need to provide faccessat replacement. dnl Copyright (C) 2009-2020 Free Software Foundation, Inc. @@ -8,6 +8,31 @@ dnl with or without modifications, as long as this notice is preserved. # Written by Eric Blake. +AC_DEFUN([gl_FUNC_FACCESSAT_EOVERFLOW], +[ + AC_CHECK_FUNCS_ONCE([faccessat]) + if test "$ac_cv_func_faccessat" = yes; then + AC_CACHE_CHECK([whether faccessat works when stat would EOVERFLOW], + [gl_cv_func_faccessat_never_eoverflows], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], + [[#ifdef __linux__ + #include + #if (! (KERNEL_VERSION (5, 8, 0) <= LINUX_VERSION_CODE \ + && 2 < (__GLIBC__ + (33 <= __GLIBC_MINOR__)))) + #error "faccessat might fail with EOVERFLOW" + #endif + #endif + ]])], + [gl_cv_func_faccessat_never_eoverflows=yes], + [gl_cv_func_faccessat_never_eoverflows=no])]) + if test "$gl_cv_func_faccessat_never_eoverflows" = yes; then + AC_DEFINE([FACCESSAT_NEVER_EOVERFLOWS], 1, + [Define to 1 if faccessat is EOVERFLOW-free.]) + fi + fi +]) + AC_DEFUN([gl_FUNC_FACCESSAT], [ AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) @@ -16,12 +41,14 @@ AC_DEFUN([gl_FUNC_FACCESSAT], dnl Persuade glibc to declare faccessat(). AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([gl_FUNC_FACCESSAT_EOVERFLOW]) + AC_CHECK_FUNCS_ONCE([faccessat]) if test $ac_cv_func_faccessat = no; then HAVE_FACCESSAT=0 else - case "$gl_cv_func_lstat_dereferences_slashed_symlink" in - *yes) ;; + case $gl_cv_func_lstat_dereferences_slashed_symlink,$gl_cv_func_faccessat_never_eoverflows in + *yes,*yes) ;; *) REPLACE_FACCESSAT=1 ;; esac fi -- 2.27.0