Skip to content

Commit 2925d0f

Browse files
committed
MDEV-27612 Connect : check buffer sizes, fix string format errors
1 parent b962338 commit 2925d0f

File tree

13 files changed

+280
-17
lines changed

13 files changed

+280
-17
lines changed

storage/connect/bsonudf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
201201
p[--n] = 0;
202202
} else if (!IsNum(p)) {
203203
// Wrong array specification
204-
sprintf(g->Message, "Invalid array specification %s", p);
204+
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s", p);
205205
return true;
206206
} // endif p
207207

storage/connect/ha_connect.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5707,10 +5707,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
57075707
if (ttp == TAB_UNDEF && !topt->http) {
57085708
topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
57095709
ttp= GetTypeID(topt->type);
5710-
sprintf(g->Message, "No table_type. Was set to %s", topt->type);
5710+
snprintf(g->Message, sizeof(g->Message), "No table_type. Was set to %s", topt->type);
57115711
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message);
57125712
} else if (ttp == TAB_NIY) {
5713-
sprintf(g->Message, "Unsupported table type %s", topt->type);
5713+
snprintf(g->Message, sizeof(g->Message), "Unsupported table type %s", topt->type);
57145714
rc= HA_ERR_INTERNAL_ERROR;
57155715
goto err;
57165716
#if defined(REST_SUPPORT)

storage/connect/jsonudf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
123123
p[--n] = 0;
124124
} else if (!IsNum(p)) {
125125
// Wrong array specification
126-
sprintf(g->Message, "Invalid array specification %s", p);
126+
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s", p);
127127
return true;
128128
} // endif p
129129

storage/connect/myconn.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,15 +399,19 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
399399
int w;
400400
MYSQLC myc;
401401
PQRYRES qrp = NULL;
402+
const char *p;
402403

403404
if (!port)
404405
port = mysqld_port;
405406

406407
if (!strnicmp(srcdef, "select ", 7) || strstr(srcdef, "%s")) {
407-
query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 10);
408+
query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 10);
408409

409-
if (strstr(srcdef, "%s"))
410-
sprintf(query, srcdef, "1=1"); // dummy where clause
410+
if ((p= strstr(srcdef, "%s")))
411+
{
412+
/* Replace %s with 1=1 */
413+
sprintf(query, "%.*s1=1%s", (int) (p - srcdef), srcdef, p + 2); // dummy where clause
414+
}
411415
else
412416
strcpy(query, srcdef);
413417

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000),
2+
' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users''');
3+
ERROR HY000: Unsupported table type JSON1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
4+
execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname''
5+
Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), '''');
6+
ERROR HY000: Subtype string too long
7+
execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''',
8+
REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), '''');
9+
ERROR HY000: Cannot open
10+
create table t engine=connect table_type=mysql
11+
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
12+
SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s';
13+
select *from t;
14+
ERROR HY000: Got error 174 'MakeSQL: Wrong place holders specification' from CONNECT
15+
drop table t;
16+
create table t engine=connect table_type=mysql
17+
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
18+
SRCDEF='SELECT 1,%n FROM DUAL WHERE %s';
19+
ERROR HY000: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '%n FROM DUAL WHERE 1=1 LIMIT 0' at line 1 [SELECT 1,%n FROM DUAL WHERE 1=1 LIMIT 0]
20+
create table t engine=connect table_type=mysql
21+
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
22+
SRCDEF='SELECT 1 FROM DUAL WHERE %s';
23+
select *from t;
24+
1
25+
1
26+
drop table t;
27+
create table beers (
28+
`Name` char(16) xpath='brandName',
29+
`Origin` char(16) xpath='origin',
30+
`Description` char(32) xpath='details')
31+
engine=CONNECT table_type=XML file_name='MYSQLTEST_VARDIR/tmp/beer.xml'
32+
tabname='table' option_list='rownode=tr,colnode=td%n';
33+
select * from beers;
34+
Name Origin Description
35+
NULL NULL NULL
36+
NULL NULL NULL
37+
drop table beers;
38+
create table beers (
39+
`Name` char(16) xpath='brandName',
40+
`Origin` char(16) xpath='origin',
41+
`Description` char(32) xpath='details')
42+
engine=CONNECT table_type=XML file_name='MYSQLTEST_VARDIR/tmp/beer.xml'
43+
tabname='table' option_list='rownode=tr,colnode=td';
44+
insert into beers values('11','22','33');
45+
drop table beers;
46+
execute immediate CONCAT('create table jsampall
47+
(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'')
48+
engine=CONNECT table_type=JSON
49+
file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json''');
50+
select author from jsampall;
51+
author
52+
Jean-Christophe Bernadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
53+
William J. Pardi
54+
drop table jsampall;
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
2+
# Overlong table type
3+
--error ER_UNKNOWN_ERROR
4+
execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000),
5+
' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users''');
6+
7+
# Overlong subtype
8+
--error ER_UNKNOWN_ERROR
9+
execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname''
10+
Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), '''');
11+
12+
13+
# Overlong filename
14+
--error ER_UNKNOWN_ERROR
15+
execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''',
16+
REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), '''');
17+
18+
19+
# Format string in SRCDEF
20+
--replace_result $MASTER_MYPORT MASTER_MYPORT
21+
eval create table t engine=connect table_type=mysql
22+
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
23+
SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s';
24+
--error ER_GET_ERRMSG
25+
select *from t;
26+
drop table t;
27+
28+
--replace_result $MASTER_MYPORT MASTER_MYPORT
29+
--error ER_UNKNOWN_ERROR
30+
eval create table t engine=connect table_type=mysql
31+
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
32+
SRCDEF='SELECT 1,%n FROM DUAL WHERE %s';
33+
34+
--replace_result $MASTER_MYPORT MASTER_MYPORT
35+
eval create table t engine=connect table_type=mysql
36+
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
37+
SRCDEF='SELECT 1 FROM DUAL WHERE %s';
38+
select *from t;
39+
drop table t;
40+
41+
write_file $MYSQLTEST_VARDIR/tmp/beer.xml;
42+
<?xml version="1.0"?>
43+
<Beers>
44+
<table>
45+
<th><td>Name</td><td>Origin</td><td>Description</td></th>
46+
<tr>
47+
<td><brandName>Huntsman</brandName></td>
48+
<td><origin>Bath, UK</origin></td>
49+
<td><details>Wonderful hop, light alcohol</details></td>
50+
</tr>
51+
<tr>
52+
<td><brandName>Tuborg</brandName></td>
53+
<td><origin>Danmark</origin></td>
54+
<td><details>In small bottles</details></td>
55+
</tr>
56+
</table>
57+
</Beers>
58+
EOF
59+
60+
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
61+
# Format string in colnode
62+
eval create table beers (
63+
`Name` char(16) xpath='brandName',
64+
`Origin` char(16) xpath='origin',
65+
`Description` char(32) xpath='details')
66+
engine=CONNECT table_type=XML file_name='$MYSQLTEST_VARDIR/tmp/beer.xml'
67+
tabname='table' option_list='rownode=tr,colnode=td%n';
68+
select * from beers;
69+
drop table beers;
70+
71+
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
72+
eval create table beers (
73+
`Name` char(16) xpath='brandName',
74+
`Origin` char(16) xpath='origin',
75+
`Description` char(32) xpath='details')
76+
engine=CONNECT table_type=XML file_name='$MYSQLTEST_VARDIR/tmp/beer.xml'
77+
tabname='table' option_list='rownode=tr,colnode=td';
78+
insert into beers values('11','22','33');
79+
drop table beers;
80+
81+
remove_file $MYSQLTEST_VARDIR/tmp/beer.xml;
82+
83+
write_file $MYSQLTEST_VARDIR/tmp/test.json;
84+
[
85+
{
86+
"ISBN": "9782212090819",
87+
"LANG": "fr",
88+
"SUBJECT": "applications",
89+
"AUTHOR": [
90+
{
91+
"FIRSTNAME": "Jean-Christophe",
92+
"LASTNAME": "Bernadac"
93+
},
94+
{
95+
"FIRSTNAME": "François",
96+
"LASTNAME": "Knab"
97+
}
98+
],
99+
"TITLE": "Construire une application XML",
100+
"PUBLISHER": {
101+
"NAME": "Eyrolles",
102+
"PLACE": "Paris"
103+
},
104+
"DATEPUB": 1999
105+
},
106+
{
107+
"ISBN": "9782840825685",
108+
"LANG": "fr",
109+
"SUBJECT": "applications",
110+
"AUTHOR": [
111+
{
112+
"FIRSTNAME": "William J.",
113+
"LASTNAME": "Pardi"
114+
}
115+
],
116+
"TITLE": "XML en Action",
117+
"TRANSLATED": {
118+
"PREFIX": "adapté de l'anglais par",
119+
"TRANSLATOR": {
120+
"FIRSTNAME": "James",
121+
"LASTNAME": "Guerin"
122+
}
123+
},
124+
"PUBLISHER": {
125+
"NAME": "Microsoft Press",
126+
"PLACE": "Paris"
127+
},
128+
"DATEPUB": 1999
129+
}
130+
]
131+
EOF
132+
133+
execute immediate CONCAT('create table jsampall
134+
(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'')
135+
engine=CONNECT table_type=JSON
136+
file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json''');
137+
138+
select author from jsampall;
139+
drop table jsampall;
140+
remove_file $MYSQLTEST_VARDIR/tmp/test.json;
141+

storage/connect/plugutil.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,12 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath)
259259
if (trace(2))
260260
htrc("prefix=%s fn=%s path=%s\n", prefix, FileName, defpath);
261261

262+
if (strlen(FileName) >= _MAX_PATH)
263+
{
264+
*pBuff= 0; /* Hope this is treated as error of some kind*/
265+
return FileName;
266+
}
267+
262268
if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) {
263269
strcpy(pBuff, FileName); // Remote file
264270
return pBuff;

storage/connect/reldef.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info)
9393
if (check_valid_path(module, strlen(module))) {
9494
strcpy(g->Message, "Module cannot contain a path");
9595
return NULL;
96-
} else
96+
}
97+
else if (strlen(subtype)+1+3 >= sizeof(getname)) {
98+
strcpy(g->Message, "Subtype string too long");
99+
return NULL;
100+
}
101+
else
97102
PlugSetPath(soname, module, GetPluginDir());
98103

99104
// The exported name is always in uppercase

storage/connect/tabbson.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,7 +1788,7 @@ bool BSONCOL::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
17881788
p[--n] = 0;
17891789
} else if (!IsNum(p)) {
17901790
// Wrong array specification
1791-
sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
1791+
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s for %s", p, Name);
17921792
return true;
17931793
} // endif p
17941794

storage/connect/tabext.cpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,37 @@ int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
286286
return 0;
287287
} // end of Decode
288288

289+
/*
290+
Count number of %s placeholders in string.
291+
Returns -1 if other sprintf placeholders are found, .g %d
292+
*/
293+
static int count_placeholders(const char *fmt)
294+
{
295+
int cnt= 0;
296+
for (const char *p=fmt; *p; p++)
297+
{
298+
if (*p == '%')
299+
{
300+
switch (p[1])
301+
{
302+
case 's':
303+
/* %s found */
304+
cnt++;
305+
p++;
306+
break;
307+
case '%':
308+
/* masking char for % found */
309+
p++;
310+
break;
311+
default:
312+
/* some other placeholder found */
313+
return -1;
314+
}
315+
}
316+
}
317+
return cnt;
318+
}
319+
289320
/***********************************************************************/
290321
/* MakeSrcdef: make the SQL statement from SRDEF option. */
291322
/***********************************************************************/
@@ -310,16 +341,29 @@ bool TDBEXT::MakeSrcdef(PGLOBAL g)
310341
? To_CondFil->Having : PlugDup(g, "1=1");
311342
} // endif ph
312343

313-
if (!stricmp(ph, "W")) {
344+
int n_placeholders = count_placeholders(Srcdef);
345+
if (n_placeholders < 0)
346+
{
347+
strcpy(g->Message, "MakeSQL: Wrong place holders specification");
348+
return true;
349+
}
350+
351+
if (!stricmp(ph, "W") && n_placeholders <= 1) {
314352
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
315353
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
316-
} else if (!stricmp(ph, "WH")) {
354+
}
355+
else if (!stricmp(ph, "WH") && n_placeholders <= 2)
356+
{
317357
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
318358
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
319-
} else if (!stricmp(ph, "H")) {
359+
}
360+
else if (!stricmp(ph, "H") && n_placeholders <= 1)
361+
{
320362
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
321363
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
322-
} else if (!stricmp(ph, "HW")) {
364+
}
365+
else if (!stricmp(ph, "HW") && n_placeholders <= 2)
366+
{
323367
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
324368
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
325369
} else {

0 commit comments

Comments
 (0)