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

Commit63e0d61

Browse files
author
Neil Conway
committed
Adjust datetime parsing to be more robust. We now pass the length of the
working buffer into ParseDateTime() and reject too-long input there,rather than checking the length of the input string before callingParseDateTime(). The old method was bogus because ParseDateTime() can usea variable amount of working space, depending on the content of theinput string (e.g. how many fields need to be NUL terminated). This fixesa minor stack overrun -- I don't _think_ it's exploitable, although Iwon't claim to be an expert.Along the way, fix a bug reported by Mark Dilger: the working bufferallocated by interval_in() was too short, which resulted in rejectingsome perfectly valid interval input values. I added a regression test forthis fix.
1 parent15e4d1e commit63e0d61

File tree

7 files changed

+86
-75
lines changed

7 files changed

+86
-75
lines changed

‎src/backend/utils/adt/date.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.108 2005/05/24 02:09:45 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.109 2005/05/26 02:04:13 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -65,12 +65,10 @@ date_in(PG_FUNCTION_ARGS)
6565
intdterr;
6666
char*field[MAXDATEFIELDS];
6767
intftype[MAXDATEFIELDS];
68-
charlowstr[MAXDATELEN+1];
68+
charworkbuf[MAXDATELEN+1];
6969

70-
if (strlen(str) >=sizeof(lowstr))
71-
dterr=DTERR_BAD_FORMAT;
72-
else
73-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
70+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
71+
field,ftype,MAXDATEFIELDS,&nf);
7472
if (dterr==0)
7573
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tzp);
7674
if (dterr!=0)
@@ -894,15 +892,13 @@ time_in(PG_FUNCTION_ARGS)
894892
inttz;
895893
intnf;
896894
intdterr;
897-
charlowstr[MAXDATELEN+1];
895+
charworkbuf[MAXDATELEN+1];
898896
char*field[MAXDATEFIELDS];
899897
intdtype;
900898
intftype[MAXDATEFIELDS];
901899

902-
if (strlen(str) >=sizeof(lowstr))
903-
dterr=DTERR_BAD_FORMAT;
904-
else
905-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
900+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
901+
field,ftype,MAXDATEFIELDS,&nf);
906902
if (dterr==0)
907903
dterr=DecodeTimeOnly(field,ftype,nf,&dtype,tm,&fsec,&tz);
908904
if (dterr!=0)
@@ -1733,15 +1729,13 @@ timetz_in(PG_FUNCTION_ARGS)
17331729
inttz;
17341730
intnf;
17351731
intdterr;
1736-
charlowstr[MAXDATELEN+1];
1732+
charworkbuf[MAXDATELEN+1];
17371733
char*field[MAXDATEFIELDS];
17381734
intdtype;
17391735
intftype[MAXDATEFIELDS];
17401736

1741-
if (strlen(str) >=sizeof(lowstr))
1742-
dterr=DTERR_BAD_FORMAT;
1743-
else
1744-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
1737+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
1738+
field,ftype,MAXDATEFIELDS,&nf);
17451739
if (dterr==0)
17461740
dterr=DecodeTimeOnly(field,ftype,nf,&dtype,tm,&fsec,&tz);
17471741
if (dterr!=0)

‎src/backend/utils/adt/datetime.c

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.144 2005/05/24 02:09:45 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.145 2005/05/26 02:04:13 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -699,21 +699,23 @@ TrimTrailingZeros(char *str)
699699
}
700700
}
701701

702-
703702
/* ParseDateTime()
704703
*Break string into tokens based on a date/time context.
705704
*Returns 0 if successful, DTERR code if bogus input detected.
706705
*
707706
* timestr - the input string
708-
* lowstr - workspace for field string storage (must be large enough for
709-
*a copy of the input string, including trailing null)
707+
* workbuf - workspace for field string storage. This must be
708+
* larger than the largest legal input for this datetime type --
709+
* some additional space will be needed to NUL terminate fields.
710+
* buflen - the size of workbuf
710711
* field[] - pointers to field strings are returned in this array
711712
* ftype[] - field type indicators are returned in this array
712713
* maxfields - dimensions of the above two arrays
713714
* *numfields - set to the actual number of fields detected
714715
*
715-
* The fields extracted from the input are stored as separate, null-terminated
716-
* strings in the workspace at lowstr.Any text is converted to lower case.
716+
* The fields extracted from the input are stored as separate,
717+
* null-terminated strings in the workspace at workbuf. Any text is
718+
* converted to lower case.
717719
*
718720
* Several field types are assigned:
719721
*DTK_NUMBER - digits and (possibly) a decimal point
@@ -729,12 +731,27 @@ TrimTrailingZeros(char *str)
729731
*DTK_DATE can hold Posix time zones (GMT-8)
730732
*/
731733
int
732-
ParseDateTime(constchar*timestr,char*lowstr,
734+
ParseDateTime(constchar*timestr,char*workbuf,size_tbuflen,
733735
char**field,int*ftype,intmaxfields,int*numfields)
734736
{
735737
intnf=0;
736738
constchar*cp=timestr;
737-
char*lp=lowstr;
739+
char*bufp=workbuf;
740+
constchar*bufend=workbuf+buflen;
741+
742+
/*
743+
* Set the character pointed-to by "bufptr" to "newchar", and
744+
* increment "bufptr". "end" gives the end of the buffer -- we
745+
* return an error if there is no space left to append a character
746+
* to the buffer. Note that "bufptr" is evaluated twice.
747+
*/
748+
#defineAPPEND_CHAR(bufptr,end,newchar)\
749+
do\
750+
{\
751+
if (((bufptr) + 1) >= (end))\
752+
return DTERR_BAD_FORMAT;\
753+
*(bufptr)++ = newchar;\
754+
} while (0)
738755

739756
/* outer loop through fields */
740757
while (*cp!='\0')
@@ -749,37 +766,37 @@ ParseDateTime(const char *timestr, char *lowstr,
749766
/* Record start of current field */
750767
if (nf >=maxfields)
751768
returnDTERR_BAD_FORMAT;
752-
field[nf]=lp;
769+
field[nf]=bufp;
753770

754771
/* leading digit? then date or time */
755772
if (isdigit((unsignedchar)*cp))
756773
{
757-
*lp++=*cp++;
774+
APPEND_CHAR(bufp,bufend,*cp++);
758775
while (isdigit((unsignedchar)*cp))
759-
*lp++=*cp++;
776+
APPEND_CHAR(bufp,bufend,*cp++);
760777

761778
/* time field? */
762779
if (*cp==':')
763780
{
764781
ftype[nf]=DTK_TIME;
765-
*lp++=*cp++;
782+
APPEND_CHAR(bufp,bufend,*cp++);
766783
while (isdigit((unsignedchar)*cp)||
767784
(*cp==':')|| (*cp=='.'))
768-
*lp++=*cp++;
785+
APPEND_CHAR(bufp,bufend,*cp++);
769786
}
770787
/* date field? allow embedded text month */
771788
elseif (*cp=='-'||*cp=='/'||*cp=='.')
772789
{
773790
/* save delimiting character to use later */
774791
chardelim=*cp;
775792

776-
*lp++=*cp++;
793+
APPEND_CHAR(bufp,bufend,*cp++);
777794
/* second field is all digits? then no embedded text month */
778795
if (isdigit((unsignedchar)*cp))
779796
{
780797
ftype[nf]= ((delim=='.') ?DTK_NUMBER :DTK_DATE);
781798
while (isdigit((unsignedchar)*cp))
782-
*lp++=*cp++;
799+
APPEND_CHAR(bufp,bufend,*cp++);
783800

784801
/*
785802
* insist that the delimiters match to get a
@@ -788,16 +805,16 @@ ParseDateTime(const char *timestr, char *lowstr,
788805
if (*cp==delim)
789806
{
790807
ftype[nf]=DTK_DATE;
791-
*lp++=*cp++;
808+
APPEND_CHAR(bufp,bufend,*cp++);
792809
while (isdigit((unsignedchar)*cp)||*cp==delim)
793-
*lp++=*cp++;
810+
APPEND_CHAR(bufp,bufend,*cp++);
794811
}
795812
}
796813
else
797814
{
798815
ftype[nf]=DTK_DATE;
799816
while (isalnum((unsignedchar)*cp)||*cp==delim)
800-
*lp++=pg_tolower((unsignedchar)*cp++);
817+
APPEND_CHAR(bufp,bufend,pg_tolower((unsignedchar)*cp++));
801818
}
802819
}
803820

@@ -811,9 +828,9 @@ ParseDateTime(const char *timestr, char *lowstr,
811828
/* Leading decimal point? Then fractional seconds... */
812829
elseif (*cp=='.')
813830
{
814-
*lp++=*cp++;
831+
APPEND_CHAR(bufp,bufend,*cp++);
815832
while (isdigit((unsignedchar)*cp))
816-
*lp++=*cp++;
833+
APPEND_CHAR(bufp,bufend,*cp++);
817834

818835
ftype[nf]=DTK_NUMBER;
819836
}
@@ -825,9 +842,9 @@ ParseDateTime(const char *timestr, char *lowstr,
825842
elseif (isalpha((unsignedchar)*cp))
826843
{
827844
ftype[nf]=DTK_STRING;
828-
*lp++=pg_tolower((unsignedchar)*cp++);
845+
APPEND_CHAR(bufp,bufend,pg_tolower((unsignedchar)*cp++));
829846
while (isalpha((unsignedchar)*cp))
830-
*lp++=pg_tolower((unsignedchar)*cp++);
847+
APPEND_CHAR(bufp,bufend,pg_tolower((unsignedchar)*cp++));
831848

832849
/*
833850
* Full date string with leading text month? Could also be a
@@ -838,34 +855,34 @@ ParseDateTime(const char *timestr, char *lowstr,
838855
chardelim=*cp;
839856

840857
ftype[nf]=DTK_DATE;
841-
*lp++=*cp++;
858+
APPEND_CHAR(bufp,bufend,*cp++);
842859
while (isdigit((unsignedchar)*cp)||*cp==delim)
843-
*lp++=*cp++;
860+
APPEND_CHAR(bufp,bufend,*cp++);
844861
}
845862
}
846863
/* sign? then special or numeric timezone */
847864
elseif (*cp=='+'||*cp=='-')
848865
{
849-
*lp++=*cp++;
866+
APPEND_CHAR(bufp,bufend,*cp++);
850867
/* soak up leading whitespace */
851868
while (isspace((unsignedchar)*cp))
852869
cp++;
853870
/* numeric timezone? */
854871
if (isdigit((unsignedchar)*cp))
855872
{
856873
ftype[nf]=DTK_TZ;
857-
*lp++=*cp++;
874+
APPEND_CHAR(bufp,bufend,*cp++);
858875
while (isdigit((unsignedchar)*cp)||
859876
*cp==':'||*cp=='.')
860-
*lp++=*cp++;
877+
APPEND_CHAR(bufp,bufend,*cp++);
861878
}
862879
/* special? */
863880
elseif (isalpha((unsignedchar)*cp))
864881
{
865882
ftype[nf]=DTK_SPECIAL;
866-
*lp++=pg_tolower((unsignedchar)*cp++);
883+
APPEND_CHAR(bufp,bufend,pg_tolower((unsignedchar)*cp++));
867884
while (isalpha((unsignedchar)*cp))
868-
*lp++=pg_tolower((unsignedchar)*cp++);
885+
APPEND_CHAR(bufp,bufend,pg_tolower((unsignedchar)*cp++));
869886
}
870887
/* otherwise something wrong... */
871888
else
@@ -882,7 +899,7 @@ ParseDateTime(const char *timestr, char *lowstr,
882899
returnDTERR_BAD_FORMAT;
883900

884901
/* force in a delimiter after each field */
885-
*lp++='\0';
902+
*bufp++='\0';
886903
nf++;
887904
}
888905

‎src/backend/utils/adt/nabstime.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.131 2005/05/24 02:09:45 momjian Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.132 2005/05/26 02:04:13 neilc Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -306,15 +306,13 @@ abstimein(PG_FUNCTION_ARGS)
306306
*tm=&date;
307307
intdterr;
308308
char*field[MAXDATEFIELDS];
309-
charlowstr[MAXDATELEN+1];
309+
charworkbuf[MAXDATELEN+1];
310310
intdtype;
311311
intnf,
312312
ftype[MAXDATEFIELDS];
313313

314-
if (strlen(str) >=sizeof(lowstr))
315-
dterr=DTERR_BAD_FORMAT;
316-
else
317-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
314+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
315+
field,ftype,MAXDATEFIELDS,&nf);
318316
if (dterr==0)
319317
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tz);
320318
if (dterr!=0)
@@ -711,12 +709,10 @@ reltimein(PG_FUNCTION_ARGS)
711709
char*field[MAXDATEFIELDS];
712710
intnf,
713711
ftype[MAXDATEFIELDS];
714-
charlowstr[MAXDATELEN+1];
712+
charworkbuf[MAXDATELEN+1];
715713

716-
if (strlen(str) >=sizeof(lowstr))
717-
dterr=DTERR_BAD_FORMAT;
718-
else
719-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
714+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
715+
field,ftype,MAXDATEFIELDS,&nf);
720716
if (dterr==0)
721717
dterr=DecodeInterval(field,ftype,nf,&dtype,tm,&fsec);
722718
if (dterr!=0)

‎src/backend/utils/adt/timestamp.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.123 2005/05/24 02:09:45 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.124 2005/05/26 02:04:13 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -77,12 +77,10 @@ timestamp_in(PG_FUNCTION_ARGS)
7777
intdterr;
7878
char*field[MAXDATEFIELDS];
7979
intftype[MAXDATEFIELDS];
80-
charlowstr[MAXDATELEN+MAXDATEFIELDS];
80+
charworkbuf[MAXDATELEN+MAXDATEFIELDS];
8181

82-
if (strlen(str) >=sizeof(lowstr))
83-
dterr=DTERR_BAD_FORMAT;
84-
else
85-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
82+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
83+
field,ftype,MAXDATEFIELDS,&nf);
8684
if (dterr==0)
8785
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tz);
8886
if (dterr!=0)
@@ -317,12 +315,10 @@ timestamptz_in(PG_FUNCTION_ARGS)
317315
intdterr;
318316
char*field[MAXDATEFIELDS];
319317
intftype[MAXDATEFIELDS];
320-
charlowstr[MAXDATELEN+MAXDATEFIELDS];
318+
charworkbuf[MAXDATELEN+MAXDATEFIELDS];
321319

322-
if (strlen(str) >=sizeof(lowstr))
323-
dterr=DTERR_BAD_FORMAT;
324-
else
325-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
320+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),
321+
field,ftype,MAXDATEFIELDS,&nf);
326322
if (dterr==0)
327323
dterr=DecodeDateTime(field,ftype,nf,&dtype,tm,&fsec,&tz);
328324
if (dterr!=0)
@@ -493,7 +489,7 @@ interval_in(PG_FUNCTION_ARGS)
493489
intdterr;
494490
char*field[MAXDATEFIELDS];
495491
intftype[MAXDATEFIELDS];
496-
charlowstr[MAXDATELEN+MAXDATEFIELDS];
492+
charworkbuf[256];
497493

498494
tm->tm_year=0;
499495
tm->tm_mon=0;
@@ -503,10 +499,8 @@ interval_in(PG_FUNCTION_ARGS)
503499
tm->tm_sec=0;
504500
fsec=0;
505501

506-
if (strlen(str) >=sizeof(lowstr))
507-
dterr=DTERR_BAD_FORMAT;
508-
else
509-
dterr=ParseDateTime(str,lowstr,field,ftype,MAXDATEFIELDS,&nf);
502+
dterr=ParseDateTime(str,workbuf,sizeof(workbuf),field,
503+
ftype,MAXDATEFIELDS,&nf);
510504
if (dterr==0)
511505
dterr=DecodeInterval(field,ftype,nf,&dtype,tm,&fsec);
512506
if (dterr!=0)

‎src/include/utils/datetime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
1010
* Portions Copyright (c) 1994, Regents of the University of California
1111
*
12-
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.53 2005/05/2404:03:01 momjian Exp $
12+
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.54 2005/05/26 02:04:14 neilc Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -276,7 +276,7 @@ extern void GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp);
276276
externvoidj2date(intjd,int*year,int*month,int*day);
277277
externintdate2j(intyear,intmonth,intday);
278278

279-
externintParseDateTime(constchar*timestr,char*lowstr,
279+
externintParseDateTime(constchar*timestr,char*workbuf,size_tbuflen,
280280
char**field,int*ftype,
281281
intmaxfields,int*numfields);
282282
externintDecodeDateTime(char**field,int*ftype,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp