diff options
author | Ron Yorston <rmy@pobox.com> | 2018-04-07 16:07:26 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-04-07 16:07:26 +0100 |
commit | 5b725727b90f1e5b4dbf1c304cfe3fa534767f15 (patch) | |
tree | 20634e3b4e970fe9a43c1f809fa05ce62fb02130 | |
parent | eda6f28c793db7d5a61ec4d8d801dfcb6def17b7 (diff) | |
download | busybox-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.c | 124 |
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 @@ | |||
5 | typedef struct { | 5 | typedef 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 | ||
12 | static pipe_data *pipes = NULL; | 11 | static pipe_data *pipes = NULL; |
13 | static int num_pipes = 0; | 12 | static int num_pipes = 0; |
14 | 13 | ||
14 | static int mingw_popen_internal(pipe_data *p, const char *cmd, | ||
15 | const char *mode, int fd0, pid_t *pid); | ||
16 | |||
15 | static int mingw_pipe(pipe_data *p, int bidi) | 17 | static 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 | |||
55 | static 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 | |||
63 | static 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 | ||
58 | static 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 | */ | ||
78 | static 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 | ||
92 | FILE *mingw_popen(const char *cmd, const char *mode) | 113 | FILE *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 | */ |
160 | int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid) | 186 | static 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 | ||
243 | finito: | 270 | finito: |
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 | ||
284 | int 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 | |||
263 | int mingw_pclose(FILE *fp) | 289 | int 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 | } |