Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb9c3bb1

Browse files
committed
Fix handling of wide datetime input/output.
Many server functions use the MAXDATELEN constant to size a buffer forparsing or displaying a datetime value. It was much too small for thelongest possible interval output and slightly too small for certainvalid timestamp input, particularly input with a long timezone name.The long input was rejected needlessly; the long output causedinterval_out() to overrun its buffer. ECPG's pgtypes library has a copyof the vulnerable functions, which bore the same vulnerabilities alongwith some of its own. In contrast to the server, certain long inputscaused stack overflow rather than failing cleanly. Back-patch to 8.4(all supported versions).Reported by Daniel Schüssler, reviewed by Tom Lane.Security:CVE-2014-0063
1 parent43d4e96 commitb9c3bb1

File tree

11 files changed

+111
-35
lines changed

11 files changed

+111
-35
lines changed

‎src/include/utils/datetime.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,17 @@
188188
#defineDTK_DATE_M(DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
189189
#defineDTK_TIME_M(DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M)
190190

191-
#defineMAXDATELEN63/* maximum possible length of an input date
192-
* string (not counting tr. null) */
193-
#defineMAXDATEFIELDS25/* maximum possible number of fields in a date
194-
* string */
195-
#defineTOKMAXLEN10/* only this many chars are stored in
196-
* datetktbl */
191+
/*
192+
* Working buffer size for input and output of interval, timestamp, etc.
193+
* Inputs that need more working space will be rejected early. Longer outputs
194+
* will overrun buffers, so this must suffice for all possible output. As of
195+
* this writing, interval_out() needs the most space at ~90 bytes.
196+
*/
197+
#defineMAXDATELEN128
198+
/* maximum possible number of fields in a date string */
199+
#defineMAXDATEFIELDS25
200+
/* only this many chars are stored in datetktbl */
201+
#defineTOKMAXLEN10
197202

198203
/* keep this struct small; it gets used a lot */
199204
typedefstruct

‎src/interfaces/ecpg/pgtypeslib/datetime.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ PGTYPESdate_from_asc(char *str, char **endptr)
6161
intnf;
6262
char*field[MAXDATEFIELDS];
6363
intftype[MAXDATEFIELDS];
64-
charlowstr[MAXDATELEN+1];
64+
charlowstr[MAXDATELEN+MAXDATEFIELDS];
6565
char*realptr;
6666
char**ptr= (endptr!=NULL) ?endptr :&realptr;
6767

6868
boolEuroDates= FALSE;
6969

7070
errno=0;
71-
if (strlen(str) >=sizeof(lowstr))
71+
if (strlen(str)>MAXDATELEN)
7272
{
7373
errno=PGTYPES_DATE_BAD_DATE;
7474
returnINT_MIN;

‎src/interfaces/ecpg/pgtypeslib/dt.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,17 @@ typedef double fsec_t;
192192
#defineDTK_DATE_M(DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
193193
#defineDTK_TIME_M(DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
194194

195-
#defineMAXDATELEN63/* maximum possible length of an input date
196-
* string (not counting tr. null) */
197-
#defineMAXDATEFIELDS25/* maximum possible number of fields in a date
198-
* string */
199-
#defineTOKMAXLEN10/* only this many chars are stored in
200-
* datetktbl */
195+
/*
196+
* Working buffer size for input and output of interval, timestamp, etc.
197+
* Inputs that need more working space will be rejected early. Longer outputs
198+
* will overrun buffers, so this must suffice for all possible output. As of
199+
* this writing, PGTYPESinterval_to_asc() needs the most space at ~90 bytes.
200+
*/
201+
#defineMAXDATELEN128
202+
/* maximum possible number of fields in a date string */
203+
#defineMAXDATEFIELDS25
204+
/* only this many chars are stored in datetktbl */
205+
#defineTOKMAXLEN10
201206

202207
/* keep this struct small; it gets used a lot */
203208
typedefstruct

‎src/interfaces/ecpg/pgtypeslib/dt_common.c

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,15 +1161,22 @@ DecodeNumberField(int len, char *str, int fmask,
11611161
if ((cp=strchr(str,'.'))!=NULL)
11621162
{
11631163
#ifdefHAVE_INT64_TIMESTAMP
1164-
charfstr[MAXDATELEN+1];
1164+
charfstr[7];
1165+
inti;
1166+
1167+
cp++;
11651168

11661169
/*
11671170
* OK, we have at most six digits to care about. Let's construct a
1168-
* string and then do the conversion to an integer.
1171+
* string with those digits, zero-padded on the right, and then do
1172+
* the conversion to an integer.
1173+
*
1174+
* XXX This truncates the seventh digit, unlike rounding it as do
1175+
* the backend and the !HAVE_INT64_TIMESTAMP case.
11691176
*/
1170-
strcpy(fstr, (cp+1));
1171-
strcpy(fstr+strlen(fstr),"000000");
1172-
*(fstr+6)='\0';
1177+
for (i=0;i<6;i++)
1178+
fstr[i]=*cp!='\0' ?*cp++ :'0';
1179+
fstr[i]='\0';
11731180
*fsec=strtol(fstr,NULL,10);
11741181
#else
11751182
*fsec=strtod(cp,NULL);
@@ -1521,15 +1528,22 @@ DecodeTime(char *str, int *tmask, struct tm * tm, fsec_t *fsec)
15211528
elseif (*cp=='.')
15221529
{
15231530
#ifdefHAVE_INT64_TIMESTAMP
1524-
charfstr[MAXDATELEN+1];
1531+
charfstr[7];
1532+
inti;
1533+
1534+
cp++;
15251535

15261536
/*
1527-
* OK, we have at most six digits to work with. Let's construct a
1528-
* string and then do the conversion to an integer.
1537+
* OK, we have at most six digits to care about. Let's construct a
1538+
* string with those digits, zero-padded on the right, and then do
1539+
* the conversion to an integer.
1540+
*
1541+
* XXX This truncates the seventh digit, unlike rounding it as do
1542+
* the backend and the !HAVE_INT64_TIMESTAMP case.
15291543
*/
1530-
strncpy(fstr, (cp+1),7);
1531-
strcpy(fstr+strlen(fstr),"000000");
1532-
*(fstr+6)='\0';
1544+
for (i=0;i<6;i++)
1545+
fstr[i]=*cp!='\0' ?*cp++ :'0';
1546+
fstr[i]='\0';
15331547
*fsec=strtol(fstr,&cp,10);
15341548
#else
15351549
str=cp;
@@ -1655,6 +1669,9 @@ DecodePosixTimezone(char *str, int *tzp)
16551669
*DTK_NUMBER can hold date fields (yy.ddd)
16561670
*DTK_STRING can hold months (January) and time zones (PST)
16571671
*DTK_DATE can hold Posix time zones (GMT-8)
1672+
*
1673+
* The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
1674+
* bytes of space. On output, field[] entries will point into it.
16581675
*/
16591676
int
16601677
ParseDateTime(char*timestr,char*lowstr,
@@ -1667,7 +1684,10 @@ ParseDateTime(char *timestr, char *lowstr,
16671684
/* outer loop through fields */
16681685
while (*(*endstr)!='\0')
16691686
{
1687+
/* Record start of current field */
16701688
field[nf]=lp;
1689+
if (nf >=MAXDATEFIELDS)
1690+
return-1;
16711691

16721692
/* leading digit? then date or time */
16731693
if (isdigit((unsignedchar)*(*endstr)))
@@ -1808,8 +1828,6 @@ ParseDateTime(char *timestr, char *lowstr,
18081828
/* force in a delimiter after each field */
18091829
*lp++='\0';
18101830
nf++;
1811-
if (nf>MAXDATEFIELDS)
1812-
return-1;
18131831
}
18141832

18151833
*numfields=nf;

‎src/interfaces/ecpg/pgtypeslib/interval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ PGTYPESinterval_from_asc(char *str, char **endptr)
10921092
tm->tm_sec=0;
10931093
fsec=0;
10941094

1095-
if (strlen(str) >=sizeof(lowstr))
1095+
if (strlen(str)>MAXDATELEN)
10961096
{
10971097
errno=PGTYPES_INTVL_BAD_INTERVAL;
10981098
returnNULL;

‎src/interfaces/ecpg/pgtypeslib/timestamp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ PGTYPEStimestamp_from_asc(char *str, char **endptr)
297297
char*realptr;
298298
char**ptr= (endptr!=NULL) ?endptr :&realptr;
299299

300-
if (strlen(str) >=sizeof(lowstr))
300+
if (strlen(str)>MAXDATELEN)
301301
{
302302
errno=PGTYPES_TS_BAD_TIMESTAMP;
303303
return (noresult);

‎src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,23 @@ char *dates[] = { "19990108foobar",
4545
"1999.008",
4646
"J2451187",
4747
"January 8, 99 BC",
48+
/*
49+
* Maximize space usage in ParseDateTime() with 25
50+
* (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
51+
*/
52+
"........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
53+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
54+
/* 26 fields */
55+
".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
56+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
4857
NULL };
4958

5059
/* do not conflict with libc "times" symbol */
5160
staticchar*times[]= {"0:04",
5261
"1:59 PDT",
5362
"13:24:40 -8:00",
5463
"13:24:40.495+3",
64+
"13:24:40.123456789+3",
5565
NULL };
5666

5767
char*intervals[]= {"1 minute",
@@ -73,22 +83,22 @@ main(void)
7383

7484

7585

76-
#line52 "dt_test2.pgc"
86+
#line62 "dt_test2.pgc"
7787
datedate1 ;
7888

79-
#line53 "dt_test2.pgc"
89+
#line63 "dt_test2.pgc"
8090
timestampts1 ,ts2 ;
8191

82-
#line54 "dt_test2.pgc"
92+
#line64 "dt_test2.pgc"
8393
char*text ;
8494

85-
#line55 "dt_test2.pgc"
95+
#line65 "dt_test2.pgc"
8696
interval*i1 ;
8797

88-
#line56 "dt_test2.pgc"
98+
#line66 "dt_test2.pgc"
8999
date*dc ;
90100
/* exec sql end declare section */
91-
#line57 "dt_test2.pgc"
101+
#line67 "dt_test2.pgc"
92102

93103

94104
inti,j;

‎src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,85 +8,104 @@ TS[3,0]: 1999-01-08 00:04:00
88
TS[3,1]: 1999-01-08 01:59:00
99
TS[3,2]: 1999-01-08 13:24:40
1010
TS[3,3]: 1999-01-08 13:24:40.495
11+
TS[3,4]: 1999-01-08 13:24:40.123456
1112
Date[4]: 1999-01-08 (N - F)
1213
TS[4,0]: 1999-01-08 00:04:00
1314
TS[4,1]: 1999-01-08 01:59:00
1415
TS[4,2]: 1999-01-08 13:24:40
1516
TS[4,3]: 1999-01-08 13:24:40.495
17+
TS[4,4]: 1999-01-08 13:24:40.123456
1618
Date[5]: 1999-01-08 (N - F)
1719
TS[5,0]: 1999-01-08 00:04:00
1820
TS[5,1]: 1999-01-08 01:59:00
1921
TS[5,2]: 1999-01-08 13:24:40
2022
TS[5,3]: 1999-01-08 13:24:40.495
23+
TS[5,4]: 1999-01-08 13:24:40.123456
2124
Date[6]: 1999-01-18 (N - F)
2225
TS[6,0]: 1999-01-18 00:04:00
2326
TS[6,1]: 1999-01-18 01:59:00
2427
TS[6,2]: 1999-01-18 13:24:40
2528
TS[6,3]: 1999-01-18 13:24:40.495
29+
TS[6,4]: 1999-01-18 13:24:40.123456
2630
Date[7]: 2003-01-02 (N - F)
2731
TS[7,0]: 2003-01-02 00:04:00
2832
TS[7,1]: 2003-01-02 01:59:00
2933
TS[7,2]: 2003-01-02 13:24:40
3034
TS[7,3]: 2003-01-02 13:24:40.495
35+
TS[7,4]: 2003-01-02 13:24:40.123456
3136
Date[8]: 1999-01-08 (N - F)
3237
TS[8,0]: 1999-01-08 00:04:00
3338
TS[8,1]: 1999-01-08 01:59:00
3439
TS[8,2]: 1999-01-08 13:24:40
3540
TS[8,3]: 1999-01-08 13:24:40.495
41+
TS[8,4]: 1999-01-08 13:24:40.123456
3642
Date[9]: 1999-01-08 (N - F)
3743
TS[9,0]: 1999-01-08 00:04:00
3844
TS[9,1]: 1999-01-08 01:59:00
3945
TS[9,2]: 1999-01-08 13:24:40
4046
TS[9,3]: 1999-01-08 13:24:40.495
47+
TS[9,4]: 1999-01-08 13:24:40.123456
4148
Date[10]: 1999-01-08 (N - F)
4249
TS[10,0]: 1999-01-08 00:04:00
4350
TS[10,1]: 1999-01-08 01:59:00
4451
TS[10,2]: 1999-01-08 13:24:40
4552
TS[10,3]: 1999-01-08 13:24:40.495
53+
TS[10,4]: 1999-01-08 13:24:40.123456
4654
Date[11]: 1999-01-08 (N - F)
4755
TS[11,0]: 1999-01-08 00:04:00
4856
TS[11,1]: 1999-01-08 01:59:00
4957
TS[11,2]: 1999-01-08 13:24:40
5058
TS[11,3]: 1999-01-08 13:24:40.495
59+
TS[11,4]: 1999-01-08 13:24:40.123456
5160
Date[12]: 1999-01-08 (N - F)
5261
TS[12,0]: 1999-01-08 00:04:00
5362
TS[12,1]: 1999-01-08 01:59:00
5463
TS[12,2]: 1999-01-08 13:24:40
5564
TS[12,3]: 1999-01-08 13:24:40.495
65+
TS[12,4]: 1999-01-08 13:24:40.123456
5666
Date[13]: 2006-01-08 (N - F)
5767
TS[13,0]: 2006-01-08 00:04:00
5868
TS[13,1]: 2006-01-08 01:59:00
5969
TS[13,2]: 2006-01-08 13:24:40
6070
TS[13,3]: 2006-01-08 13:24:40.495
71+
TS[13,4]: 2006-01-08 13:24:40.123456
6172
Date[14]: 1999-01-08 (N - F)
6273
TS[14,0]: 1999-01-08 00:04:00
6374
TS[14,1]: 1999-01-08 01:59:00
6475
TS[14,2]: 1999-01-08 13:24:40
6576
TS[14,3]: 1999-01-08 13:24:40.495
77+
TS[14,4]: 1999-01-08 13:24:40.123456
6678
Date[15]: 1999-01-08 (N - F)
6779
TS[15,0]: 1999-01-08 00:04:00
6880
TS[15,1]: 1999-01-08 01:59:00
6981
TS[15,2]: 1999-01-08 13:24:40
7082
TS[15,3]: 1999-01-08 13:24:40.495
83+
TS[15,4]: 1999-01-08 13:24:40.123456
7184
Date[16]: 1999-01-08 (N - F)
7285
TS[16,0]: 1999-01-08 00:04:00
7386
TS[16,1]: 1999-01-08 01:59:00
7487
TS[16,2]: 1999-01-08 13:24:40
7588
TS[16,3]: 1999-01-08 13:24:40.495
89+
TS[16,4]: 1999-01-08 13:24:40.123456
7690
Date[17]: 1999-01-08 (N - F)
7791
TS[17,0]: 1999-01-08 00:04:00
7892
TS[17,1]: 1999-01-08 01:59:00
7993
TS[17,2]: 1999-01-08 13:24:40
8094
TS[17,3]: 1999-01-08 13:24:40.495
95+
TS[17,4]: 1999-01-08 13:24:40.123456
8196
Date[18]: 1999-01-08 (N - F)
8297
TS[18,0]: 1999-01-08 00:04:00
8398
TS[18,1]: 1999-01-08 01:59:00
8499
TS[18,2]: 1999-01-08 13:24:40
85100
TS[18,3]: 1999-01-08 13:24:40.495
101+
TS[18,4]: 1999-01-08 13:24:40.123456
86102
Date[19]: 0099-01-08 BC (N - F)
87103
TS[19,0]: 0099-01-08 00:04:00 BC
88104
TS[19,1]: 0099-01-08 01:59:00 BC
89105
TS[19,2]: 0099-01-08 13:24:40 BC
106+
TS[19,4]: 0099-01-08 13:24:40.123456 BC
107+
Date[20]: - (N - T)
108+
Date[21]: - (N - T)
90109
interval[0]: @ 1 min
91110
interval_copy[0]: @ 1 min
92111
interval[1]: @ 1 day 12 hours 59 mins 10 secs

‎src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,23 @@ char *dates[] = { "19990108foobar",
2727
"1999.008",
2828
"J2451187",
2929
"January 8, 99 BC",
30+
/*
31+
* Maximize space usage in ParseDateTime() with 25
32+
* (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
33+
*/
34+
"........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
35+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
36+
/* 26 fields */
37+
".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
38+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3039
NULL };
3140

3241
/* do not conflict with libc "times" symbol */
3342
static char *times[] = { "0:04",
3443
"1:59 PDT",
3544
"13:24:40 -8:00",
3645
"13:24:40.495+3",
46+
"13:24:40.123456789+3",
3747
NULL };
3848

3949
char *intervals[] = { "1 minute",

‎src/test/regress/expected/interval.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,13 @@ select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31
306306
@ 4541 years 4 mons 4 days 17 mins 31 secs
307307
(1 row)
308308

309+
-- test long interval output
310+
select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
311+
interval
312+
-------------------------------------------------------------------------------------------
313+
@ 100000000 years 10 mons -1000000000 days -1000000000 hours -10 mins -10.000001 secs ago
314+
(1 row)
315+
309316
-- test justify_hours() and justify_days()
310317
SELECT justify_hours(interval '6 months 3 days 52 hours 3 minutes 2 seconds') as "6 mons 5 days 4 hours 3 mins 2 seconds";
311318
6 mons 5 days 4 hours 3 mins 2 seconds

‎src/test/regress/sql/interval.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ select avg(f1) from interval_tbl;
108108
-- test long interval input
109109
select'4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval;
110110

111+
-- test long interval output
112+
select'100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
111113

112114
-- test justify_hours() and justify_days()
113115

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp