Skip to content

Commit 56b970f

Browse files
committed
to_char(): prevent writing beyond the allocated buffer
Previously very long localized month and weekday strings could overflow the allocated buffers, causing a server crash. Reported and patch reviewed by Noah Misch. Backpatch to all supported versions. Security: CVE-2015-0241
1 parent 611e110 commit 56b970f

File tree

1 file changed

+126
-15
lines changed

1 file changed

+126
-15
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
* Maximal length of one node
110110
* ----------
111111
*/
112-
#define DCH_MAX_ITEM_SIZ 9 /* max julian day */
112+
#define DCH_MAX_ITEM_SIZ 12 /* max localized day name */
113113
#define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */
114114

115115
/* ----------
@@ -524,10 +524,12 @@ do { \
524524
* Suffixes definition for DATE-TIME TO/FROM CHAR
525525
* ----------
526526
*/
527+
#define TM_SUFFIX_LEN 2
528+
527529
static KeySuffix DCH_suff[] = {
528530
{"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
529531
{"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
530-
{"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
532+
{"TM", TM_SUFFIX_LEN, DCH_S_TM, SUFFTYPE_PREFIX},
531533
{"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
532534
{"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
533535
{"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
@@ -536,6 +538,7 @@ static KeySuffix DCH_suff[] = {
536538
{NULL, 0, 0, 0}
537539
};
538540

541+
539542
/* ----------
540543
* Format-pictures (KeyWord).
541544
*
@@ -2292,18 +2295,36 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
22922295
if (!tm->tm_mon)
22932296
break;
22942297
if (S_TM(n->suffix))
2295-
strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1]));
2298+
{
2299+
char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1]);
2300+
2301+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2302+
strcpy(s, str);
2303+
else
2304+
ereport(ERROR,
2305+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2306+
errmsg("localized string format value too long")));
2307+
}
22962308
else
22972309
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2298-
asc_toupper_z(months_full[tm->tm_mon - 1]));
2310+
asc_toupper_z(months_full[tm->tm_mon - 1]));
22992311
s += strlen(s);
23002312
break;
23012313
case DCH_Month:
23022314
INVALID_FOR_INTERVAL;
23032315
if (!tm->tm_mon)
23042316
break;
23052317
if (S_TM(n->suffix))
2306-
strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1]));
2318+
{
2319+
char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1]);
2320+
2321+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2322+
strcpy(s, str);
2323+
else
2324+
ereport(ERROR,
2325+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2326+
errmsg("localized string format value too long")));
2327+
}
23072328
else
23082329
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
23092330
months_full[tm->tm_mon - 1]);
@@ -2314,7 +2335,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23142335
if (!tm->tm_mon)
23152336
break;
23162337
if (S_TM(n->suffix))
2317-
strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1]));
2338+
{
2339+
char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1]);
2340+
2341+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2342+
strcpy(s, str);
2343+
else
2344+
ereport(ERROR,
2345+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2346+
errmsg("localized string format value too long")));
2347+
}
23182348
else
23192349
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
23202350
asc_tolower_z(months_full[tm->tm_mon - 1]));
@@ -2325,7 +2355,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23252355
if (!tm->tm_mon)
23262356
break;
23272357
if (S_TM(n->suffix))
2328-
strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1]));
2358+
{
2359+
char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1]);
2360+
2361+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2362+
strcpy(s, str);
2363+
else
2364+
ereport(ERROR,
2365+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2366+
errmsg("localized string format value too long")));
2367+
}
23292368
else
23302369
strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
23312370
s += strlen(s);
@@ -2335,7 +2374,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23352374
if (!tm->tm_mon)
23362375
break;
23372376
if (S_TM(n->suffix))
2338-
strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1]));
2377+
{
2378+
char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1]);
2379+
2380+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2381+
strcpy(s, str);
2382+
else
2383+
ereport(ERROR,
2384+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2385+
errmsg("localized string format value too long")));
2386+
}
23392387
else
23402388
strcpy(s, months[tm->tm_mon - 1]);
23412389
s += strlen(s);
@@ -2345,7 +2393,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23452393
if (!tm->tm_mon)
23462394
break;
23472395
if (S_TM(n->suffix))
2348-
strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1]));
2396+
{
2397+
char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1]);
2398+
2399+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2400+
strcpy(s, str);
2401+
else
2402+
ereport(ERROR,
2403+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2404+
errmsg("localized string format value too long")));
2405+
}
23492406
else
23502407
strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
23512408
s += strlen(s);
@@ -2359,7 +2416,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23592416
case DCH_DAY:
23602417
INVALID_FOR_INTERVAL;
23612418
if (S_TM(n->suffix))
2362-
strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday]));
2419+
{
2420+
char *str = str_toupper_z(localized_full_days[tm->tm_wday]);
2421+
2422+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2423+
strcpy(s, str);
2424+
else
2425+
ereport(ERROR,
2426+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2427+
errmsg("localized string format value too long")));
2428+
}
23632429
else
23642430
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
23652431
asc_toupper_z(days[tm->tm_wday]));
@@ -2368,7 +2434,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23682434
case DCH_Day:
23692435
INVALID_FOR_INTERVAL;
23702436
if (S_TM(n->suffix))
2371-
strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday]));
2437+
{
2438+
char *str = str_initcap_z(localized_full_days[tm->tm_wday]);
2439+
2440+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2441+
strcpy(s, str);
2442+
else
2443+
ereport(ERROR,
2444+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2445+
errmsg("localized string format value too long")));
2446+
}
23722447
else
23732448
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
23742449
days[tm->tm_wday]);
@@ -2377,7 +2452,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23772452
case DCH_day:
23782453
INVALID_FOR_INTERVAL;
23792454
if (S_TM(n->suffix))
2380-
strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday]));
2455+
{
2456+
char *str = str_tolower_z(localized_full_days[tm->tm_wday]);
2457+
2458+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2459+
strcpy(s, str);
2460+
else
2461+
ereport(ERROR,
2462+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2463+
errmsg("localized string format value too long")));
2464+
}
23812465
else
23822466
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
23832467
asc_tolower_z(days[tm->tm_wday]));
@@ -2386,23 +2470,50 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out)
23862470
case DCH_DY:
23872471
INVALID_FOR_INTERVAL;
23882472
if (S_TM(n->suffix))
2389-
strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday]));
2473+
{
2474+
char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday]);
2475+
2476+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2477+
strcpy(s, str);
2478+
else
2479+
ereport(ERROR,
2480+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2481+
errmsg("localized string format value too long")));
2482+
}
23902483
else
23912484
strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
23922485
s += strlen(s);
23932486
break;
23942487
case DCH_Dy:
23952488
INVALID_FOR_INTERVAL;
23962489
if (S_TM(n->suffix))
2397-
strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday]));
2490+
{
2491+
char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday]);
2492+
2493+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2494+
strcpy(s, str);
2495+
else
2496+
ereport(ERROR,
2497+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2498+
errmsg("localized string format value too long")));
2499+
}
23982500
else
23992501
strcpy(s, days_short[tm->tm_wday]);
24002502
s += strlen(s);
24012503
break;
24022504
case DCH_dy:
24032505
INVALID_FOR_INTERVAL;
24042506
if (S_TM(n->suffix))
2405-
strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday]));
2507+
{
2508+
char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday]);
2509+
2510+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2511+
strcpy(s, str);
2512+
else
2513+
ereport(ERROR,
2514+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2515+
errmsg("localized string format value too long")));
2516+
}
24062517
else
24072518
strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
24082519
s += strlen(s);

0 commit comments

Comments
 (0)