1 /*
2 * fdclosed.cc: Part of GNU CSSC.
3 *
4 * Copyright (C) 1998, 2000, 2007, 2008, 2009, 2010, 2011, 2014, 2019
5 * Free Software Foundation, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 /* This class exists to ensure that the standard file descriptors are
23 * not closed. That would mean that we could open an ordinary file
24 * and then corrupt it since we don't realise that output to stdout or
25 * stderr will go to it.
26 *
27 *
28 * If any of the file descriptors 0, 1, 2 are not open, attach them
29 * to /dev/null so that we don't fopen() a file, get a low numbered
30 * file descriptor, and accidentally corrupt our file with a printf()
31 * to stdout or stderr, or trying to read from stdin (hence changing
32 * the file pointer on our file too).
33 */
34
35 #include <config.h>
36
37 #include <unistd.h>
38 #include <stdio.h> /* perror() */
39
40 #include "cssc.h"
41 #include "sysdep.h"
42 #include "defaults.h" // CONFIG_NULL_FILENAME
43
44 class SafeFdCheck
45 {
46 public:
47 SafeFdCheck();
48 };
49
50
51 /* We want to emit an error message. If stderr has been closed, this
52 * is difficult. We just send the output to the closed file
53 * descriptor (using perror()).
54 *
55 * We do this becauase (1) there isn't really a better option, and
56 * (2) because the output will still show up in the strace(8) output
57 * if the user really needs to track down the problem.
58 *
59 * If you have an idea for a better way of implementing it, please
60 * feel free to do so; but remember, it needs to work when we just
61 * failed to open() /dev/null. So opening another file (e.g. /dev/log
62 * with syslog) isn't going to work.
63 */
64
SafeFdCheck()65 SafeFdCheck::SafeFdCheck()
66 {
67 int i, fd;
68
69 for (i=0; i<3; ++i)
70 {
71 fd = open(CONFIG_NULL_FILENAME, O_RDONLY, 0);
72 if (fd < 0)
73 {
74 perror(CONFIG_NULL_FILENAME);
75 _exit(1);
76 }
77 else if (fd > 2)
78 {
79 close(fd);
80 return;
81 }
82 }
83 }
84
85
86 /* Instantiate the class so that the constructor is called to do the check.
87 */
88 static SafeFdCheck PleaseDoIt;
89
90 /* Local variables: */
91 /* mode: c++ */
92 /* End: */
93