
1: /* Copyright (C) 2000, 2002, 2003, 2005 Free Software Foundation, Inc. 2: This file is part of the GNU C Library. 3: 4: The GNU C Library is free software; you can redistribute it and/or 5: modify it under the terms of the GNU Lesser General Public 6: License as published by the Free Software Foundation; either 7: version 2.1 of the License, or (at your option) any later version. 8: 9: The GNU C Library is distributed in the hope that it will be useful, 10: but WITHOUT ANY WARRANTY; without even the implied warranty of 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12: Lesser General Public License for more details. 13: 14: You should have received a copy of the GNU Lesser General Public 15: License along with the GNU C Library; if not, write to the Free 16: Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 17: 02111-1307 USA. */ 18: 19: #include <errno.h> 20: #include <fcntl.h> 21: #include <paths.h> 22: #include <unistd.h> 23: #include <sys/stat.h> 24: #include <sys/sysmacros.h> 25: 26: /* Try to get a machine dependent instruction which will make the 27: program crash. This is used in case everything else fails. */ 28: #include <abort-instr.h> 29: #ifndef ABORT_INSTRUCTION 30: /* No such instruction is available. */ 31: # define ABORT_INSTRUCTION 32: #endif 33: 34: #include <device-nrs.h> 35: #include <not-cancel.h> 36: 37: 38: /* Should other OSes (e.g., Hurd) have different versions which can 39: be written in a better way? */ 40: static void 41: check_one_fd (int fd, int mode) 42: { 43: /* Note that fcntl() with this parameter is not a cancellation point. */ 44: if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1 45: && errno == EBADF) 46: { 47: const char *name; 48: dev_t dev; 49: 50: /* For writable descriptors we use /dev/full. */ 51: if ((mode & O_ACCMODE) == O_WRONLY) 52: { 53: name = _PATH_DEV "full"; 54: dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR); 55: } 56: else 57: { 58: name = _PATH_DEVNULL; 59: dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR); 60: } 61: 62: /* Something is wrong with this descriptor, it's probably not 63: opened. Open /dev/null so that the SUID program we are 64: about to start does not accidently use this descriptor. */ 65: int nullfd = open_not_cancel (name, mode, 0); 66: 67: /* We are very paranoid here. With all means we try to ensure 68: that we are actually opening the /dev/null device and nothing 69: else. 70: 71: Note that the following code assumes that STDIN_FILENO, 72: STDOUT_FILENO, STDERR_FILENO are the three lowest file 73: decsriptor numbers, in this order. */ 74: struct stat64 st; 75: if (__builtin_expect (nullfd != fd, 0) 76: || __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0 77: || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 78: || st.st_rdev != dev) 79: /* We cannot even give an error message here since it would 80: run into the same problems. */ 81: while (1) 82: /* Try for ever and ever. */ 83: ABORT_INSTRUCTION; 84: } 85: } 86: 87: 88: void 89: __libc_check_standard_fds (void) 90: { 91: /* This is really paranoid but some people actually are. If /dev/null 92: should happen to be a symlink to somewhere else and not the device 93: commonly known as "/dev/null" we bail out. We can detect this with 94: the O_NOFOLLOW flag for open() but only on some system. */ 95: #ifndef O_NOFOLLOW 96: # define O_NOFOLLOW 0 97: #endif 98: /* Check all three standard file descriptors. */ 99: check_one_fd (STDIN_FILENO, O_WRONLY | O_NOFOLLOW); 100: check_one_fd (STDOUT_FILENO, O_RDONLY | O_NOFOLLOW); 101: check_one_fd (STDERR_FILENO, O_RDONLY | O_NOFOLLOW); 102: }