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

Skip to content
  • Commit 9241c84

    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 0150ab5 commit 9241c84

    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
    /* ----------
    @@ -518,10 +518,12 @@ do { \
    518518
    * Suffixes definition for DATE-TIME TO/FROM CHAR
    519519
    * ----------
    520520
    */
    521+
    #define TM_SUFFIX_LEN 2
    522+
    521523
    static const KeySuffix DCH_suff[] = {
    522524
    {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
    523525
    {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
    524-
    {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
    526+
    {"TM", TM_SUFFIX_LEN, DCH_S_TM, SUFFTYPE_PREFIX},
    525527
    {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
    526528
    {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
    527529
    {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
    @@ -530,6 +532,7 @@ static const KeySuffix DCH_suff[] = {
    530532
    {NULL, 0, 0, 0}
    531533
    };
    532534

    535+
    533536
    /* ----------
    534537
    * Format-pictures (KeyWord).
    535538
    *
    @@ -2537,7 +2540,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25372540
    if (!tm->tm_mon)
    25382541
    break;
    25392542
    if (S_TM(n->suffix))
    2540-
    strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
    2543+
    {
    2544+
    char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
    2545+
    2546+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2547+
    strcpy(s, str);
    2548+
    else
    2549+
    ereport(ERROR,
    2550+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2551+
    errmsg("localized string format value too long")));
    2552+
    }
    25412553
    else
    25422554
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    25432555
    asc_toupper_z(months_full[tm->tm_mon - 1]));
    @@ -2548,7 +2560,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25482560
    if (!tm->tm_mon)
    25492561
    break;
    25502562
    if (S_TM(n->suffix))
    2551-
    strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
    2563+
    {
    2564+
    char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
    2565+
    2566+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2567+
    strcpy(s, str);
    2568+
    else
    2569+
    ereport(ERROR,
    2570+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2571+
    errmsg("localized string format value too long")));
    2572+
    }
    25522573
    else
    25532574
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    25542575
    months_full[tm->tm_mon - 1]);
    @@ -2559,7 +2580,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25592580
    if (!tm->tm_mon)
    25602581
    break;
    25612582
    if (S_TM(n->suffix))
    2562-
    strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
    2583+
    {
    2584+
    char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
    2585+
    2586+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2587+
    strcpy(s, str);
    2588+
    else
    2589+
    ereport(ERROR,
    2590+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2591+
    errmsg("localized string format value too long")));
    2592+
    }
    25632593
    else
    25642594
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    25652595
    asc_tolower_z(months_full[tm->tm_mon - 1]));
    @@ -2570,7 +2600,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25702600
    if (!tm->tm_mon)
    25712601
    break;
    25722602
    if (S_TM(n->suffix))
    2573-
    strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
    2603+
    {
    2604+
    char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
    2605+
    2606+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2607+
    strcpy(s, str);
    2608+
    else
    2609+
    ereport(ERROR,
    2610+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2611+
    errmsg("localized string format value too long")));
    2612+
    }
    25742613
    else
    25752614
    strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
    25762615
    s += strlen(s);
    @@ -2580,7 +2619,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25802619
    if (!tm->tm_mon)
    25812620
    break;
    25822621
    if (S_TM(n->suffix))
    2583-
    strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
    2622+
    {
    2623+
    char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], 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+
    }
    25842632
    else
    25852633
    strcpy(s, months[tm->tm_mon - 1]);
    25862634
    s += strlen(s);
    @@ -2590,7 +2638,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    25902638
    if (!tm->tm_mon)
    25912639
    break;
    25922640
    if (S_TM(n->suffix))
    2593-
    strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
    2641+
    {
    2642+
    char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
    2643+
    2644+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2645+
    strcpy(s, str);
    2646+
    else
    2647+
    ereport(ERROR,
    2648+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2649+
    errmsg("localized string format value too long")));
    2650+
    }
    25942651
    else
    25952652
    strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
    25962653
    s += strlen(s);
    @@ -2604,7 +2661,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    26042661
    case DCH_DAY:
    26052662
    INVALID_FOR_INTERVAL;
    26062663
    if (S_TM(n->suffix))
    2607-
    strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
    2664+
    {
    2665+
    char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
    2666+
    2667+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2668+
    strcpy(s, str);
    2669+
    else
    2670+
    ereport(ERROR,
    2671+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2672+
    errmsg("localized string format value too long")));
    2673+
    }
    26082674
    else
    26092675
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    26102676
    asc_toupper_z(days[tm->tm_wday]));
    @@ -2613,7 +2679,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    26132679
    case DCH_Day:
    26142680
    INVALID_FOR_INTERVAL;
    26152681
    if (S_TM(n->suffix))
    2616-
    strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
    2682+
    {
    2683+
    char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
    2684+
    2685+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2686+
    strcpy(s, str);
    2687+
    else
    2688+
    ereport(ERROR,
    2689+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2690+
    errmsg("localized string format value too long")));
    2691+
    }
    26172692
    else
    26182693
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    26192694
    days[tm->tm_wday]);
    @@ -2622,7 +2697,16 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    26222697
    case DCH_day:
    26232698
    INVALID_FOR_INTERVAL;
    26242699
    if (S_TM(n->suffix))
    2625-
    strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
    2700+
    {
    2701+
    char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
    2702+
    2703+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2704+
    strcpy(s, str);
    2705+
    else
    2706+
    ereport(ERROR,
    2707+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2708+
    errmsg("localized string format value too long")));
    2709+
    }
    26262710
    else
    26272711
    sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
    26282712
    asc_tolower_z(days[tm->tm_wday]));
    @@ -2631,23 +2715,50 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
    26312715
    case DCH_DY:
    26322716
    INVALID_FOR_INTERVAL;
    26332717
    if (S_TM(n->suffix))
    2634-
    strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
    2718+
    {
    2719+
    char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
    2720+
    2721+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2722+
    strcpy(s, str);
    2723+
    else
    2724+
    ereport(ERROR,
    2725+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2726+
    errmsg("localized string format value too long")));
    2727+
    }
    26352728
    else
    26362729
    strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
    26372730
    s += strlen(s);
    26382731
    break;
    26392732
    case DCH_Dy:
    26402733
    INVALID_FOR_INTERVAL;
    26412734
    if (S_TM(n->suffix))
    2642-
    strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
    2735+
    {
    2736+
    char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
    2737+
    2738+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2739+
    strcpy(s, str);
    2740+
    else
    2741+
    ereport(ERROR,
    2742+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2743+
    errmsg("localized string format value too long")));
    2744+
    }
    26432745
    else
    26442746
    strcpy(s, days_short[tm->tm_wday]);
    26452747
    s += strlen(s);
    26462748
    break;
    26472749
    case DCH_dy:
    26482750
    INVALID_FOR_INTERVAL;
    26492751
    if (S_TM(n->suffix))
    2650-
    strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
    2752+
    {
    2753+
    char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
    2754+
    2755+
    if (strlen(str) < (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2756+
    strcpy(s, str);
    2757+
    else
    2758+
    ereport(ERROR,
    2759+
    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2760+
    errmsg("localized string format value too long")));
    2761+
    }
    26512762
    else
    26522763
    strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
    26532764
    s += strlen(s);

    0 commit comments

    Comments
     (0)
    0