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

Commit4318dae

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 parent5f17304 commit4318dae

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 @@ struct tzEntry;
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
@@ -60,14 +60,14 @@ PGTYPESdate_from_asc(char *str, char **endptr)
6060
intnf;
6161
char*field[MAXDATEFIELDS];
6262
intftype[MAXDATEFIELDS];
63-
charlowstr[MAXDATELEN+1];
63+
charlowstr[MAXDATELEN+MAXDATEFIELDS];
6464
char*realptr;
6565
char**ptr= (endptr!=NULL) ?endptr :&realptr;
6666

6767
boolEuroDates= FALSE;
6868

6969
errno=0;
70-
if (strlen(str) >=sizeof(lowstr))
70+
if (strlen(str)>MAXDATELEN)
7171
{
7272
errno=PGTYPES_DATE_BAD_DATE;
7373
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
@@ -1171,15 +1171,22 @@ DecodeNumberField(int len, char *str, int fmask,
11711171
if ((cp=strchr(str,'.'))!=NULL)
11721172
{
11731173
#ifdefHAVE_INT64_TIMESTAMP
1174-
charfstr[MAXDATELEN+1];
1174+
charfstr[7];
1175+
inti;
1176+
1177+
cp++;
11751178

11761179
/*
11771180
* OK, we have at most six digits to care about. Let's construct a
1178-
* string and then do the conversion to an integer.
1181+
* string with those digits, zero-padded on the right, and then do
1182+
* the conversion to an integer.
1183+
*
1184+
* XXX This truncates the seventh digit, unlike rounding it as do
1185+
* the backend and the !HAVE_INT64_TIMESTAMP case.
11791186
*/
1180-
strcpy(fstr, (cp+1));
1181-
strcpy(fstr+strlen(fstr),"000000");
1182-
*(fstr+6)='\0';
1187+
for (i=0;i<6;i++)
1188+
fstr[i]=*cp!='\0' ?*cp++ :'0';
1189+
fstr[i]='\0';
11831190
*fsec=strtol(fstr,NULL,10);
11841191
#else
11851192
*fsec=strtod(cp,NULL);
@@ -1531,15 +1538,22 @@ DecodeTime(char *str, int *tmask, struct tm * tm, fsec_t *fsec)
15311538
elseif (*cp=='.')
15321539
{
15331540
#ifdefHAVE_INT64_TIMESTAMP
1534-
charfstr[MAXDATELEN+1];
1541+
charfstr[7];
1542+
inti;
1543+
1544+
cp++;
15351545

15361546
/*
1537-
* OK, we have at most six digits to work with. Let's construct a
1538-
* string and then do the conversion to an integer.
1547+
* OK, we have at most six digits to care about. Let's construct a
1548+
* string with those digits, zero-padded on the right, and then do
1549+
* the conversion to an integer.
1550+
*
1551+
* XXX This truncates the seventh digit, unlike rounding it as do
1552+
* the backend and the !HAVE_INT64_TIMESTAMP case.
15391553
*/
1540-
strncpy(fstr, (cp+1),7);
1541-
strcpy(fstr+strlen(fstr),"000000");
1542-
*(fstr+6)='\0';
1554+
for (i=0;i<6;i++)
1555+
fstr[i]=*cp!='\0' ?*cp++ :'0';
1556+
fstr[i]='\0';
15431557
*fsec=strtol(fstr,&cp,10);
15441558
#else
15451559
str=cp;
@@ -1665,6 +1679,9 @@ DecodePosixTimezone(char *str, int *tzp)
16651679
*DTK_NUMBER can hold date fields (yy.ddd)
16661680
*DTK_STRING can hold months (January) and time zones (PST)
16671681
*DTK_DATE can hold Posix time zones (GMT-8)
1682+
*
1683+
* The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
1684+
* bytes of space. On output, field[] entries will point into it.
16681685
*/
16691686
int
16701687
ParseDateTime(char*timestr,char*lowstr,
@@ -1677,7 +1694,10 @@ ParseDateTime(char *timestr, char *lowstr,
16771694
/* outer loop through fields */
16781695
while (*(*endstr)!='\0')
16791696
{
1697+
/* Record start of current field */
16801698
field[nf]=lp;
1699+
if (nf >=MAXDATEFIELDS)
1700+
return-1;
16811701

16821702
/* leading digit? then date or time */
16831703
if (isdigit((unsignedchar)*(*endstr)))
@@ -1818,8 +1838,6 @@ ParseDateTime(char *timestr, char *lowstr,
18181838
/* force in a delimiter after each field */
18191839
*lp++='\0';
18201840
nf++;
1821-
if (nf>MAXDATEFIELDS)
1822-
return-1;
18231841
}
18241842

18251843
*numfields=nf;

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

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

1097-
if (strlen(str) >=sizeof(lowstr))
1097+
if (strlen(str)>MAXDATELEN)
10981098
{
10991099
errno=PGTYPES_INTVL_BAD_INTERVAL;
11001100
returnNULL;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ PGTYPEStimestamp_from_asc(char *str, char **endptr)
294294
char*realptr;
295295
char**ptr= (endptr!=NULL) ?endptr :&realptr;
296296

297-
if (strlen(str) >=sizeof(lowstr))
297+
if (strlen(str)>MAXDATELEN)
298298
{
299299
errno=PGTYPES_TS_BAD_TIMESTAMP;
300300
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