8000 to_char(): prevent writing beyond the allocated buffer · garyhuntddn/postgres@fe25269 · GitHub
[go: up one dir, main page]

Skip to content

Commit fe25269

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 b8b5801 commit fe25269

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
*
@@ -2532,7 +2535,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25322535
if (!tm->tm_mon)
25332536
break;
25342537
if (S_TM(n->suffix))
2535-
strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
2538+
{
2539+
char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
2540+
2541+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2542+
strcpy(s, str);
2543+
else
2544+
ereport(ERROR,
2545+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2546+
errmsg("localized string format value too long")));
2547+
}
25362548
else
25372549
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25382550
asc_toupper_z(months_full[tm->tm_mon - 1]));
@@ -2543,7 +2555,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25432555
if (!tm->tm_mon)
25442556
break;
25452557
if (S_TM(n->suffix))
2546-
strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
2558+
{
2559+
char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
2560+
2561+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2562+
strcpy(s, str);
2563+
else
2564+
ereport(ERROR,
2565+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2566+
errmsg("localized string format value too long")));
2567+
}
25472568
else
25482569
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25492570
months_full[tm->tm_mon - 1]);
@@ -2554,7 +2575,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25542575
if (!tm->tm_mon)
25552576
break;
25562577
if (S_TM(n->suffix))
2557-
strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
2578+
{
2579+
char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
2580+
2581+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2582+
strcpy(s, str);
2583+
else
2584+
ereport(ERROR,
2585+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2586+
errmsg("localized string format value too long")));
2587+
}
25582588
else
25592589
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
25602590
asc_tolower_z(months_full[tm->tm_mon - 1]));
@@ -2565,7 +2595,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25652595
if (!tm->tm_mon)
25662596
break;
25672597
if (S_TM(n->suffix))
2568-
strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2598+
{
2599+
char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2600+
2601+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2602+
strcpy(s, str);
2603+
else
2604+
ereport(ERROR,
2605+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2606+
errmsg("localized string format value too long")));
2607+
}
25692608
else
25702609
strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
25712610
s += strlen(s);
@@ -2575,7 +2614,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25752614
if (!tm->tm_mon)
25762615
break;
25772616
if (S_TM(n->suffix))
2578-
strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2617+
{
2618+
char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2619+
2620+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2621+
strcpy(s, str);
2622+
else
2623+
ereport(ERROR,
2624+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2625+
errmsg("localized string format value too long")));
2626+
}
25792627
else
25802628
strcpy(s, months[tm->tm_mon - 1]);
25812629
s += strlen(s);
@@ -2585,7 +2633,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25852633
if (!tm->tm_mon)
25862634
break;
25872635
if (S_TM(n->suffix))
2588-
strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2636+
{
2637+
char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2638+
2639+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2640+
strcpy(s, str);
2641+
else
2642+
ereport(ERROR,
2643+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2644+
errmsg("localized string format value too long")));
2645+
}
25892646
else
25902647
strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
25912648
s += strlen(s);
@@ -2599,7 +2656,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
25992656
case DCH_DAY:
26002657
INVALID_FOR_INTERVAL;
26012658
if (S_TM(n->suffix))
2602-
strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
2659+
{
2660+
char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
2661+
2662+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2663+
strcpy(s, str);
2664+
else
2665+
ereport(ERROR,
2666+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2667+
errmsg("localized string format value too long")));
2668+
}
26032669
else
26042670
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
26052671
asc_toupper_z(days[tm->tm_wday]));
@@ -2608,7 +2674,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26082674
case DCH_Day:
26092675
INVALID_FOR_INTERVAL;
26102676
if (S_TM(n->suffix))
2611-
strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
2677+
{
2678+
char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
2679+
2680+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2681+
strcpy(s, str);
2682+
else
2683+
ereport(ERROR,
2684+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2685+
errmsg("localized string format value too long")));
2686+
}
26122687
else
26132688
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
26142689
days[tm->tm_wday]);
@@ -2617,7 +2692,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26172692
case DCH_day:
26182693
INVALID_FOR_INTERVAL;
26192694
if (S_TM(n->suffix))
2620-
strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
2695+
{
2696+
char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
2697+
2698+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2699+
strcpy(s, str);
2700+
else
2701+
ereport(ERROR,
2702+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2703+
errmsg("localized string format value too long")));
2704+
}
26212705
else
26222706
sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
26232707
asc_tolower_z(days[tm->tm_wday]));
@@ -2626,23 +2710,50 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26262710
case DCH_DY:
26272711
INVALID_FOR_INTERVAL;
26282712
if (S_TM(n->suffix))
2629-
strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
2713+
{
2714+
char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
2715+
2716+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2717+
strcpy(s, str);
2718+
else
2719+
ereport(ERROR,
2720+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2721+
errmsg("localized string format value too long")));
2722+
}
26302723
else
26312724
strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
26322725
s += strlen(s);
26332726
break;
26342727
case DCH_Dy:
26352728
INVALID_FOR_INTERVAL;
26362729
if (S_TM(n->suffix))
2637-
strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
2730+
{
2731+
char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
2732+
2733+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2734+
strcpy(s, str);
2735+
else
2736+
ereport(ERROR,
2737+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2738+
errmsg("localized string format value too long")));
2739+
}
26382740
else
26392741
strcpy(s, days_short[tm->tm_wday]);
26402742
s += strlen(s);
26412743
break;
26422744
case DCH_dy:
26432745
INVALID_FOR_INTERVAL;
26442746
if (S_TM(n->suffix))
2645-
strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
2747+
{
2748+
char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
2749+
2750+
if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2751+
strcpy(s, str);
2752+
else
2753+
ereport(ERROR,
2754+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2755+
errmsg("localized string format value too long")));
2756+
}
26462757
else
26472758
strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
26482759
s += strlen(s);

0 commit comments

Comments
 (0)
0