Skip to content

Commit 2ceb63d

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 037529a commit 2ceb63d

File tree

1 file changed

+125
-14
lines changed

1 file changed

+125
-14
lines changed

src/backend/utils/adt/formatting.c

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

116116
/* ----------
@@ -525,10 +525,12 @@ do { \
525525
* Suffixes definition for DATE-TIME TO/FROM CHAR
526526
* ----------
527527
*/
528+
#define TM_SUFFIX_LEN 2
529+
528530
static KeySuffix DCH_suff[] = {
529531
{"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
530532
{"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
531-
{"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
533+
{"TM", TM_SUFFIX_LEN, DCH_S_TM, SUFFTYPE_PREFIX},
532534
{"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
533535
{"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
534536
{"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
@@ -537,6 +539,7 @@ static KeySuffix DCH_suff[] = {
537539
{NULL, 0, 0, 0}
538540
};
539541

542+
540543
/* ----------
541544
* Format-pictures (KeyWord).
542545
*
@@ -2495,7 +2498,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
24952498
if (!tm->tm_mon)
24962499
break;
24972500
if (S_TM(n->suffix))
2498-
strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
2501+
{
2502+
char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
2503+
2504+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2505+
strcpy(s, str);
2506+
else
2507+
ereport(ERROR,
2508+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2509+
errmsg("localized string format value too long")));
2510+
}
24992511
else
25002512
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25012513
asc_toupper_z(months_full[tm->tm_mon - 1]));
@@ -2506,7 +2518,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25062518
if (!tm->tm_mon)
25072519
break;
25082520
if (S_TM(n->suffix))
2509-
strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
2521+
{
2522+
char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
2523+
2524+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2525+
strcpy(s, str);
2526+
else
2527+
ereport(ERROR,
2528+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2529+
errmsg("localized string format value too long")));
2530+
}
25102531
else
25112532
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25122533
months_full[tm->tm_mon - 1]);
@@ -2517,7 +2538,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25172538
if (!tm->tm_mon)
25182539
break;
25192540
if (S_TM(n->suffix))
2520-
strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
2541+
{
2542+
char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
2543+
2544+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2545+
strcpy(s, str);
2546+
else
2547+
ereport(ERROR,
2548+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2549+
errmsg("localized string format value too long")));
2550+
}
25212551
else
25222552
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25232553
asc_tolower_z(months_full[tm->tm_mon - 1]));
@@ -2528,7 +2558,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25282558
if (!tm->tm_mon)
25292559
break;
25302560
if (S_TM(n->suffix))
2531-
strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2561+
{
2562+
char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2563+
2564+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2565+
strcpy(s, str);
2566+
else
2567+
ereport(ERROR,
2568+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2569+
errmsg("localized string format value too long")));
2570+
}
25322571
else
25332572
strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
25342573
s += strlen(s);
@@ -2538,7 +2577,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25382577
if (!tm->tm_mon)
25392578
break;
25402579
if (S_TM(n->suffix))
2541-
strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2580+
{
2581+
char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2582+
2583+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2584+
strcpy(s, str);
2585+
else
2586+
ereport(ERROR,
2587+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2588+
errmsg("localized string format value too long")));
2589+
}
25422590
else
25432591
strcpy(s, months[tm->tm_mon - 1]);
25442592
s += strlen(s);
@@ -2548,7 +2596,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25482596
if (!tm->tm_mon)
25492597
break;
25502598
if (S_TM(n->suffix))
2551-
strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2599+
{
2600+
char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2601+
2602+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2603+
strcpy(s, str);
2604+
else
2605+
ereport(ERROR,
2606+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2607+
errmsg("localized string format value too long")));
2608+
}
25522609
else
25532610
strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
25542611
s += strlen(s);
@@ -2562,7 +2619,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25622619
case DCH_DAY:
25632620
INVALID_FOR_INTERVAL;
25642621
if (S_TM(n->suffix))
2565-
strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
2622+
{
2623+
char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
2624+
2625+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2626+
strcpy(s, str);
2627+
else
2628+
ereport(ERROR,
2629+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2630+
errmsg("localized string format value too long")));
2631+
}
25662632
else
25672633
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25682634
asc_toupper_z(days[tm->tm_wday]));
@@ -2571,7 +2637,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25712637
case DCH_Day:
25722638
INVALID_FOR_INTERVAL;
25732639
if (S_TM(n->suffix))
2574-
strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
2640+
{
2641+
char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
2642+
2643+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2644+
strcpy(s, str);
2645+
else
2646+
ereport(ERROR,
2647+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2648+
errmsg("localized string format value too long")));
2649+
}
25752650
else
25762651
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25772652
days[tm->tm_wday]);
@@ -2580,7 +2655,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25802655
case DCH_day:
25812656
INVALID_FOR_INTERVAL;
25822657
if (S_TM(n->suffix))
2583-
strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
2658+
{
2659+
char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
2660+
2661+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2662+
strcpy(s, str);
2663+
else
2664+
ereport(ERROR,
2665+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2666+
errmsg("localized string format value too long")));
2667+
}
25842668
else
25852669
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25862670
asc_tolower_z(days[tm->tm_wday]));
@@ -2589,23 +2673,50 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25892673
case DCH_DY:
25902674
INVALID_FOR_INTERVAL;
25912675
if (S_TM(n->suffix))
2592-
strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
2676+
{
2677+
char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
2678+
2679+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2680+
strcpy(s, str);
2681+
else
2682+
ereport(ERROR,
2683+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2684+
errmsg("localized string format value too long")));
2685+
}
25932686
else
25942687
strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
25952688
s += strlen(s);
25962689
break;
25972690
case DCH_Dy:
25982691
INVALID_FOR_INTERVAL;
25992692
if (S_TM(n->suffix))
2600-
strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
2693+
{
2694+
char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
2695+
2696+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2697+
strcpy(s, str);
2698+
else
2699+
ereport(ERROR,
2700+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2701+
errmsg("localized string format value too long")));
2702+
}
26012703
else
26022704
strcpy(s, days_short[tm->tm_wday]);
26032705
s += strlen(s);
26042706
break;
26052707
case DCH_dy:
26062708
INVALID_FOR_INTERVAL;
26072709
if (S_TM(n->suffix))
2608-
strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
2710+
{
2711+
char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
2712+
2713+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2714+
strcpy(s, str);
2715+
else
2716+
ereport(ERROR,
2717+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2718+
errmsg("localized string format value too long")));
2719+
}
26092720
else
26102721
strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
26112722
s += strlen(s);

0 commit comments

Comments
 (0)