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

Commit 2c37cb2

Browse files
committed
ecpg: Fix out-of-bound read in DecodeDateTime()
It was possible for the code to read out-of-bound data from the "day_tab" table with some crafted input data. Let's treat these as invalid input as the month number is incorrect. A test is added to test this case with a check on the errno returned by the decoding routine. A test close to the new one added in this commit was testing for a failure, but did not look at the errno generated, so let's use this commit to also change it, adding a check on the errno returned by DecodeDateTime(). Like the other test scripts, dt_test should likely be expanded to include more checks based on the errnos generated in these code paths. This is left as future work. This issue exists since 2e6f975, so backpatch all the way down. Reported-by: Pavel Nekrasov Author: Bruce Momjian, Pavel Nekrasov Discussion: https://postgr.es/m/18614-6bbe00117352309e@postgresql.org Backpatch-through: 12
1 parent 5914a22 commit 2c37cb2

File tree

5 files changed

+109
-48
lines changed

5 files changed

+109
-48
lines changed

src/interfaces/ecpg/pgtypeslib/dt_common.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -2325,10 +2325,10 @@ DecodeDateTime(char **field, int *ftype, int nf,
23252325
return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
23262326

23272327
/*
2328-
* check for valid day of month, now that we know for sure the month
2329-
* and year...
2328+
* check for valid day of month and month, now that we know for sure
2329+
* the month and year...
23302330
*/
2331-
if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2331+
if (tm->tm_mon < 1 || tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
23322332
return -1;
23332333

23342334
/*

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c

+53-23
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <string.h>
1212
#include <stdlib.h>
1313
#include <pgtypes_date.h>
14+
#include <pgtypes_error.h>
1415
#include <pgtypes_timestamp.h>
1516
#include <pgtypes_interval.h>
1617

@@ -22,9 +23,11 @@
2223

2324

2425

25-
#line 8 "dt_test.pgc"
26+
#line 9 "dt_test.pgc"
2627

2728

29+
static void check_errno(void);
30+
2831
int
2932
main(void)
3033
{
@@ -34,19 +37,19 @@ main(void)
3437

3538

3639

37-
#line 14 "dt_test.pgc"
40+
#line 17 "dt_test.pgc"
3841
date date1 ;
3942

40-
#line 15 "dt_test.pgc"
43+
#line 18 "dt_test.pgc"
4144
timestamp ts1 ;
4245

43-
#line 16 "dt_test.pgc"
46+
#line 19 "dt_test.pgc"
4447
interval * iv1 , iv2 ;
4548

46-
#line 17 "dt_test.pgc"
49+
#line 20 "dt_test.pgc"
4750
char * text ;
4851
/* exec sql end declare section */
49-
#line 18 "dt_test.pgc"
52+
#line 21 "dt_test.pgc"
5053

5154
date date2;
5255
int mdy[3] = { 4, 19, 1998 };
@@ -57,31 +60,31 @@ main(void)
5760

5861
ECPGdebug(1, stderr);
5962
/* exec sql whenever sqlerror do sqlprint ( ) ; */
60-
#line 27 "dt_test.pgc"
63+
#line 30 "dt_test.pgc"
6164

6265
{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0);
63-
#line 28 "dt_test.pgc"
66+
#line 31 "dt_test.pgc"
6467

6568
if (sqlca.sqlcode < 0) sqlprint ( );}
66-
#line 28 "dt_test.pgc"
69+
#line 31 "dt_test.pgc"
6770

6871
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table date_test ( d date , ts timestamp )", ECPGt_EOIT, ECPGt_EORT);
69-
#line 29 "dt_test.pgc"
72+
#line 32 "dt_test.pgc"
7073

7174
if (sqlca.sqlcode < 0) sqlprint ( );}
72-
#line 29 "dt_test.pgc"
75+
#line 32 "dt_test.pgc"
7376

7477
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
75-
#line 30 "dt_test.pgc"
78+
#line 33 "dt_test.pgc"
7679

7780
if (sqlca.sqlcode < 0) sqlprint ( );}
78-
#line 30 "dt_test.pgc"
81+
#line 33 "dt_test.pgc"
7982

8083
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "set intervalstyle to postgres_verbose", ECPGt_EOIT, ECPGt_EORT);
81-
#line 31 "dt_test.pgc"
84+
#line 34 "dt_test.pgc"
8285

8386
if (sqlca.sqlcode < 0) sqlprint ( );}
84-
#line 31 "dt_test.pgc"
87+
#line 34 "dt_test.pgc"
8588

8689

8790
date1 = PGTYPESdate_from_asc(d1, NULL);
@@ -92,10 +95,10 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
9295
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
9396
ECPGt_timestamp,&(ts1),(long)1,(long)1,sizeof(timestamp),
9497
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
95-
#line 36 "dt_test.pgc"
98+
#line 39 "dt_test.pgc"
9699

97100
if (sqlca.sqlcode < 0) sqlprint ( );}
98-
#line 36 "dt_test.pgc"
101+
#line 39 "dt_test.pgc"
99102

100103

101104
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select * from date_test where d = $1 ",
@@ -105,10 +108,10 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
105108
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
106109
ECPGt_timestamp,&(ts1),(long)1,(long)1,sizeof(timestamp),
107110
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
108-
#line 38 "dt_test.pgc"
111+
#line 41 "dt_test.pgc"
109112

110113
if (sqlca.sqlcode < 0) sqlprint ( );}
111-
#line 38 "dt_test.pgc"
114+
#line 41 "dt_test.pgc"
112115

113116

114117
text = PGTYPESdate_to_asc(date1);
@@ -263,10 +266,19 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
263266
PGTYPESchar_free(text);
264267

265268
ts1 = PGTYPEStimestamp_from_asc("1994-02-11 26:10:35", NULL);
269+
/* failure, check error code */
270+
check_errno();
266271
text = PGTYPEStimestamp_to_asc(ts1);
267272
printf("timestamp_to_asc3: %s\n", text);
268273
PGTYPESchar_free(text);
269274

275+
ts1 = PGTYPEStimestamp_from_asc("AM95000062", NULL);
276+
/* failure, check error code */
277+
check_errno();
278+
text = PGTYPEStimestamp_to_asc(ts1);
279+
printf("timestamp_to_asc4: %s\n", text);
280+
PGTYPESchar_free(text);
281+
270282
/* abc-03:10:35-def-02/11/94-gh */
271283
/* 12345678901234567890123456789 */
272284

@@ -453,17 +465,35 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
453465
free(out);
454466

455467
{ ECPGtrans(__LINE__, NULL, "rollback");
456-
#line 381 "dt_test.pgc"
468+
#line 393 "dt_test.pgc"
457469

458470
if (sqlca.sqlcode < 0) sqlprint ( );}
459-
#line 381 "dt_test.pgc"
471+
#line 393 "dt_test.pgc"
460472

461473
{ ECPGdisconnect(__LINE__, "CURRENT");
462-
#line 382 "dt_test.pgc"
474+
#line 394 "dt_test.pgc"
463475

464476
if (sqlca.sqlcode < 0) sqlprint ( );}
465-
#line 382 "dt_test.pgc"
477+
#line 394 "dt_test.pgc"
466478

467479

468480
return 0;
469481
}
482+
483+
static void
484+
check_errno(void)
485+
{
486+
switch(errno)
487+
{
488+
case 0:
489+
printf("(no errno set) - ");
490+
break;
491+
case PGTYPES_TS_BAD_TIMESTAMP:
492+
printf("(errno == PGTYPES_TS_BAD_TIMESTAMP) - ");
493+
break;
494+
default:
495+
printf("(unknown errno (%d))\n", errno);
496+
printf("(libc: (%s)) ", strerror(errno));
497+
break;
498+
}
499+
}

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr

+21-21
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,47 @@
22
[NO_PID]: sqlca: code: 0, state: 00000
33
[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>
44
[NO_PID]: sqlca: code: 0, state: 00000
5-
[NO_PID]: ecpg_execute on line 29: query: create table date_test ( d date , ts timestamp ); with 0 parameter(s) on connection ecpg1_regression
5+
[NO_PID]: ecpg_execute on line 32: query: create table date_test ( d date , ts timestamp ); with 0 parameter(s) on connection ecpg1_regression
66
[NO_PID]: sqlca: code: 0, state: 00000
7-
[NO_PID]: ecpg_execute on line 29: using PQexec
7+
[NO_PID]: ecpg_execute on line 32: using PQexec
88
[NO_PID]: sqlca: code: 0, state: 00000
9-
[NO_PID]: ecpg_process_output on line 29: OK: CREATE TABLE
9+
[NO_PID]: ecpg_process_output on line 32: OK: CREATE TABLE
1010
[NO_PID]: sqlca: code: 0, state: 00000
11-
[NO_PID]: ecpg_execute on line 30: query: set datestyle to iso; with 0 parameter(s) on connection ecpg1_regression
11+
[NO_PID]: ecpg_execute on line 33: query: set datestyle to iso; with 0 parameter(s) on connection ecpg1_regression
1212
[NO_PID]: sqlca: code: 0, state: 00000
13-
[NO_PID]: ecpg_execute on line 30: using PQexec
13+
[NO_PID]: ecpg_execute on line 33: using PQexec
1414
[NO_PID]: sqlca: code: 0, state: 00000
15-
[NO_PID]: ecpg_process_output on line 30: OK: SET
15+
[NO_PID]: ecpg_process_output on line 33: OK: SET
1616
[NO_PID]: sqlca: code: 0, state: 00000
17-
[NO_PID]: ecpg_execute on line 31: query: set intervalstyle to postgres_verbose; with 0 parameter(s) on connection ecpg1_regression
17+
[NO_PID]: ecpg_execute on line 34: query: set intervalstyle to postgres_verbose; with 0 parameter(s) on connection ecpg1_regression
1818
[NO_PID]: sqlca: code: 0, state: 00000
19-
[NO_PID]: ecpg_execute on line 31: using PQexec
19+
[NO_PID]: ecpg_execute on line 34: using PQexec
2020
[NO_PID]: sqlca: code: 0, state: 00000
21-
[NO_PID]: ecpg_process_output on line 31: OK: SET
21+
[NO_PID]: ecpg_process_output on line 34: OK: SET
2222
[NO_PID]: sqlca: code: 0, state: 00000
23-
[NO_PID]: ecpg_execute on line 36: query: insert into date_test ( d , ts ) values ( $1 , $2 ); with 2 parameter(s) on connection ecpg1_regression
23+
[NO_PID]: ecpg_execute on line 39: query: insert into date_test ( d , ts ) values ( $1 , $2 ); with 2 parameter(s) on connection ecpg1_regression
2424
[NO_PID]: sqlca: code: 0, state: 00000
25-
[NO_PID]: ecpg_execute on line 36: using PQexecParams
25+
[NO_PID]: ecpg_execute on line 39: using PQexecParams
2626
[NO_PID]: sqlca: code: 0, state: 00000
27-
[NO_PID]: ecpg_free_params on line 36: parameter 1 = 1966-01-17
27+
[NO_PID]: ecpg_free_params on line 39: parameter 1 = 1966-01-17
2828
[NO_PID]: sqlca: code: 0, state: 00000
29-
[NO_PID]: ecpg_free_params on line 36: parameter 2 = 2000-07-12 17:34:29
29+
[NO_PID]: ecpg_free_params on line 39: parameter 2 = 2000-07-12 17:34:29
3030
[NO_PID]: sqlca: code: 0, state: 00000
31-
[NO_PID]: ecpg_process_output on line 36: OK: INSERT 0 1
31+
[NO_PID]: ecpg_process_output on line 39: OK: INSERT 0 1
3232
[NO_PID]: sqlca: code: 0, state: 00000
33-
[NO_PID]: ecpg_execute on line 38: query: select * from date_test where d = $1 ; with 1 parameter(s) on connection ecpg1_regression
33+
[NO_PID]: ecpg_execute on line 41: query: select * from date_test where d = $1 ; with 1 parameter(s) on connection ecpg1_regression
3434
[NO_PID]: sqlca: code: 0, state: 00000
35-
[NO_PID]: ecpg_execute on line 38: using PQexecParams
35+
[NO_PID]: ecpg_execute on line 41: using PQexecParams
3636
[NO_PID]: sqlca: code: 0, state: 00000
37-
[NO_PID]: ecpg_free_params on line 38: parameter 1 = 1966-01-17
37+
[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1966-01-17
3838
[NO_PID]: sqlca: code: 0, state: 00000
39-
[NO_PID]: ecpg_process_output on line 38: correctly got 1 tuples with 2 fields
39+
[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
4040
[NO_PID]: sqlca: code: 0, state: 00000
41-
[NO_PID]: ecpg_get_data on line 38: RESULT: 1966-01-17 offset: -1; array: no
41+
[NO_PID]: ecpg_get_data on line 41: RESULT: 1966-01-17 offset: -1; array: no
4242
[NO_PID]: sqlca: code: 0, state: 00000
43-
[NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: no
43+
[NO_PID]: ecpg_get_data on line 41: RESULT: 2000-07-12 17:34:29 offset: -1; array: no
4444
[NO_PID]: sqlca: code: 0, state: 00000
45-
[NO_PID]: ECPGtrans on line 381: action "rollback"; connection "ecpg1_regression"
45+
[NO_PID]: ECPGtrans on line 393: action "rollback"; connection "ecpg1_regression"
4646
[NO_PID]: sqlca: code: 0, state: 00000
4747
[NO_PID]: ecpg_finish: connection ecpg1_regression closed
4848
[NO_PID]: sqlca: code: 0, state: 00000

src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stdout

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ date_defmt_asc10: 1995-12-25
2020
date_defmt_asc12: 0095-12-25
2121
timestamp_to_asc1: 1996-02-29 00:00:00
2222
timestamp_to_asc2: 1994-02-11 03:10:35
23-
timestamp_to_asc3: 2000-01-01 00:00:00
23+
(errno == PGTYPES_TS_BAD_TIMESTAMP) - timestamp_to_asc3: 2000-01-01 00:00:00
24+
(errno == PGTYPES_TS_BAD_TIMESTAMP) - timestamp_to_asc4: 2000-01-01 00:00:00
2425
timestamp_fmt_asc: 0: abc-00:00:00-def-01/01/00-ghi%
2526
timestamp_defmt_asc(This is a 4/12/80 3-39l12test, This is a %m/%d/%y %H-%Ml%Stest) = 1980-04-12 03:39:12, error: 0
2627
timestamp_defmt_asc(Tue Jul 22 17:28:44 +0200 2003, %a %b %d %H:%M:%S %z %Y) = 2003-07-22 15:28:44, error: 0

src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc

+30
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
#include <string.h>
33
#include <stdlib.h>
44
#include <pgtypes_date.h>
5+
#include <pgtypes_error.h>
56
#include <pgtypes_timestamp.h>
67
#include <pgtypes_interval.h>
78

89
exec sql include ../regression;
910

11+
static void check_errno(void);
12+
1013
int
1114
main(void)
1215
{
@@ -189,10 +192,19 @@ main(void)
189192
PGTYPESchar_free(text);
190193

191194
ts1 = PGTYPEStimestamp_from_asc("1994-02-11 26:10:35", NULL);
195+
/* failure, check error code */
196+
check_errno();
192197
text = PGTYPEStimestamp_to_asc(ts1);
193198
printf("timestamp_to_asc3: %s\n", text);
194199
PGTYPESchar_free(text);
195200

201+
ts1 = PGTYPEStimestamp_from_asc("AM95000062", NULL);
202+
/* failure, check error code */
203+
check_errno();
204+
text = PGTYPEStimestamp_to_asc(ts1);
205+
printf("timestamp_to_asc4: %s\n", text);
206+
PGTYPESchar_free(text);
207+
196208
/* abc-03:10:35-def-02/11/94-gh */
197209
/* 12345678901234567890123456789 */
198210

@@ -383,3 +395,21 @@ main(void)
383395

384396
return 0;
385397
}
398+
399+
static void
400+
check_errno(void)
401+
{
402+
switch(errno)
403+
{
404+
case 0:
405+
printf("(no errno set) - ");
406+
break;
407+
case PGTYPES_TS_BAD_TIMESTAMP:
408+
printf("(errno == PGTYPES_TS_BAD_TIMESTAMP) - ");
409+
break;
410+
default:
411+
printf("(unknown errno (%d))\n", errno);
412+
printf("(libc: (%s)) ", strerror(errno));
413+
break;
414+
}
415+
}

0 commit comments

Comments
 (0)