Back to index

glibc  2.9
check_fds.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000, 2002, 2003, 2005 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <paths.h>
00022 #include <unistd.h>
00023 #include <sys/stat.h>
00024 #include <sys/sysmacros.h>
00025 
00026 /* Try to get a machine dependent instruction which will make the
00027    program crash.  This is used in case everything else fails.  */
00028 #include <abort-instr.h>
00029 #ifndef ABORT_INSTRUCTION
00030 /* No such instruction is available.  */
00031 # define ABORT_INSTRUCTION
00032 #endif
00033 
00034 #include <device-nrs.h>
00035 #include <not-cancel.h>
00036 
00037 
00038 /* Should other OSes (e.g., Hurd) have different versions which can
00039    be written in a better way?  */
00040 static void
00041 check_one_fd (int fd, int mode)
00042 {
00043   /* Note that fcntl() with this parameter is not a cancellation point.  */
00044   if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1
00045       && errno == EBADF)
00046     {
00047       const char *name;
00048       dev_t dev;
00049 
00050       /* For writable descriptors we use /dev/full.  */
00051       if ((mode & O_ACCMODE) == O_WRONLY)
00052        {
00053          name = _PATH_DEV "full";
00054          dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR);
00055        }
00056       else
00057        {
00058          name = _PATH_DEVNULL;
00059          dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR);
00060        }
00061 
00062       /* Something is wrong with this descriptor, it's probably not
00063         opened.  Open /dev/null so that the SUID program we are
00064         about to start does not accidently use this descriptor.  */
00065       int nullfd = open_not_cancel (name, mode, 0);
00066 
00067       /* We are very paranoid here.  With all means we try to ensure
00068         that we are actually opening the /dev/null device and nothing
00069         else.
00070 
00071         Note that the following code assumes that STDIN_FILENO,
00072         STDOUT_FILENO, STDERR_FILENO are the three lowest file
00073         decsriptor numbers, in this order.  */
00074       struct stat64 st;
00075       if (__builtin_expect (nullfd != fd, 0)
00076          || __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0
00077          || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0
00078          || st.st_rdev != dev)
00079        /* We cannot even give an error message here since it would
00080           run into the same problems.  */
00081        while (1)
00082          /* Try for ever and ever.  */
00083          ABORT_INSTRUCTION;
00084     }
00085 }
00086 
00087 
00088 void
00089 __libc_check_standard_fds (void)
00090 {
00091   /* This is really paranoid but some people actually are.  If /dev/null
00092      should happen to be a symlink to somewhere else and not the device
00093      commonly known as "/dev/null" we bail out.  We can detect this with
00094      the O_NOFOLLOW flag for open() but only on some system.  */
00095 #ifndef O_NOFOLLOW
00096 # define O_NOFOLLOW  0
00097 #endif
00098   /* Check all three standard file descriptors.  */
00099   check_one_fd (STDIN_FILENO, O_WRONLY | O_NOFOLLOW);
00100   check_one_fd (STDOUT_FILENO, O_RDONLY | O_NOFOLLOW);
00101   check_one_fd (STDERR_FILENO, O_RDONLY | O_NOFOLLOW);
00102 }