1 /* Copyright (C) 1993-2022 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, see
16    <https://www.gnu.org/licenses/>.
17 
18    As a special exception, if you link the code in this file with
19    files compiled with a GNU compiler to produce an executable,
20    that does not cause the resulting executable to be covered by
21    the GNU Lesser General Public License.  This exception does not
22    however invalidate any other reasons why the executable file
23    might be covered by the GNU Lesser General Public License.
24    This exception applies to code released by its copyright holders
25    in files containing the exception.  */
26 
27 #include "libioP.h"
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <shlib-compat.h>
33 #include <not-cancel.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <spawn.h>
37 #include <paths.h>
38 
39 struct _IO_proc_file
40 {
41   struct _IO_FILE_plus file;
42   /* Following fields must match those in class procbuf (procbuf.h) */
43   pid_t pid;
44   struct _IO_proc_file *next;
45 };
46 typedef struct _IO_proc_file _IO_proc_file;
47 
48 static const struct _IO_jump_t _IO_proc_jumps;
49 
50 static struct _IO_proc_file *proc_file_chain;
51 
52 #ifdef _IO_MTSAFE_IO
53 static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
54 
55 static void
unlock(void * not_used)56 unlock (void *not_used)
57 {
58   _IO_lock_unlock (proc_file_chain_lock);
59 }
60 #endif
61 
62 /* POSIX states popen shall ensure that any streams from previous popen()
63    calls that remain open in the parent process should be closed in the new
64    child process.
65    To avoid a race-condition between checking which file descriptors need to
66    be close (by transversing the proc_file_chain list) and the insertion of a
67    new one after a successful posix_spawn this function should be called
68    with proc_file_chain_lock acquired.  */
69 static bool
spawn_process(posix_spawn_file_actions_t * fa,FILE * fp,const char * command,int do_cloexec,int pipe_fds[2],int parent_end,int child_end,int child_pipe_fd)70 spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
71 	       int do_cloexec, int pipe_fds[2], int parent_end, int child_end,
72 	       int child_pipe_fd)
73 {
74 
75   for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next)
76     {
77       int fd = _IO_fileno ((FILE *) p);
78 
79       /* If any stream from previous popen() calls has fileno
80 	 child_pipe_fd, it has been already closed by the adddup2 action
81 	 above.  */
82       if (fd != child_pipe_fd
83 	  && __posix_spawn_file_actions_addclose (fa, fd) != 0)
84 	return false;
85     }
86 
87   if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0,
88 		     (char *const[]){ (char*) "sh", (char*) "-c",
89 		     (char *) command, NULL }, __environ) != 0)
90     return false;
91 
92   __close_nocancel (pipe_fds[child_end]);
93 
94   if (!do_cloexec)
95     /* Undo the effects of the pipe2 call which set the
96        close-on-exec flag.  */
97     __fcntl (pipe_fds[parent_end], F_SETFD, 0);
98 
99   _IO_fileno (fp) = pipe_fds[parent_end];
100 
101   ((_IO_proc_file *) fp)->next = proc_file_chain;
102   proc_file_chain = (_IO_proc_file *) fp;
103 
104   return true;
105 }
106 
107 FILE *
_IO_new_proc_open(FILE * fp,const char * command,const char * mode)108 _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
109 {
110   int read_or_write;
111   /* These are indexes for pipe_fds.  */
112   int parent_end, child_end;
113   int pipe_fds[2];
114   int child_pipe_fd;
115   bool spawn_ok;
116 
117   int do_read = 0;
118   int do_write = 0;
119   int do_cloexec = 0;
120   while (*mode != '\0')
121     switch (*mode++)
122       {
123       case 'r':
124 	do_read = 1;
125 	break;
126       case 'w':
127 	do_write = 1;
128 	break;
129       case 'e':
130 	do_cloexec = 1;
131 	break;
132       default:
133       errout:
134 	__set_errno (EINVAL);
135 	return NULL;
136       }
137 
138   if ((do_read ^ do_write) == 0)
139     goto errout;
140 
141   if (_IO_file_is_open (fp))
142     return NULL;
143 
144   /* Atomically set the O_CLOEXEC flag for the pipe end used by the
145      child process (to avoid leaking the file descriptor in case of a
146      concurrent fork).  This is later reverted in the child process.
147      When popen returns, the parent pipe end can be O_CLOEXEC or not,
148      depending on the 'e' open mode, but there is only one flag which
149      controls both descriptors.  The parent end is adjusted below,
150      after creating the child process.  (In the child process, the
151      parent end should be closed on execve, so O_CLOEXEC remains set
152      there.)  */
153   if (__pipe2 (pipe_fds, O_CLOEXEC) < 0)
154     return NULL;
155 
156   if (do_read)
157     {
158       parent_end = 0;
159       child_end = 1;
160       read_or_write = _IO_NO_WRITES;
161       child_pipe_fd = 1;
162     }
163   else
164     {
165       parent_end = 1;
166       child_end = 0;
167       read_or_write = _IO_NO_READS;
168       child_pipe_fd = 0;
169     }
170 
171   posix_spawn_file_actions_t fa;
172   /* posix_spawn_file_actions_init does not fail.  */
173   __posix_spawn_file_actions_init (&fa);
174 
175   /* The descriptor is already the one the child will use.  In this case
176      it must be moved to another one otherwise, there is no safe way to
177      remove the close-on-exec flag in the child without creating a FD leak
178      race in the parent.  */
179   if (pipe_fds[child_end] == child_pipe_fd)
180     {
181       int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0);
182       if (tmp < 0)
183 	goto spawn_failure;
184       __close_nocancel (pipe_fds[child_end]);
185       pipe_fds[child_end] = tmp;
186     }
187 
188   if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end],
189       child_pipe_fd) != 0)
190     goto spawn_failure;
191 
192 #ifdef _IO_MTSAFE_IO
193   _IO_cleanup_region_start_noarg (unlock);
194   _IO_lock_lock (proc_file_chain_lock);
195 #endif
196   spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds,
197 			    parent_end, child_end, child_pipe_fd);
198 #ifdef _IO_MTSAFE_IO
199   _IO_lock_unlock (proc_file_chain_lock);
200   _IO_cleanup_region_end (0);
201 #endif
202 
203   __posix_spawn_file_actions_destroy (&fa);
204 
205   if (!spawn_ok)
206     {
207     spawn_failure:
208       __close_nocancel (pipe_fds[child_end]);
209       __close_nocancel (pipe_fds[parent_end]);
210       __set_errno (ENOMEM);
211       return NULL;
212     }
213 
214   _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
215   return fp;
216 }
217 
218 FILE *
_IO_new_popen(const char * command,const char * mode)219 _IO_new_popen (const char *command, const char *mode)
220 {
221   struct locked_FILE
222   {
223     struct _IO_proc_file fpx;
224 #ifdef _IO_MTSAFE_IO
225     _IO_lock_t lock;
226 #endif
227   } *new_f;
228   FILE *fp;
229 
230   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
231   if (new_f == NULL)
232     return NULL;
233 #ifdef _IO_MTSAFE_IO
234   new_f->fpx.file.file._lock = &new_f->lock;
235 #endif
236   fp = &new_f->fpx.file.file;
237   _IO_init_internal (fp, 0);
238   _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
239   _IO_new_file_init_internal (&new_f->fpx.file);
240   if (_IO_new_proc_open (fp, command, mode) != NULL)
241     return (FILE *) &new_f->fpx.file;
242   _IO_un_link (&new_f->fpx.file);
243   free (new_f);
244   return NULL;
245 }
246 
247 int
_IO_new_proc_close(FILE * fp)248 _IO_new_proc_close (FILE *fp)
249 {
250   /* This is not name-space clean. FIXME! */
251   int wstatus;
252   _IO_proc_file **ptr = &proc_file_chain;
253   pid_t wait_pid;
254   int status = -1;
255 
256   /* Unlink from proc_file_chain. */
257 #ifdef _IO_MTSAFE_IO
258   _IO_cleanup_region_start_noarg (unlock);
259   _IO_lock_lock (proc_file_chain_lock);
260 #endif
261   for ( ; *ptr != NULL; ptr = &(*ptr)->next)
262     {
263       if (*ptr == (_IO_proc_file *) fp)
264 	{
265 	  *ptr = (*ptr)->next;
266 	  status = 0;
267 	  break;
268 	}
269     }
270 #ifdef _IO_MTSAFE_IO
271   _IO_lock_unlock (proc_file_chain_lock);
272   _IO_cleanup_region_end (0);
273 #endif
274 
275   if (status < 0 || __close_nocancel (_IO_fileno(fp)) < 0)
276     return -1;
277   /* POSIX.2 Rationale:  "Some historical implementations either block
278      or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
279      for the child process to terminate.  Since this behavior is not
280      described in POSIX.2, such implementations are not conforming." */
281   do
282     {
283       int state;
284       __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
285       wait_pid = __waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
286       __pthread_setcancelstate (state, NULL);
287     }
288   while (wait_pid == -1 && errno == EINTR);
289   if (wait_pid == -1)
290     return -1;
291   return wstatus;
292 }
293 
294 static const struct _IO_jump_t _IO_proc_jumps libio_vtable = {
295   JUMP_INIT_DUMMY,
296   JUMP_INIT(finish, _IO_new_file_finish),
297   JUMP_INIT(overflow, _IO_new_file_overflow),
298   JUMP_INIT(underflow, _IO_new_file_underflow),
299   JUMP_INIT(uflow, _IO_default_uflow),
300   JUMP_INIT(pbackfail, _IO_default_pbackfail),
301   JUMP_INIT(xsputn, _IO_new_file_xsputn),
302   JUMP_INIT(xsgetn, _IO_default_xsgetn),
303   JUMP_INIT(seekoff, _IO_new_file_seekoff),
304   JUMP_INIT(seekpos, _IO_default_seekpos),
305   JUMP_INIT(setbuf, _IO_new_file_setbuf),
306   JUMP_INIT(sync, _IO_new_file_sync),
307   JUMP_INIT(doallocate, _IO_file_doallocate),
308   JUMP_INIT(read, _IO_file_read),
309   JUMP_INIT(write, _IO_new_file_write),
310   JUMP_INIT(seek, _IO_file_seek),
311   JUMP_INIT(close, _IO_new_proc_close),
312   JUMP_INIT(stat, _IO_file_stat),
313   JUMP_INIT(showmanyc, _IO_default_showmanyc),
314   JUMP_INIT(imbue, _IO_default_imbue)
315 };
316 
317 strong_alias (_IO_new_popen, __new_popen)
318 versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
319 versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
320 versioned_symbol (libc, _IO_new_proc_open, _IO_proc_open, GLIBC_2_1);
321 versioned_symbol (libc, _IO_new_proc_close, _IO_proc_close, GLIBC_2_1);
322