aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-04-07 16:07:26 +0100
committerRon Yorston <rmy@pobox.com>2018-04-07 16:07:26 +0100
commit5b725727b90f1e5b4dbf1c304cfe3fa534767f15 (patch)
tree20634e3b4e970fe9a43c1f809fa05ce62fb02130
parenteda6f28c793db7d5a61ec4d8d801dfcb6def17b7 (diff)
downloadbusybox-w32-5b725727b90f1e5b4dbf1c304cfe3fa534767f15.tar.gz
busybox-w32-5b725727b90f1e5b4dbf1c304cfe3fa534767f15.tar.bz2
busybox-w32-5b725727b90f1e5b4dbf1c304cfe3fa534767f15.zip
win32: don't leak pipe data structures
popen uses an array of pipe_data structures to record information that's later used by pclose. pclose releases the structure after use. The lower-level pipe function mingw_popen_fd was also using this array of structures but didn't provide any way to release them. Avoid this leak by letting mingw_popen_fd use a local structure instead.
-rw-r--r--win32/popen.c124
1 files changed, 66 insertions, 58 deletions
diff --git a/win32/popen.c b/win32/popen.c
index 6fc04e169..0da5cde23 100644
--- a/win32/popen.c
+++ b/win32/popen.c
@@ -5,16 +5,17 @@
5typedef struct { 5typedef struct {
6 PROCESS_INFORMATION piProcInfo; 6 PROCESS_INFORMATION piProcInfo;
7 HANDLE pipe[2]; 7 HANDLE pipe[2];
8 char mode;
9 int fd; 8 int fd;
10} pipe_data; 9} pipe_data;
11 10
12static pipe_data *pipes = NULL; 11static pipe_data *pipes = NULL;
13static int num_pipes = 0; 12static int num_pipes = 0;
14 13
14static int mingw_popen_internal(pipe_data *p, const char *cmd,
15 const char *mode, int fd0, pid_t *pid);
16
15static int mingw_pipe(pipe_data *p, int bidi) 17static int mingw_pipe(pipe_data *p, int bidi)
16{ 18{
17 int ret = 0;
18 SECURITY_ATTRIBUTES sa; 19 SECURITY_ATTRIBUTES sa;
19 20
20 sa.nLength = sizeof(sa); /* Length in bytes */ 21 sa.nLength = sizeof(sa); /* Length in bytes */
@@ -31,9 +32,9 @@ static int mingw_pipe(pipe_data *p, int bidi)
31 char *name; 32 char *name;
32 const int ip = 1; /* index of parent end of pipe */ 33 const int ip = 1; /* index of parent end of pipe */
33 const int ic = 0; /* index of child end of pipe */ 34 const int ic = 0; /* index of child end of pipe */
35 static int count = 0;
34 36
35 name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), 37 name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), ++count);
36 (int)(p-pipes));
37 38
38 p->pipe[ip] = CreateNamedPipe(name, 39 p->pipe[ip] = CreateNamedPipe(name,
39 PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, 40 PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
@@ -44,30 +45,53 @@ static int mingw_pipe(pipe_data *p, int bidi)
44 OPEN_EXISTING, 45 OPEN_EXISTING,
45 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 46 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
46 NULL); 47 NULL);
47 if (p->pipe[ip] == INVALID_HANDLE_VALUE ||
48 p->pipe[ic] == INVALID_HANDLE_VALUE) {
49 ret = -1;
50 }
51
52 free(name); 48 free(name);
53 } 49 }
54 50
55 return ret; 51 return (p->pipe[0] == INVALID_HANDLE_VALUE ||
52 p->pipe[1] == INVALID_HANDLE_VALUE) ? -1 : 0;
53}
54
55static void clear_pipe_data(pipe_data *p)
56{
57 memset(p, 0, sizeof(pipe_data));
58 p->pipe[0] = INVALID_HANDLE_VALUE;
59 p->pipe[1] = INVALID_HANDLE_VALUE;
60 p->fd = -1;
61}
62
63static void close_pipe_data(pipe_data *p)
64{
65 if (p->pipe[0] != INVALID_HANDLE_VALUE)
66 CloseHandle(p->pipe[0]);
67 if (p->pipe[1] != INVALID_HANDLE_VALUE)
68 CloseHandle(p->pipe[1]);
69 clear_pipe_data(p);
56} 70}
57 71
58static pipe_data *find_pipe(void) 72/*
73 * Search for a pipe_data structure with file descriptor fd. If fd is
74 * -1 and no empty slots are available the array is extended. Return
75 * NULL if the file descriptor can't be found or the array can't be
76 * extended.
77 */
78static pipe_data *find_pipe(int fd)
59{ 79{
60 int i; 80 int i;
61 pipe_data *p = NULL; 81 pipe_data *p = NULL;
62 82
63 /* find an unused pipe structure */ 83 /* find a matching pipe structure */
64 for ( i=0; i<num_pipes; ++i ) { 84 for ( i=0; i<num_pipes; ++i ) {
65 if ( pipes[i].mode == '\0' ) { 85 if (pipes[i].fd == fd) {
66 p = pipes+i; 86 p = pipes+i;
67 break; 87 break;
68 } 88 }
69 } 89 }
70 90
91 /* if looking for valid file descriptor return now */
92 if (fd != -1)
93 return p;
94
71 if ( p == NULL ) { 95 if ( p == NULL ) {
72 /* need to extend array */ 96 /* need to extend array */
73 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) { 97 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) {
@@ -75,22 +99,20 @@ static pipe_data *find_pipe(void)
75 } 99 }
76 100
77 pipes = p; 101 pipes = p;
102 p = pipes + num_pipes;
78 for ( i=0; i<10; ++i ) { 103 for ( i=0; i<10; ++i ) {
79 memset(pipes+num_pipes+i, 0, sizeof(pipe_data)); 104 clear_pipe_data(p+i);
80 } 105 }
81 p = pipes + num_pipes;
82 num_pipes += 10; 106 num_pipes += 10;
83 } 107 }
84 108 clear_pipe_data(p);
85 p->pipe[0] = INVALID_HANDLE_VALUE;
86 p->pipe[1] = INVALID_HANDLE_VALUE;
87 p->fd = -1;
88 109
89 return p; 110 return p;
90} 111}
91 112
92FILE *mingw_popen(const char *cmd, const char *mode) 113FILE *mingw_popen(const char *cmd, const char *mode)
93{ 114{
115 pipe_data *p;
94 FILE *fptr = NULL; 116 FILE *fptr = NULL;
95 int fd; 117 int fd;
96 int len, count; 118 int len, count;
@@ -103,6 +125,11 @@ FILE *mingw_popen(const char *cmd, const char *mode)
103 return NULL; 125 return NULL;
104 } 126 }
105 127
128 /* find an unused pipe structure */
129 if ((p=find_pipe(-1)) == NULL) {
130 return NULL;
131 }
132
106 /* count double quotes */ 133 /* count double quotes */
107 count = 0; 134 count = 0;
108 for ( s=cmd; *s; ++s ) { 135 for ( s=cmd; *s; ++s ) {
@@ -115,16 +142,15 @@ FILE *mingw_popen(const char *cmd, const char *mode)
115 if ( (cmd_buff=malloc(len)) == NULL ) { 142 if ( (cmd_buff=malloc(len)) == NULL ) {
116 return NULL; 143 return NULL;
117 } 144 }
145 cmd_buff[0] = '\0';
118 146
119#if (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) && \ 147#if (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) && \
120 NUM_APPLETS > 1 148 NUM_APPLETS > 1
121 if (find_applet_by_name("sh") >= 0) { 149 if (find_applet_by_name("sh") >= 0) {
122 strcpy(cmd_buff, bb_busybox_exec_path); 150 sprintf(cmd_buff, "%s --busybox ", bb_busybox_exec_path);
123 strcat(cmd_buff, " --busybox sh -c \"");
124 } 151 }
125 else
126#endif 152#endif
127 strcpy(cmd_buff, "sh -c \""); 153 strcat(cmd_buff, "sh -c \"");
128 154
129 /* escape double quotes */ 155 /* escape double quotes */
130 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) { 156 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
@@ -137,7 +163,7 @@ FILE *mingw_popen(const char *cmd, const char *mode)
137 *t = '\0'; 163 *t = '\0';
138 164
139 /* Create the pipe */ 165 /* Create the pipe */
140 if ((fd=mingw_popen_fd(cmd_buff, mode, -1, NULL)) != -1) { 166 if ((fd=mingw_popen_internal(p, cmd_buff, mode, -1, NULL)) != -1) {
141 fptr = _fdopen(fd, *mode == 'r' ? "rb" : "wb"); 167 fptr = _fdopen(fd, *mode == 'r' ? "rb" : "wb");
142 } 168 }
143 169
@@ -157,9 +183,10 @@ FILE *mingw_popen(const char *cmd, const char *mode)
157 * - the pid of the command is returned in the variable pid, which 183 * - the pid of the command is returned in the variable pid, which
158 * can be NULL if the pid is not required. 184 * can be NULL if the pid is not required.
159 */ 185 */
160int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid) 186static int mingw_popen_internal(pipe_data *p, const char *cmd,
187 const char *mode, int fd0, pid_t *pid)
161{ 188{
162 pipe_data *p; 189 pipe_data pd;
163 STARTUPINFO siStartInfo; 190 STARTUPINFO siStartInfo;
164 int success; 191 int success;
165 int fd = -1; 192 int fd = -1;
@@ -187,9 +214,9 @@ int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid)
187 } 214 }
188 ic = !ip; 215 ic = !ip;
189 216
190 /* find an unused pipe structure */ 217 if (!p) {
191 if ( (p=find_pipe()) == NULL ) { 218 /* no struct provided, use a local one */
192 return -1; 219 p = &pd;
193 } 220 }
194 221
195 /* Create the pipe */ 222 /* Create the pipe */
@@ -242,15 +269,9 @@ int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid)
242 269
243finito: 270finito:
244 if ( fd == -1 ) { 271 if ( fd == -1 ) {
245 if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { 272 close_pipe_data(p);
246 CloseHandle(p->pipe[0]);
247 }
248 if ( p->pipe[1] != INVALID_HANDLE_VALUE ) {
249 CloseHandle(p->pipe[1]);
250 }
251 } 273 }
252 else { 274 else {
253 p->mode = *mode;
254 p->fd = fd; 275 p->fd = fd;
255 if ( pid ) { 276 if ( pid ) {
256 *pid = (pid_t)p->piProcInfo.dwProcessId; 277 *pid = (pid_t)p->piProcInfo.dwProcessId;
@@ -260,41 +281,28 @@ finito:
260 return fd; 281 return fd;
261} 282}
262 283
284int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid)
285{
286 return mingw_popen_internal(NULL, cmd, mode, fd0, pid);
287}
288
263int mingw_pclose(FILE *fp) 289int mingw_pclose(FILE *fp)
264{ 290{
265 int i, ip, fd; 291 int fd;
266 pipe_data *p = NULL; 292 pipe_data *p;
267 DWORD ret; 293 DWORD ret;
268 294
269 if ( fp == NULL ) {
270 return -1;
271 }
272
273 /* find struct containing fd */ 295 /* find struct containing fd */
274 fd = fileno(fp); 296 if (fp == NULL || (fd=fileno(fp)) == -1 || (p=find_pipe(fd)) == NULL)
275 for ( i=0; i<num_pipes; ++i ) {
276 if ( pipes[i].mode && pipes[i].fd == fd ) {
277 p = pipes+i;
278 break;
279 }
280 }
281
282 if ( p == NULL ) {
283 /* no pipe data, maybe fd isn't a pipe? */
284 return -1; 297 return -1;
285 }
286 298
287 fclose(fp); 299 fclose(fp);
288 300
289 ip = !(p->mode == 'r');
290 CloseHandle(p->pipe[ip]);
291
292 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE); 301 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE);
293 302
294 CloseHandle(p->piProcInfo.hProcess); 303 CloseHandle(p->piProcInfo.hProcess);
295 CloseHandle(p->piProcInfo.hThread); 304 CloseHandle(p->piProcInfo.hThread);
296 305 close_pipe_data(p);
297 p->mode = '\0';
298 306
299 return (ret == WAIT_OBJECT_0) ? 0 : -1; 307 return (ret == WAIT_OBJECT_0) ? 0 : -1;
300} 308}