glibc/csu/check_fds.c

98 lines
3.2 KiB
C
Raw Normal View History

/* Copyright (C) 2000-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
/* Try to get a machine dependent instruction which will make the
program crash. This is used in case everything else fails. */
#include <abort-instr.h>
#ifndef ABORT_INSTRUCTION
/* No such instruction is available. */
# define ABORT_INSTRUCTION
#endif
#include <device-nrs.h>
#include <not-cancel.h>
/* Should other OSes (e.g., Hurd) have different versions which can
be written in a better way? */
static void
check_one_fd (int fd, int mode)
{
/* Note that fcntl() with this parameter is not a cancellation point. */
if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1
&& errno == EBADF)
{
const char *name;
dev_t dev;
/* For writable descriptors we use /dev/full. */
if ((mode & O_ACCMODE) == O_WRONLY)
{
name = _PATH_DEV "full";
dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR);
}
else
{
name = _PATH_DEVNULL;
dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR);
}
/* Something is wrong with this descriptor, it's probably not
opened. Open /dev/null so that the SUID program we are
2013-08-22 01:48:48 +08:00
about to start does not accidentally use this descriptor. */
Consolidate non cancellable open call This patch consolidates all the non cancellable open calls to use the __open_nocancel identifier. For non cancellable targets it will be just a macro to call the default respective symbol while on Linux will be a internal one. To be consistent with the following non cancellable openat call, a new __open64_nocancel is also added (although not currently used). Checked on x86_64-linux-gnu, x86_64-linux-gnu-x32, and i686-linux-gnu. * sysdeps/generic/not-cancel.h (open_not_cancel): Remove macro. (open_not_cancel_2): Likewise. (open_nocancel): New macro. (open64_nocancel): Likewise. * sysdeps/unix/sysv/linux/not-cancel.h (open_not_cancel): Remove macro. (open_not_cancel_2): Likewise. (__open_nocancel): New prototype. (__open64_nocancel): Likewise. * sysdeps/unix/sysv/linux/Versions (libc) [GLIBC_PRIVATE]: Add __open_nocancel. * sysdeps/unix/sysv/linux/open.c (__open_nocancel): New function. * sysdeps/unix/sysv/linux/open64.c (__open64_nocancel): Likewise. * catgets/open_catalog.c (__open_catalog): Replace open_not_cancel{_2} with __open_nocancel. * csu/check_fds.c (check_one_fd): Likewise. * gmon/gmon.c (write_gmon): Likewise. * iconv/gconv_cache.c (__gconv_load_cached): Likewise. * intl/loadmsgcat.c (open): Likewise. * libio/fileops.c (_IO_file_open): Likewise. * locale/loadarchive.c (_nl_load_locale_from_archive): Likewise. * locale/loadlocale.c (_nl_load_locale): Likewise. * login/utmp_file.c (setutent_file): Likewise. * misc/daemon.c (daemon): Likewise. * nss/nss_db/db-open.c (internal_setent): Likewise. * sysdeps/mach/hurd/opendir.c (__opendirat): Likewise. * sysdeps/posix/libc_fatal.c (__libc_message): Likewise. * sysdeps/posix/opendir.c (tryopen_o_directory): Likewise. (__opendir): Likewise. * sysdeps/posix/spawni.c (__spawni_child): Likewise. * sysdeps/unix/sysv/linux/fips-private.h (fips_enable_p): Likewise. * sysdeps/unix/sysv/linux/gethostid.c (sethostid): Likewise. (gethostid): Likewise. * sysdeps/unix/sysv/linux/getloadavg.c (getloadavg): Likewise. * sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid): Likewise. * sysdeps/unix/sysv/linux/getsysstats.c (__get_nprocs): Likewise. * sysdeps/unix/sysv/linux/grantpt.c (__close_all_fds): Likewise. * sysdeps/unix/sysv/linux/i386/smp.h (is_smp_system): Likewise. * sysdeps/unix/sysv/linux/ia64/has_cpuclock.c (has_cpuclock): Likewise. * sysdeps/unix/sysv/linux/libc_fatal.c (backtrace_and_maps): Likewise. * sysdeps/unix/sysv/linux/malloc-sysdep.h (check_may_shrink_heap): Likewise. * sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c (__get_clockfreq): Likewise. * sysdeps/unix/sysv/linux/pthread_getname.c (pthread_getname_np): Likewise. * sysdeps/unix/sysv/linux/pthread_setname.c (pthread_setname_np): Likewise. * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Likewise. * sysdeps/unix/sysv/linux/sysconf.c (__sysconf): Likewise.
2017-07-03 22:11:24 +08:00
int nullfd = __open_nocancel (name, mode, 0);
/* We are very paranoid here. With all means we try to ensure
that we are actually opening the /dev/null device and nothing
else.
Note that the following code assumes that STDIN_FILENO,
STDOUT_FILENO, STDERR_FILENO are the three lowest file
decsriptor numbers, in this order. */
struct stat64 st;
if (__builtin_expect (nullfd != fd, 0)
|| __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0
|| __builtin_expect (S_ISCHR (st.st_mode), 1) == 0
|| st.st_rdev != dev)
/* We cannot even give an error message here since it would
run into the same problems. */
while (1)
/* Try for ever and ever. */
ABORT_INSTRUCTION;
}
}
void
__libc_check_standard_fds (void)
{
/* Check all three standard file descriptors. The O_NOFOLLOW flag
is really paranoid but some people actually are. If /dev/null
should happen to be a symlink to somewhere else and not the
device commonly known as "/dev/null" we bail out. */
check_one_fd (STDIN_FILENO, O_WRONLY | O_NOFOLLOW);
check_one_fd (STDOUT_FILENO, O_RDONLY | O_NOFOLLOW);
check_one_fd (STDERR_FILENO, O_RDONLY | O_NOFOLLOW);
}