diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2016-05-30 12:57:22 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2016-05-30 12:57:22 +0000 |
commit | 9be6e5b74ad4bc70cb6a82115bf73c03046db3d4 (patch) | |
tree | 618ab6f155b8f991df9a9e4a656d74d15d3a73c0 /usr.bin/ssh | |
parent | 266fac72e1f616dd32bc3abff13fa36a63b26951 (diff) |
Even when only writing an unescaped character, the dst buffer may need to
grow, or it would be overrun; issue found by tb@ with malloc.conf(5) 'C'.
While here, reserve an additional byte for the terminating NUL
up front such that we don't have to realloc() later just for that.
OK tb@
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/utf8.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/usr.bin/ssh/utf8.c b/usr.bin/ssh/utf8.c index caf789cee65..18ee538583f 100644 --- a/usr.bin/ssh/utf8.c +++ b/usr.bin/ssh/utf8.c @@ -1,4 +1,4 @@ -/* $OpenBSD: utf8.c,v 1.2 2016/05/30 12:05:56 schwarze Exp $ */ +/* $OpenBSD: utf8.c,v 1.3 2016/05/30 12:57:21 schwarze Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> * @@ -33,6 +33,7 @@ #include "utf8.h" static int dangerous_locale(void); +static int grow_dst(char **, size_t *, size_t, char **, size_t); static int vasnmprintf(char **, size_t, int *, const char *, va_list); @@ -53,6 +54,25 @@ dangerous_locale(void) { return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8"); } +static int +grow_dst(char **dst, size_t *sz, size_t maxsz, char **dp, size_t need) +{ + char *tp; + size_t tsz; + + if (*dp + need < *dst + *sz) + return 0; + tsz = *sz + 128; + if (tsz > maxsz) + tsz = maxsz; + if ((tp = realloc(*dst, tsz)) == NULL) + return -1; + *dp = tp + (*dp - *dst); + *dst = tp; + *sz = tsz; + return 0; +} + /* * The following two functions limit the number of bytes written, * including the terminating '\0', to sz. Unless wp is NULL, @@ -74,7 +94,6 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) char *dp; /* Pointer into dst. */ char *tp; /* Temporary pointer for dst. */ size_t sz; /* Number of bytes allocated for dst. */ - size_t tsz; /* Temporary size while extending dst. */ wchar_t wc; /* Wide character at sp. */ int len; /* Number of bytes in the character at sp. */ int ret; /* Number of bytes needed to format src. */ @@ -85,7 +104,7 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) if ((ret = vasprintf(&src, fmt, ap)) <= 0) goto fail; - sz = strlen(src); + sz = strlen(src) + 1; if ((dst = malloc(sz)) == NULL) { free(src); goto fail; @@ -130,6 +149,11 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) total_width > max_width - width)) print = 0; if (print) { + if (grow_dst(&dst, &sz, maxsz, + &dp, len) == -1) { + ret = -1; + break; + } total_width += width; memcpy(dp, sp, len); dp += len; @@ -147,18 +171,10 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) total_width > max_width - 4)) print = 0; if (print) { - if (dp + 4 >= dst + sz) { - tsz = sz + 128; - if (tsz > maxsz) - tsz = maxsz; - tp = realloc(dst, tsz); - if (tp == NULL) { - ret = -1; - break; - } - dp = tp + (dp - dst); - dst = tp; - sz = tsz; + if (grow_dst(&dst, &sz, maxsz, + &dp, 4) == -1) { + ret = -1; + break; } tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0); width = tp - dp; |