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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy