mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
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
This commit is contained in:
parent
b08c7aff70
commit
9b5e831e34
@ -1014,15 +1014,16 @@ pg_GSS_recvauth(Port *port)
|
||||
size_t kt_len = strlen(pg_krb_server_keyfile) + 14;
|
||||
char *kt_path = malloc(kt_len);
|
||||
|
||||
if (!kt_path)
|
||||
if (!kt_path ||
|
||||
snprintf(kt_path, kt_len, "KRB5_KTNAME=%s",
|
||||
pg_krb_server_keyfile) != kt_len - 2 ||
|
||||
putenv(kt_path) != 0)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", pg_krb_server_keyfile);
|
||||
putenv(kt_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,24 +558,34 @@ PGLC_localeconv(void)
|
||||
* pg_strftime(), which isn't locale-aware and does not need to be replaced.
|
||||
*/
|
||||
static size_t
|
||||
strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm * tm)
|
||||
strftime_win32(char *dst, size_t dstlen,
|
||||
const char *format, const struct tm * tm)
|
||||
{
|
||||
size_t len;
|
||||
wchar_t wformat[8]; /* formats used below need 3 bytes */
|
||||
wchar_t wbuf[MAX_L10N_DATA];
|
||||
int encoding;
|
||||
|
||||
encoding = GetDatabaseEncoding();
|
||||
|
||||
len = wcsftime(wbuf, MAX_L10N_DATA, format, tm);
|
||||
/* get a wchar_t version of the format string */
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, format, -1,
|
||||
wformat, lengthof(wformat));
|
||||
if (len == 0)
|
||||
elog(ERROR, "could not convert format string from UTF-8: error code %lu",
|
||||
GetLastError());
|
||||
|
||||
len = wcsftime(wbuf, MAX_L10N_DATA, wformat, tm);
|
||||
if (len == 0)
|
||||
|
||||
/*
|
||||
* strftime call failed - return 0 with the contents of dst
|
||||
* unspecified
|
||||
* strftime failed, possibly because the result would not fit in
|
||||
* MAX_L10N_DATA. Return 0 with the contents of dst unspecified.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL, NULL);
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen - 1,
|
||||
NULL, NULL);
|
||||
if (len == 0)
|
||||
elog(ERROR,
|
||||
"could not convert string to UTF-8:error %lu", GetLastError());
|
||||
@ -596,9 +606,33 @@ strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm
|
||||
}
|
||||
|
||||
/* redefine strftime() */
|
||||
#define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
|
||||
#define strftime(a,b,c,d) strftime_win32(a,b,c,d)
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* Subroutine for cache_locale_time(). */
|
||||
static void
|
||||
cache_single_time(char **dst, const char *format, const struct tm * tm)
|
||||
{
|
||||
char buf[MAX_L10N_DATA];
|
||||
char *ptr;
|
||||
|
||||
/*
|
||||
* MAX_L10N_DATA is sufficient buffer space for every known locale, and
|
||||
* POSIX defines no strftime() errors. (Buffer space exhaustion is not an
|
||||
* error.) An implementation might report errors (e.g. ENOMEM) by
|
||||
* returning 0 (or, less plausibly, a negative value) and setting errno.
|
||||
* Report errno just in case the implementation did that, but clear it in
|
||||
* advance of the call so we don't emit a stale, unrelated errno.
|
||||
*/
|
||||
errno = 0;
|
||||
if (strftime(buf, MAX_L10N_DATA, format, tm) <= 0)
|
||||
elog(ERROR, "strftime(%s) failed: %m", format);
|
||||
|
||||
ptr = MemoryContextStrdup(TopMemoryContext, buf);
|
||||
if (*dst)
|
||||
pfree(*dst);
|
||||
*dst = ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the lc_time localization cache variables if needed.
|
||||
@ -609,8 +643,6 @@ cache_locale_time(void)
|
||||
char *save_lc_time;
|
||||
time_t timenow;
|
||||
struct tm *timeinfo;
|
||||
char buf[MAX_L10N_DATA];
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
#ifdef WIN32
|
||||
@ -657,17 +689,8 @@ cache_locale_time(void)
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
timeinfo->tm_wday = i;
|
||||
strftime(buf, MAX_L10N_DATA, "%a", timeinfo);
|
||||
ptr = MemoryContextStrdup(TopMemoryContext, buf);
|
||||
if (localized_abbrev_days[i])
|
||||
pfree(localized_abbrev_days[i]);
|
||||
localized_abbrev_days[i] = ptr;
|
||||
|
||||
strftime(buf, MAX_L10N_DATA, "%A", timeinfo);
|
||||
ptr = MemoryContextStrdup(TopMemoryContext, buf);
|
||||
if (localized_full_days[i])
|
||||
pfree(localized_full_days[i]);
|
||||
localized_full_days[i] = ptr;
|
||||
cache_single_time(&localized_abbrev_days[i], "%a", timeinfo);
|
||||
cache_single_time(&localized_full_days[i], "%A", timeinfo);
|
||||
}
|
||||
|
||||
/* localized months */
|
||||
@ -675,17 +698,8 @@ cache_locale_time(void)
|
||||
{
|
||||
timeinfo->tm_mon = i;
|
||||
timeinfo->tm_mday = 1; /* make sure we don't have invalid date */
|
||||
strftime(buf, MAX_L10N_DATA, "%b", timeinfo);
|
||||
ptr = MemoryContextStrdup(TopMemoryContext, buf);
|
||||
if (localized_abbrev_months[i])
|
||||
pfree(localized_abbrev_months[i]);
|
||||
localized_abbrev_months[i] = ptr;
|
||||
|
||||
strftime(buf, MAX_L10N_DATA, "%B", timeinfo);
|
||||
ptr = MemoryContextStrdup(TopMemoryContext, buf);
|
||||
if (localized_full_months[i])
|
||||
pfree(localized_full_months[i]);
|
||||
localized_full_months[i] = ptr;
|
||||
cache_single_time(&localized_abbrev_months[i], "%b", timeinfo);
|
||||
cache_single_time(&localized_full_months[i], "%B", timeinfo);
|
||||
}
|
||||
|
||||
/* try to restore internal settings */
|
||||
|
Loading…
Reference in New Issue
Block a user