diff options
author | Darren Tucker <dtucker@dtucker.net> | 2021-11-10 12:34:25 +1100 |
---|---|---|
committer | Darren Tucker <dtucker@dtucker.net> | 2021-11-10 12:34:25 +1100 |
commit | 10b899a15c88eb40eb5f73cd0fa84ef0966f79c9 (patch) | |
tree | 4f34af056504ed1e101f1fcbdd5eb919ce86b915 | |
parent | eb1f63195a9a38b519536a5b398d9939261ec081 (diff) |
Don't trust closefrom() on Linux.
glibc's closefrom implementation does not work in a chroot when the kernel
does not have close_range. It tries to read from /proc/self/fd and when
that fails dies with an assertion of sorts. Instead, call close_range
ourselves from our compat code and fall back if that fails. bz#3349,
with william.wilson at canonical.com and fweimer at redhat.com.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | openbsd-compat/bsd-closefrom.c | 7 |
2 files changed, 8 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 165b391f..cd4cadec 100644 --- a/configure.ac +++ b/configure.ac @@ -839,6 +839,7 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) dnl Target SUSv3/POSIX.1-2001 plus BSD specifics. dnl _DEFAULT_SOURCE is the new name for _BSD_SOURCE CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE" + AC_DEFINE([BROKEN_CLOSEFROM], [1], [broken in chroots on older kernels]) AC_DEFINE([PAM_TTY_KLUDGE], [1], [Work around problematic Linux PAM modules handling of PAM_TTY]) AC_DEFINE([LOCKED_PASSWD_PREFIX], ["!"], @@ -1820,6 +1821,7 @@ AC_CHECK_FUNCS([ \ cap_rights_limit \ clock \ closefrom \ + close_range \ dirfd \ endgrent \ err \ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c index 8fadca2d..08b7da69 100644 --- a/openbsd-compat/bsd-closefrom.c +++ b/openbsd-compat/bsd-closefrom.c @@ -16,7 +16,7 @@ #include "includes.h" -#ifndef HAVE_CLOSEFROM +#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) #include <sys/types.h> #include <sys/param.h> @@ -130,6 +130,11 @@ closefrom(int lowfd) DIR *dirp; int len; +#ifdef HAVE_CLOSE_RANGE + if (close_range(lowfd, INT_MAX, 0) == 0) + return; +#endif + /* Check for a /proc/$$/fd directory. */ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) { |