Use close_range(2) in closefrom() emulation if available.

On Linux, prefer our own closefrom() emulation since the glibc
version may fail if /proc is not present and close_range() is not
supported.  On FreeBSD, closefrom(3) will either call the closefrom
or close_range system call, depending on which is available.
This commit is contained in:
Todd C. Miller
2022-03-01 09:54:23 -07:00
parent c3177ce831
commit f1a697a8ff
5 changed files with 59 additions and 2 deletions

5
NEWS
View File

@@ -67,6 +67,11 @@ What's new in Sudo 1.9.10
that don't interact with the user via a terminal do not trigger
the lecture.
* Sudo now uses its own closefrom() emulation on Linux systems.
The glibc version may not work in a chroot jail where /proc is
not available. If close_range(2) is present, it will be used
in preference to /proc/self/fd.
What's new in Sudo 1.9.9
* Sudo can now be built with OpenSSL 3.0 without generating warnings

View File

@@ -100,6 +100,9 @@
/* Define to 1 if you have the `closefrom' function. */
#undef HAVE_CLOSEFROM
/* Define to 1 if you have the `close_range' function. */
#undef HAVE_CLOSE_RANGE
/* Define to 1 if you have the `crypt' function. */
#undef HAVE_CRYPT
@@ -548,6 +551,9 @@
/* Define to 1 to enable Linux audit support. */
#undef HAVE_LINUX_AUDIT
/* Define to 1 if you have the <linux/close_range.h> header file. */
#undef HAVE_LINUX_CLOSE_RANGE_H
/* Define to 1 if you have the <linux/random.h> header file. */
#undef HAVE_LINUX_RANDOM_H

29
configure vendored
View File

@@ -17687,6 +17687,10 @@ fi
# The glibc getentropy() emulation may fail on older kernels.
# We use our own getentropy() by default on Linux.
: ${ac_cv_func_getentropy='no'}
# The glibc closefrom() emulation may fail in chroot.
# We use our own closefrom() by default on Linux.
: ${ac_cv_func_closefrom='no'}
;;
*-*-gnu*)
# lockf() is broken on the Hurd
@@ -23081,6 +23085,31 @@ if test "x$ac_cv_have_decl_F_CLOSEM" = xyes
then :
printf "%s\n" "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h
else $as_nop
# Linux has a special header for close_range(2).
for ac_func in close_range
do :
ac_fn_c_check_func "$LINENO" "close_range" "ac_cv_func_close_range"
if test "x$ac_cv_func_close_range" = xyes
then :
printf "%s\n" "#define HAVE_CLOSE_RANGE 1" >>confdefs.h
case "$host_os" in
linux*) ac_fn_c_check_header_compile "$LINENO" "linux/close_range.h" "ac_cv_header_linux_close_range_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_close_range_h" = xyes
then :
printf "%s\n" "#define HAVE_LINUX_CLOSE_RANGE_H 1" >>confdefs.h
fi
;;
esac
fi
done
fi
fi

View File

@@ -2066,6 +2066,10 @@ case "$host" in
# The glibc getentropy() emulation may fail on older kernels.
# We use our own getentropy() by default on Linux.
: ${ac_cv_func_getentropy='no'}
# The glibc closefrom() emulation may fail in chroot.
# We use our own closefrom() by default on Linux.
: ${ac_cv_func_closefrom='no'}
;;
*-*-gnu*)
# lockf() is broken on the Hurd
@@ -2909,7 +2913,14 @@ AC_CHECK_FUNCS([getopt_long], [], [
])
AC_CHECK_FUNCS([closefrom], [], [AC_LIBOBJ(closefrom)
SUDO_APPEND_COMPAT_EXP(sudo_closefrom)
AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [], [
AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [
# Linux has a special header for close_range(2).
AC_CHECK_FUNCS([close_range], [
case "$host_os" in
linux*) AC_CHECK_HEADERS([linux/close_range.h]);;
esac
])
], [
# include <limits.h>
# include <fcntl.h> ])
])

View File

@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2021
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2022
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -39,6 +39,9 @@
#ifdef HAVE_LIBPROC_H
# include <libproc.h>
#endif
#ifdef HAVE_LINUX_CLOSE_RANGE_H
# include <linux/close_range.h>
#endif
#include "sudo_compat.h"
#include "sudo_util.h"
@@ -107,6 +110,9 @@ sudo_closefrom(int lowfd)
#if defined(HAVE_FCNTL_CLOSEM)
if (fcntl(lowfd, F_CLOSEM, 0) != -1)
return;
#elif defined(HAVE_CLOSE_RANGE)
if (close_range(lowfd, ~0U, 0) != -1)
return;
#elif defined(HAVE_PROC_PIDINFO)
len = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
switch (len) {