check_fds.c 3.1 KB

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