Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ca32594

Browse files
committed
Check return values of sensitive system library calls.
PostgreSQL already checked the vast majority of these, missing this handful that nearly cannot fail. If putenv() failed with ENOMEM in pg_GSS_recvauth(), authentication would proceed with the wrong keytab file. If strftime() returned zero in cache_locale_time(), using the unspecified buffer contents could lead to information exposure or a crash. Back-patch to 9.0 (all supported versions). Other unchecked calls to these functions, especially those in frontend code, pose negligible security concern. This patch does not address them. Nonetheless, it is always better to check return values whose specification provides for indicating an error. In passing, fix an off-by-one error in strftime_win32()'s invocation of WideCharToMultiByte(). Upon retrieving a value of exactly MAX_L10N_DATA bytes, strftime_win32() would overrun the caller's buffer by one byte. MAX_L10N_DATA is chosen to exceed the length of every possible value, so the vulnerable scenario probably does not arise. Security: CVE-2015-3166
1 parent 2e3bd06 commit ca32594

File tree

2 files changed

+48
-33
lines changed

2 files changed

+48
-33
lines changed

src/backend/libpq/auth.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -817,15 +817,16 @@ pg_GSS_recvauth(Port *port)
817817
size_t kt_len = strlen(pg_krb_server_keyfile) + 14;
818818
char *kt_path = malloc(kt_len);
819819

820-
if (!kt_path)
820+
if (!kt_path ||
821+
snprintf(kt_path, kt_len, "KRB5_KTNAME=%s",
822+
pg_krb_server_keyfile) != kt_len - 2 ||
823+
putenv(kt_path) != 0)
821824
{
822825
ereport(LOG,
823826
(errcode(ERRCODE_OUT_OF_MEMORY),
824827
errmsg("out of memory")));
825828
return STATUS_ERROR;
826829
}
827-
snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", pg_krb_server_keyfile);
828-
putenv(kt_path);
829830
}
830831
}
831832

src/backend/utils/adt/pg_locale.c

+44-30
Original file line numberDiff line numberDiff line change
@@ -575,22 +575,32 @@ PGLC_localeconv(void)
575575
* pg_strftime(), which isn't locale-aware and does not need to be replaced.
576576
*/
577577
static size_t
578-
strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm * tm)
578+
strftime_win32(char *dst, size_t dstlen,
579+
const char *format, const struct tm * tm)
579580
{
580581
size_t len;
582+
wchar_t wformat[8]; /* formats used below need 3 bytes */
581583
wchar_t wbuf[MAX_L10N_DATA];
582584

583-
len = wcsftime(wbuf, MAX_L10N_DATA, format, tm);
585+
/* get a wchar_t version of the format string */
586+
len = MultiByteToWideChar(CP_UTF8, 0, format, -1,
587+
wformat, lengthof(wformat));
588+
if (len == 0)
589+
elog(ERROR, "could not convert format string from UTF-8: error code %lu",
590+
GetLastError());
591+
592+
len = wcsftime(wbuf, MAX_L10N_DATA, wformat, tm);
584593
if (len == 0)
585594
{
586595
/*
587-
* strftime call failed - return 0 with the contents of dst
588-
* unspecified
596+
* strftime failed, possibly because the result would not fit in
597+
* MAX_L10N_DATA. Return 0 with the contents of dst unspecified.
589598
*/
590599
return 0;
591600
}
592601

593-
len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL, NULL);
602+
len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen - 1,
603+
NULL, NULL);
594604
if (len == 0)
595605
elog(ERROR, "could not convert string to UTF-8: error code %lu",
596606
GetLastError());
@@ -612,9 +622,33 @@ strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm
612622
}
613623

614624
/* redefine strftime() */
615-
#define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
625+
#define strftime(a,b,c,d) strftime_win32(a,b,c,d)
616626
#endif /* WIN32 */
617627

628+
/* Subroutine for cache_locale_time(). */
629+
static void
630+
cache_single_time(char **dst, const char *format, const struct tm * tm)
631+
{
632+
char buf[MAX_L10N_DATA];
633+
char *ptr;
634+
635+
/*
636+
* MAX_L10N_DATA is sufficient buffer space for every known locale, and
637+
* POSIX defines no strftime() errors. (Buffer space exhaustion is not an
638+
* error.) An implementation might report errors (e.g. ENOMEM) by
639+
* returning 0 (or, less plausibly, a negative value) and setting errno.
640+
* Report errno just in case the implementation did that, but clear it in
641+
* advance of the call so we don't emit a stale, unrelated errno.
642+
*/
643+
errno = 0;
644+
if (strftime(buf, MAX_L10N_DATA, format, tm) <= 0)
645+
elog(ERROR, "strftime(%s) failed: %m", format);
646+
647+
ptr = MemoryContextStrdup(TopMemoryContext, buf);
648+
if (*dst)
649+
pfree(*dst);
650+
*dst = ptr;
651+
}
618652

619653
/*
620654
* Update the lc_time localization cache variables if needed.
@@ -625,8 +659,6 @@ cache_locale_time(void)
625659
char *save_lc_time;
626660
time_t timenow;
627661
struct tm *timeinfo;
628-
char buf[MAX_L10N_DATA];
629-
char *ptr;
630662
int i;
631663

632664
#ifdef WIN32
@@ -673,35 +705,17 @@ cache_locale_time(void)
673705
for (i = 0; i < 7; i++)
674706
{
675707
timeinfo->tm_wday = i;
676-
strftime(buf, MAX_L10N_DATA, "%a", timeinfo);
677-
ptr = MemoryContextStrdup(TopMemoryContext, buf);
678-
if (localized_abbrev_days[i])
679-
pfree(localized_abbrev_days[i]);
680-
localized_abbrev_days[i] = ptr;
681-
682-
strftime(buf, MAX_L10N_DATA, "%A", timeinfo);
683-
ptr = MemoryContextStrdup(TopMemoryContext, buf);
684-
if (localized_full_days[i])
685-
pfree(localized_full_days[i]);
686-
localized_full_days[i] = ptr;
708+
cache_single_time(&localized_abbrev_days[i], "%a", timeinfo);
709+
cache_single_time(&localized_full_days[i], "%A", timeinfo);
687710
}
688711

689712
/* localized months */
690713
for (i = 0; i < 12; i++)
691714
{
692715
timeinfo->tm_mon = i;
693716
timeinfo->tm_mday = 1; /* make sure we don't have invalid date */
694-
strftime(buf, MAX_L10N_DATA, "%b", timeinfo);
695-
ptr = MemoryContextStrdup(TopMemoryContext, buf);
696-
if (localized_abbrev_months[i])
697-
pfree(localized_abbrev_months[i]);
698-
localized_abbrev_months[i] = ptr;
699-
700-
strftime(buf, MAX_L10N_DATA, "%B", timeinfo);
701-
ptr = MemoryContextStrdup(TopMemoryContext, buf);
702-
if (localized_full_months[i])
703-
pfree(localized_full_months[i]);
704-
localized_full_months[i] = ptr;
717+
cache_single_time(&localized_abbrev_months[i], "%b", timeinfo);
718+
cache_single_time(&localized_full_months[i], "%B", timeinfo);
705719
}
706720

707721
/* try to restore internal settings */

0 commit comments

Comments
 (0)