diff options
author | tb <> | 2020-09-24 19:29:09 +0000 |
---|---|---|
committer | tb <> | 2020-09-24 19:29:09 +0000 |
commit | 019d699d5cdb8e0fbd506ab1f8a1b1c872f69dd3 (patch) | |
tree | 83099f355e9ebf9fa764f4ff2037fb540437baf8 /src/lib | |
parent | 8b60c9a777523278ddbc7a43f410248840567f0d (diff) | |
download | openbsd-019d699d5cdb8e0fbd506ab1f8a1b1c872f69dd3.tar.gz openbsd-019d699d5cdb8e0fbd506ab1f8a1b1c872f69dd3.tar.bz2 openbsd-019d699d5cdb8e0fbd506ab1f8a1b1c872f69dd3.zip |
Fix a number of leaks in the UI_dup_* functions
If any of general_allocate_{prompt,string,boolean}() fail, the
UI_dup_* functions may leak the strings they strduped beforehand.
Instead, use strdup inside these functions, so we can free as
necessary. This makes the UI_add_* and UI_dup_* simple wrappers
around general_allocate_{string,boolean}() that differ only in
passing a Boolean that indicates whether or not to use strdup.
Make a general cleanup pass over these functions, simplify the
logic and make it overall a bit easier to follow. While there,
use strcspn() instead of a handrolled variant.
The only changes in behavior are that ERR_R_MALLOC_FAILURE is now
pushed onto the stack a bit more often and that UI_dup_input_string()
now returns -1 on failure to dup prompt like all the other UI_dup_*
functions. This is not a problem since the manual already documents
that errors are signaled with <= 0. The only consumer of this function
according to Debian's codesearch is libp11, I sent them a PR to fix
their (already broken) error handling.
Addresses about 10 errors thrown by the LLVM static analyzer in ui/.
ok jsing
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/ui/ui_lib.c | 242 |
1 files changed, 99 insertions, 143 deletions
diff --git a/src/lib/libcrypto/ui/ui_lib.c b/src/lib/libcrypto/ui/ui_lib.c index 32a56e581b..e349cb3853 100644 --- a/src/lib/libcrypto/ui/ui_lib.c +++ b/src/lib/libcrypto/ui/ui_lib.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ui_lib.c,v 1.36 2020/09/24 19:24:45 tb Exp $ */ | 1 | /* $OpenBSD: ui_lib.c,v 1.37 2020/09/24 19:29:09 tb Exp $ */ |
2 | /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL | 2 | /* Written by Richard Levitte (richard@levitte.org) for the OpenSSL |
3 | * project 2001. | 3 | * project 2001. |
4 | */ | 4 | */ |
@@ -139,90 +139,123 @@ allocate_string_stack(UI *ui) | |||
139 | } | 139 | } |
140 | 140 | ||
141 | static UI_STRING * | 141 | static UI_STRING * |
142 | general_allocate_prompt(UI *ui, const char *prompt, int prompt_freeable, | 142 | general_allocate_prompt(const char *prompt, int dup_prompt, |
143 | enum UI_string_types type, int input_flags, char *result_buf) | 143 | enum UI_string_types type, int input_flags, char *result_buf) |
144 | { | 144 | { |
145 | UI_STRING *ret = NULL; | 145 | UI_STRING *uis = NULL; |
146 | 146 | ||
147 | if (prompt == NULL) { | 147 | if (prompt == NULL) { |
148 | UIerror(ERR_R_PASSED_NULL_PARAMETER); | 148 | UIerror(ERR_R_PASSED_NULL_PARAMETER); |
149 | } else if ((type == UIT_PROMPT || type == UIT_VERIFY || | 149 | goto err; |
150 | type == UIT_BOOLEAN) && result_buf == NULL) { | 150 | } |
151 | if ((type == UIT_PROMPT || type == UIT_VERIFY || type == UIT_BOOLEAN) && | ||
152 | result_buf == NULL) { | ||
151 | UIerror(UI_R_NO_RESULT_BUFFER); | 153 | UIerror(UI_R_NO_RESULT_BUFFER); |
152 | } else if ((ret = malloc(sizeof(UI_STRING)))) { | 154 | goto err; |
153 | ret->out_string = prompt; | ||
154 | ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0; | ||
155 | ret->input_flags = input_flags; | ||
156 | ret->type = type; | ||
157 | ret->result_buf = result_buf; | ||
158 | } | 155 | } |
159 | return ret; | 156 | |
157 | if ((uis = calloc(1, sizeof(UI_STRING))) == NULL) { | ||
158 | UIerror(ERR_R_MALLOC_FAILURE); | ||
159 | goto err; | ||
160 | } | ||
161 | uis->out_string = prompt; | ||
162 | if (dup_prompt) { | ||
163 | if ((uis->out_string = strdup(prompt)) == NULL) { | ||
164 | UIerror(ERR_R_MALLOC_FAILURE); | ||
165 | goto err; | ||
166 | } | ||
167 | uis->flags = OUT_STRING_FREEABLE; | ||
168 | } | ||
169 | uis->input_flags = input_flags; | ||
170 | uis->type = type; | ||
171 | uis->result_buf = result_buf; | ||
172 | |||
173 | return uis; | ||
174 | |||
175 | err: | ||
176 | free_string(uis); | ||
177 | return NULL; | ||
160 | } | 178 | } |
161 | 179 | ||
162 | static int | 180 | static int |
163 | general_allocate_string(UI *ui, const char *prompt, int prompt_freeable, | 181 | general_allocate_string(UI *ui, const char *prompt, int dup_prompt, |
164 | enum UI_string_types type, int input_flags, char *result_buf, int minsize, | 182 | enum UI_string_types type, int input_flags, char *result_buf, int minsize, |
165 | int maxsize, const char *test_buf) | 183 | int maxsize, const char *test_buf) |
166 | { | 184 | { |
167 | int ret = -1; | 185 | UI_STRING *s; |
168 | UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable, | 186 | int ret; |
169 | type, input_flags, result_buf); | 187 | |
170 | 188 | if ((s = general_allocate_prompt(prompt, dup_prompt, type, input_flags, | |
171 | if (s) { | 189 | result_buf)) == NULL) |
172 | if (allocate_string_stack(ui) >= 0) { | 190 | goto err; |
173 | s->_.string_data.result_minsize = minsize; | 191 | s->_.string_data.result_minsize = minsize; |
174 | s->_.string_data.result_maxsize = maxsize; | 192 | s->_.string_data.result_maxsize = maxsize; |
175 | s->_.string_data.test_buf = test_buf; | 193 | s->_.string_data.test_buf = test_buf; |
176 | ret = sk_UI_STRING_push(ui->strings, s); | 194 | |
177 | /* sk_push() returns 0 on error. Let's adapt that */ | 195 | if (allocate_string_stack(ui) < 0) |
178 | if (ret <= 0) | 196 | goto err; |
179 | ret--; | 197 | if ((ret = sk_UI_STRING_push(ui->strings, s)) <= 0) |
180 | } else | 198 | goto err; |
181 | free_string(s); | 199 | |
182 | } | ||
183 | return ret; | 200 | return ret; |
201 | |||
202 | err: | ||
203 | free_string(s); | ||
204 | return -1; | ||
184 | } | 205 | } |
185 | 206 | ||
186 | static int | 207 | static int |
187 | general_allocate_boolean(UI *ui, const char *prompt, const char *action_desc, | 208 | general_allocate_boolean(UI *ui, const char *prompt, const char *action_desc, |
188 | const char *ok_chars, const char *cancel_chars, int prompt_freeable, | 209 | const char *ok_chars, const char *cancel_chars, int dup_strings, |
189 | enum UI_string_types type, int input_flags, char *result_buf) | 210 | enum UI_string_types type, int input_flags, char *result_buf) |
190 | { | 211 | { |
191 | int ret = -1; | 212 | UI_STRING *s = NULL; |
192 | UI_STRING *s; | 213 | int ret; |
193 | const char *p; | ||
194 | 214 | ||
195 | if (ok_chars == NULL) { | 215 | if (ok_chars == NULL || cancel_chars == NULL) { |
196 | UIerror(ERR_R_PASSED_NULL_PARAMETER); | 216 | UIerror(ERR_R_PASSED_NULL_PARAMETER); |
197 | } else if (cancel_chars == NULL) { | 217 | goto err; |
198 | UIerror(ERR_R_PASSED_NULL_PARAMETER); | 218 | } |
199 | } else { | 219 | if (ok_chars[strcspn(ok_chars, cancel_chars)] != '\0') |
200 | for (p = ok_chars; *p; p++) { | 220 | UIerror(UI_R_COMMON_OK_AND_CANCEL_CHARACTERS); |
201 | if (strchr(cancel_chars, *p)) { | 221 | |
202 | UIerror(UI_R_COMMON_OK_AND_CANCEL_CHARACTERS); | 222 | if ((s = general_allocate_prompt(prompt, dup_strings, type, input_flags, |
223 | result_buf)) == NULL) | ||
224 | goto err; | ||
225 | |||
226 | if (dup_strings) { | ||
227 | if (action_desc != NULL) { | ||
228 | if ((s->_.boolean_data.action_desc = | ||
229 | strdup(action_desc)) == NULL) { | ||
230 | UIerror(ERR_R_MALLOC_FAILURE); | ||
231 | goto err; | ||
203 | } | 232 | } |
204 | } | 233 | } |
205 | 234 | if ((s->_.boolean_data.ok_chars = strdup(ok_chars)) == NULL) { | |
206 | s = general_allocate_prompt(ui, prompt, prompt_freeable, | 235 | UIerror(ERR_R_MALLOC_FAILURE); |
207 | type, input_flags, result_buf); | 236 | goto err; |
208 | 237 | } | |
209 | if (s) { | 238 | if ((s->_.boolean_data.cancel_chars = strdup(cancel_chars)) == |
210 | if (allocate_string_stack(ui) >= 0) { | 239 | NULL) { |
211 | s->_.boolean_data.action_desc = action_desc; | 240 | UIerror(ERR_R_MALLOC_FAILURE); |
212 | s->_.boolean_data.ok_chars = ok_chars; | 241 | goto err; |
213 | s->_.boolean_data.cancel_chars = cancel_chars; | ||
214 | ret = sk_UI_STRING_push(ui->strings, s); | ||
215 | /* | ||
216 | * sk_push() returns 0 on error. Let's adapt | ||
217 | * that | ||
218 | */ | ||
219 | if (ret <= 0) | ||
220 | ret--; | ||
221 | } else | ||
222 | free_string(s); | ||
223 | } | 242 | } |
243 | } else { | ||
244 | s->_.boolean_data.action_desc = action_desc; | ||
245 | s->_.boolean_data.ok_chars = ok_chars; | ||
246 | s->_.boolean_data.cancel_chars = cancel_chars; | ||
224 | } | 247 | } |
248 | |||
249 | if (allocate_string_stack(ui) < 0) | ||
250 | goto err; | ||
251 | if ((ret = sk_UI_STRING_push(ui->strings, s)) <= 0) | ||
252 | goto err; | ||
253 | |||
225 | return ret; | 254 | return ret; |
255 | |||
256 | err: | ||
257 | free_string(s); | ||
258 | return -1; | ||
226 | } | 259 | } |
227 | 260 | ||
228 | /* Returns the index to the place in the stack or -1 for error. Uses a | 261 | /* Returns the index to the place in the stack or -1 for error. Uses a |
@@ -240,16 +273,7 @@ int | |||
240 | UI_dup_input_string(UI *ui, const char *prompt, int flags, char *result_buf, | 273 | UI_dup_input_string(UI *ui, const char *prompt, int flags, char *result_buf, |
241 | int minsize, int maxsize) | 274 | int minsize, int maxsize) |
242 | { | 275 | { |
243 | char *prompt_copy = NULL; | 276 | return general_allocate_string(ui, prompt, 1, UIT_PROMPT, flags, |
244 | |||
245 | if (prompt) { | ||
246 | prompt_copy = strdup(prompt); | ||
247 | if (prompt_copy == NULL) { | ||
248 | UIerror(ERR_R_MALLOC_FAILURE); | ||
249 | return 0; | ||
250 | } | ||
251 | } | ||
252 | return general_allocate_string(ui, prompt_copy, 1, UIT_PROMPT, flags, | ||
253 | result_buf, minsize, maxsize, NULL); | 277 | result_buf, minsize, maxsize, NULL); |
254 | } | 278 | } |
255 | 279 | ||
@@ -265,16 +289,7 @@ int | |||
265 | UI_dup_verify_string(UI *ui, const char *prompt, int flags, | 289 | UI_dup_verify_string(UI *ui, const char *prompt, int flags, |
266 | char *result_buf, int minsize, int maxsize, const char *test_buf) | 290 | char *result_buf, int minsize, int maxsize, const char *test_buf) |
267 | { | 291 | { |
268 | char *prompt_copy = NULL; | 292 | return general_allocate_string(ui, prompt, 1, UIT_VERIFY, flags, |
269 | |||
270 | if (prompt) { | ||
271 | prompt_copy = strdup(prompt); | ||
272 | if (prompt_copy == NULL) { | ||
273 | UIerror(ERR_R_MALLOC_FAILURE); | ||
274 | return -1; | ||
275 | } | ||
276 | } | ||
277 | return general_allocate_string(ui, prompt_copy, 1, UIT_VERIFY, flags, | ||
278 | result_buf, minsize, maxsize, test_buf); | 293 | result_buf, minsize, maxsize, test_buf); |
279 | } | 294 | } |
280 | 295 | ||
@@ -290,49 +305,8 @@ int | |||
290 | UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc, | 305 | UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc, |
291 | const char *ok_chars, const char *cancel_chars, int flags, char *result_buf) | 306 | const char *ok_chars, const char *cancel_chars, int flags, char *result_buf) |
292 | { | 307 | { |
293 | char *prompt_copy = NULL; | 308 | return general_allocate_boolean(ui, prompt, action_desc, ok_chars, |
294 | char *action_desc_copy = NULL; | 309 | cancel_chars, 1, UIT_BOOLEAN, flags, result_buf); |
295 | char *ok_chars_copy = NULL; | ||
296 | char *cancel_chars_copy = NULL; | ||
297 | |||
298 | if (prompt) { | ||
299 | prompt_copy = strdup(prompt); | ||
300 | if (prompt_copy == NULL) { | ||
301 | UIerror(ERR_R_MALLOC_FAILURE); | ||
302 | goto err; | ||
303 | } | ||
304 | } | ||
305 | if (action_desc) { | ||
306 | action_desc_copy = strdup(action_desc); | ||
307 | if (action_desc_copy == NULL) { | ||
308 | UIerror(ERR_R_MALLOC_FAILURE); | ||
309 | goto err; | ||
310 | } | ||
311 | } | ||
312 | if (ok_chars) { | ||
313 | ok_chars_copy = strdup(ok_chars); | ||
314 | if (ok_chars_copy == NULL) { | ||
315 | UIerror(ERR_R_MALLOC_FAILURE); | ||
316 | goto err; | ||
317 | } | ||
318 | } | ||
319 | if (cancel_chars) { | ||
320 | cancel_chars_copy = strdup(cancel_chars); | ||
321 | if (cancel_chars_copy == NULL) { | ||
322 | UIerror(ERR_R_MALLOC_FAILURE); | ||
323 | goto err; | ||
324 | } | ||
325 | } | ||
326 | return general_allocate_boolean(ui, prompt_copy, action_desc_copy, | ||
327 | ok_chars_copy, cancel_chars_copy, 1, UIT_BOOLEAN, flags, | ||
328 | result_buf); | ||
329 | |||
330 | err: | ||
331 | free(prompt_copy); | ||
332 | free(action_desc_copy); | ||
333 | free(ok_chars_copy); | ||
334 | free(cancel_chars_copy); | ||
335 | return -1; | ||
336 | } | 310 | } |
337 | 311 | ||
338 | int | 312 | int |
@@ -345,17 +319,8 @@ UI_add_info_string(UI *ui, const char *text) | |||
345 | int | 319 | int |
346 | UI_dup_info_string(UI *ui, const char *text) | 320 | UI_dup_info_string(UI *ui, const char *text) |
347 | { | 321 | { |
348 | char *text_copy = NULL; | 322 | return general_allocate_string(ui, text, 1, UIT_INFO, 0, NULL, 0, 0, |
349 | 323 | NULL); | |
350 | if (text) { | ||
351 | text_copy = strdup(text); | ||
352 | if (text_copy == NULL) { | ||
353 | UIerror(ERR_R_MALLOC_FAILURE); | ||
354 | return -1; | ||
355 | } | ||
356 | } | ||
357 | return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL, | ||
358 | 0, 0, NULL); | ||
359 | } | 324 | } |
360 | 325 | ||
361 | int | 326 | int |
@@ -368,17 +333,8 @@ UI_add_error_string(UI *ui, const char *text) | |||
368 | int | 333 | int |
369 | UI_dup_error_string(UI *ui, const char *text) | 334 | UI_dup_error_string(UI *ui, const char *text) |
370 | { | 335 | { |
371 | char *text_copy = NULL; | 336 | return general_allocate_string(ui, text, 1, UIT_ERROR, 0, NULL, 0, 0, |
372 | 337 | NULL); | |
373 | if (text) { | ||
374 | text_copy = strdup(text); | ||
375 | if (text_copy == NULL) { | ||
376 | UIerror(ERR_R_MALLOC_FAILURE); | ||
377 | return -1; | ||
378 | } | ||
379 | } | ||
380 | return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL, | ||
381 | 0, 0, NULL); | ||
382 | } | 338 | } |
383 | 339 | ||
384 | char * | 340 | char * |