Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6faf795

Browse files
committed
Fix a passel of ancient bugs in to_char(), including two distinct buffer
overruns (neither of which seem likely to be exploitable as security holes, fortunately, since the provoker can't control the data written). One of these is due to choosing to stomp on the output of a called function, which is bad news in any case; make it treat the called functions' results as read-only. Avoid some unnecessary palloc/pfree traffic too; it's not really helpful to free small temporary objects, and again this is presuming more than it ought to about the nature of the results of called functions. Per report from Patrick Welche and additional code-reading by Imad.
1 parent 700eabb commit 6faf795

File tree

1 file changed

+56
-94
lines changed

1 file changed

+56
-94
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 56 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.129 2007/02/27 23:48:08 tgl Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.130 2007/06/29 01:51:35 tgl Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
@@ -74,6 +74,7 @@
7474
#include <unistd.h>
7575
#include <math.h>
7676
#include <float.h>
77+
#include <limits.h>
7778
#include <locale.h>
7879

7980
#include "utils/builtins.h"
@@ -112,8 +113,8 @@
112113
* More is in float.c
113114
* ----------
114115
*/
115-
#define MAXFLOATWIDTH 64
116-
#define MAXDOUBLEWIDTH 128
116+
#define MAXFLOATWIDTH 60
117+
#define MAXDOUBLEWIDTH 500
117118

118119

119120
/* ----------
@@ -958,13 +959,12 @@ static char *localize_month(int index);
958959
static char *localize_day_full(int index);
959960
static char *localize_day(int index);
960961

961-
/*
962-
* External (defined in oracle_compat.c
963-
*/
964962
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
965963
#define USE_WIDE_UPPER_LOWER
964+
/* externs are in oracle_compat.c */
966965
extern char *wstring_upper(char *str);
967966
extern char *wstring_lower(char *str);
967+
968968
static char *localized_str_toupper(char *buff);
969969
static char *localized_str_tolower(char *buff);
970970
#else
@@ -1510,7 +1510,7 @@ str_numth(char *dest, char *num, int type)
15101510
}
15111511

15121512
/* ----------
1513-
* Convert string to upper-string. Input string is modified in place.
1513+
* Convert string to upper case. Input string is modified in place.
15141514
* ----------
15151515
*/
15161516
static char *
@@ -1531,7 +1531,7 @@ str_toupper(char *buff)
15311531
}
15321532

15331533
/* ----------
1534-
* Convert string to lower-string. Input string is modified in place.
1534+
* Convert string to lower case. Input string is modified in place.
15351535
* ----------
15361536
*/
15371537
static char *
@@ -1553,7 +1553,8 @@ str_tolower(char *buff)
15531553

15541554
#ifdef USE_WIDE_UPPER_LOWER
15551555
/* ----------
1556-
* Convert localized string to upper string. Input string is modified in place.
1556+
* Convert localized string to upper case.
1557+
* Input string may be modified in place ... or we might make a copy.
15571558
* ----------
15581559
*/
15591560
static char *
@@ -1579,7 +1580,8 @@ localized_str_toupper(char *buff)
15791580
}
15801581

15811582
/* ----------
1582-
* Convert localized string to upper string. Input string is modified in place.
1583+
* Convert localized string to lower case.
1584+
* Input string may be modified in place ... or we might make a copy.
15831585
* ----------
15841586
*/
15851587
static char *
@@ -2107,19 +2109,16 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
21072109
INVALID_FOR_INTERVAL;
21082110
if (is_to_char && tmtcTzn(tmtc))
21092111
{
2110-
int siz = strlen(tmtcTzn(tmtc));
2111-
21122112
if (arg == DCH_TZ)
21132113
strcpy(inout, tmtcTzn(tmtc));
21142114
else
21152115
{
2116-
char *p = palloc(siz);
2116+
char *p = pstrdup(tmtcTzn(tmtc));
21172117

2118-
strcpy(p, tmtcTzn(tmtc));
21192118
strcpy(inout, str_tolower(p));
21202119
pfree(p);
21212120
}
2122-
return siz;
2121+
return strlen(inout);
21232122
}
21242123
else if (!is_to_char)
21252124
ereport(ERROR,
@@ -3624,7 +3623,7 @@ static char *
36243623
fill_str(char *str, int c, int max)
36253624
{
36263625
memset(str, c, max);
3627-
*(str + max + 1) = '\0';
3626+
*(str + max) = '\0';
36283627
return str;
36293628
}
36303629

@@ -4798,10 +4797,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
47984797
#define NUM_TOCHAR_prepare \
47994798
do { \
48004799
len = VARSIZE(fmt) - VARHDRSZ; \
4801-
if (len <= 0) \
4800+
if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
48024801
return DirectFunctionCall1(textin, CStringGetDatum("")); \
4803-
result = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
4804-
memset(result, 0, (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
4802+
result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
48054803
format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree); \
48064804
} while (0)
48074805

@@ -4811,30 +4809,19 @@ do { \
48114809
*/
48124810
#define NUM_TOCHAR_finish \
48134811
do { \
4814-
NUM_processor(format, &Num, VARDATA(result), \
4815-
numstr, plen, sign, true); \
4816-
pfree(orgnum); \
4812+
NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true); \
48174813
\
4818-
if (shouldFree) \
4819-
pfree(format); \
4814+
if (shouldFree) \
4815+
pfree(format); \
48204816
\
4821-
/*
4822-
* for result is allocated max memory, which current format-picture\
4823-
* needs, now it must be re-allocate to result real size \
4817+
/* \
4818+
* Convert null-terminated representation of result to standard text. \
4819+
* The result is usually much bigger than it needs to be, but there \
4820+
* seems little point in realloc'ing it smaller. \
48244821
*/ \
4825-
if (!(len = strlen(VARDATA(result)))) \
4826-
{ \
4827-
pfree(result); \
4828-
PG_RETURN_NULL(); \
4829-
} \
4830-
\
4831-
result_tmp = result; \
4832-
result = (text *) palloc(len + VARHDRSZ); \
4833-
\
4834-
memcpy(VARDATA(result), VARDATA(result_tmp), len); \
4835-
SET_VARSIZE(result, len + VARHDRSZ); \
4836-
pfree(result_tmp); \
4837-
} while(0)
4822+
len = strlen(VARDATA(result)); \
4823+
SET_VARSIZE(result, len + VARHDRSZ); \
4824+
} while (0)
48384825

48394826
/* -------------------
48404827
* NUMERIC to_number() (convert string to numeric)
@@ -4856,7 +4843,7 @@ numeric_to_number(PG_FUNCTION_ARGS)
48564843

48574844
len = VARSIZE(fmt) - VARHDRSZ;
48584845

4859-
if (len <= 0)
4846+
if (len <= 0 || len >= INT_MAX/NUM_MAX_ITEM_SIZ)
48604847
PG_RETURN_NULL();
48614848

48624849
format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);
@@ -4891,8 +4878,7 @@ numeric_to_char(PG_FUNCTION_ARGS)
48914878
text *fmt = PG_GETARG_TEXT_P(1);
48924879
NUMDesc Num;
48934880
FormatNode *format;
4894-
text *result,
4895-
*result_tmp;
4881+
text *result;
48964882
bool shouldFree;
48974883
int len = 0,
48984884
plen = 0,
@@ -4915,7 +4901,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
49154901
numstr = orgnum =
49164902
int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
49174903
NumericGetDatum(x))));
4918-
pfree(x);
49194904
}
49204905
else
49214906
{
@@ -4934,9 +4919,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
49344919
val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
49354920
NumericGetDatum(value),
49364921
NumericGetDatum(x)));
4937-
pfree(x);
4938-
pfree(a);
4939-
pfree(b);
49404922
Num.pre += Num.multi;
49414923
}
49424924

@@ -4945,10 +4927,9 @@ numeric_to_char(PG_FUNCTION_ARGS)
49454927
Int32GetDatum(Num.post)));
49464928
orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
49474929
NumericGetDatum(x)));
4948-
pfree(x);
49494930

49504931
if (*orgnum == '-')
4951-
{ /* < 0 */
4932+
{
49524933
sign = '-';
49534934
numstr = orgnum + 1;
49544935
}
@@ -4966,13 +4947,10 @@ numeric_to_char(PG_FUNCTION_ARGS)
49664947
plen = Num.pre - len;
49674948
else if (len > Num.pre)
49684949
{
4969-
fill_str(numstr, '#', Num.pre);
4950+
numstr = (char *) palloc(Num.pre + Num.post + 2);
4951+
fill_str(numstr, '#', Num.pre + Num.post + 1);
49704952
*(numstr + Num.pre) = '.';
4971-
fill_str(numstr + 1 + Num.pre, '#', Num.post);
49724953
}
4973-
4974-
if (IS_MULTI(&Num))
4975-
pfree(val);
49764954
}
49774955

49784956
NUM_TOCHAR_finish;
@@ -4990,8 +4968,7 @@ int4_to_char(PG_FUNCTION_ARGS)
49904968
text *fmt = PG_GETARG_TEXT_P(1);
49914969
NUMDesc Num;
49924970
FormatNode *format;
4993-
text *result,
4994-
*result_tmp;
4971+
text *result;
49954972
bool shouldFree;
49964973
int len = 0,
49974974
plen = 0,
@@ -5019,40 +4996,34 @@ int4_to_char(PG_FUNCTION_ARGS)
50194996
orgnum = DatumGetCString(DirectFunctionCall1(int4out,
50204997
Int32GetDatum(value)));
50214998
}
5022-
len = strlen(orgnum);
50234999

50245000
if (*orgnum == '-')
5025-
{ /* < 0 */
5001+
{
50265002
sign = '-';
5027-
--len;
5003+
orgnum++;
50285004
}
50295005
else
50305006
sign = '+';
5007+
len = strlen(orgnum);
50315008

50325009
if (Num.post)
50335010
{
5034-
int i;
5035-
50365011
numstr = (char *) palloc(len + Num.post + 2);
5037-
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
5012+
strcpy(numstr, orgnum);
50385013
*(numstr + len) = '.';
5039-
5040-
for (i = len + 1; i <= len + Num.post; i++)
5041-
*(numstr + i) = '0';
5014+
memset(numstr + len + 1, '0', Num.post);
50425015
*(numstr + len + Num.post + 1) = '\0';
5043-
pfree(orgnum);
5044-
orgnum = numstr;
50455016
}
50465017
else
5047-
numstr = orgnum + (*orgnum == '-' ? 1 : 0);
5018+
numstr = orgnum;
50485019

50495020
if (Num.pre > len)
50505021
plen = Num.pre - len;
50515022
else if (len > Num.pre)
50525023
{
5053-
fill_str(numstr, '#', Num.pre);
5024+
numstr = (char *) palloc(Num.pre + Num.post + 2);
5025+
fill_str(numstr, '#', Num.pre + Num.post + 1);
50545026
*(numstr + Num.pre) = '.';
5055-
fill_str(numstr + 1 + Num.pre, '#', Num.post);
50565027
}
50575028
}
50585029

@@ -5071,8 +5042,7 @@ int8_to_char(PG_FUNCTION_ARGS)
50715042
text *fmt = PG_GETARG_TEXT_P(1);
50725043
NUMDesc Num;
50735044
FormatNode *format;
5074-
text *result,
5075-
*result_tmp;
5045+
text *result;
50765046
bool shouldFree;
50775047
int len = 0,
50785048
plen = 0,
@@ -5106,40 +5076,34 @@ int8_to_char(PG_FUNCTION_ARGS)
51065076

51075077
orgnum = DatumGetCString(DirectFunctionCall1(int8out,
51085078
Int64GetDatum(value)));
5109-
len = strlen(orgnum);
51105079

51115080
if (*orgnum == '-')
5112-
{ /* < 0 */
5081+
{
51135082
sign = '-';
5114-
--len;
5083+
orgnum++;
51155084
}
51165085
else
51175086
sign = '+';
5087+
len = strlen(orgnum);
51185088

51195089
if (Num.post)
51205090
{
5121-
int i;
5122-
51235091
numstr = (char *) palloc(len + Num.post + 2);
5124-
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
5092+
strcpy(numstr, orgnum);
51255093
*(numstr + len) = '.';
5126-
5127-
for (i = len + 1; i <= len + Num.post; i++)
5128-
*(numstr + i) = '0';
5094+
memset(numstr + len + 1, '0', Num.post);
51295095
*(numstr + len + Num.post + 1) = '\0';
5130-
pfree(orgnum);
5131-
orgnum = numstr;
51325096
}
51335097
else
5134-
numstr = orgnum + (*orgnum == '-' ? 1 : 0);
5098+
numstr = orgnum;
51355099

51365100
if (Num.pre > len)
51375101
plen = Num.pre - len;
51385102
else if (len > Num.pre)
51395103
{
5140-
fill_str(numstr, '#', Num.pre);
5104+
numstr = (char *) palloc(Num.pre + Num.post + 2);
5105+
fill_str(numstr, '#', Num.pre + Num.post + 1);
51415106
*(numstr + Num.pre) = '.';
5142-
fill_str(numstr + 1 + Num.pre, '#', Num.post);
51435107
}
51445108
}
51455109

@@ -5158,8 +5122,7 @@ float4_to_char(PG_FUNCTION_ARGS)
51585122
text *fmt = PG_GETARG_TEXT_P(1);
51595123
NUMDesc Num;
51605124
FormatNode *format;
5161-
text *result,
5162-
*result_tmp;
5125+
text *result;
51635126
bool shouldFree;
51645127
int len = 0,
51655128
plen = 0,
@@ -5214,9 +5177,9 @@ float4_to_char(PG_FUNCTION_ARGS)
52145177
plen = Num.pre - len;
52155178
else if (len > Num.pre)
52165179
{
5217-
fill_str(numstr, '#', Num.pre);
5180+
numstr = (char *) palloc(Num.pre + Num.post + 2);
5181+
fill_str(numstr, '#', Num.pre + Num.post + 1);
52185182
*(numstr + Num.pre) = '.';
5219-
fill_str(numstr + 1 + Num.pre, '#', Num.post);
52205183
}
52215184
}
52225185

@@ -5235,8 +5198,7 @@ float8_to_char(PG_FUNCTION_ARGS)
52355198
text *fmt = PG_GETARG_TEXT_P(1);
52365199
NUMDesc Num;
52375200
FormatNode *format;
5238-
text *result,
5239-
*result_tmp;
5201+
text *result;
52405202
bool shouldFree;
52415203
int len = 0,
52425204
plen = 0,
@@ -5289,9 +5251,9 @@ float8_to_char(PG_FUNCTION_ARGS)
52895251
plen = Num.pre - len;
52905252
else if (len > Num.pre)
52915253
{
5292-
fill_str(numstr, '#', Num.pre);
5254+
numstr = (char *) palloc(Num.pre + Num.post + 2);
5255+
fill_str(numstr, '#', Num.pre + Num.post + 1);
52935256
*(numstr + Num.pre) = '.';
5294-
fill_str(numstr + 1 + Num.pre, '#', Num.post);
52955257
}
52965258
}
52975259

0 commit comments

Comments
 (0)