Skip to content

Commit

Permalink
MDEV-27612 Connect : check buffer sizes, fix string format errors
Browse files Browse the repository at this point in the history
  • Loading branch information
vaintroub committed Jan 26, 2022
1 parent b962338 commit 2925d0f
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 17 deletions.
2 changes: 1 addition & 1 deletion storage/connect/bsonudf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s", p);
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s", p);
return true;
} // endif p

Expand Down
4 changes: 2 additions & 2 deletions storage/connect/ha_connect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5707,10 +5707,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd,
if (ttp == TAB_UNDEF && !topt->http) {
topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
ttp= GetTypeID(topt->type);
sprintf(g->Message, "No table_type. Was set to %s", topt->type);
snprintf(g->Message, sizeof(g->Message), "No table_type. Was set to %s", topt->type);
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message);
} else if (ttp == TAB_NIY) {
sprintf(g->Message, "Unsupported table type %s", topt->type);
snprintf(g->Message, sizeof(g->Message), "Unsupported table type %s", topt->type);
rc= HA_ERR_INTERNAL_ERROR;
goto err;
#if defined(REST_SUPPORT)
Expand Down
2 changes: 1 addition & 1 deletion storage/connect/jsonudf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s", p);
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s", p);
return true;
} // endif p

Expand Down
10 changes: 7 additions & 3 deletions storage/connect/myconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,15 +399,19 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
int w;
MYSQLC myc;
PQRYRES qrp = NULL;
const char *p;

if (!port)
port = mysqld_port;

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

if (strstr(srcdef, "%s"))
sprintf(query, srcdef, "1=1"); // dummy where clause
if ((p= strstr(srcdef, "%s")))
{
/* Replace %s with 1=1 */
sprintf(query, "%.*s1=1%s", (int) (p - srcdef), srcdef, p + 2); // dummy where clause
}
else
strcpy(query, srcdef);

Expand Down
54 changes: 54 additions & 0 deletions storage/connect/mysql-test/connect/r/misc.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000),
' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users''');
ERROR HY000: Unsupported table type JSON1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname''
Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), '''');
ERROR HY000: Subtype string too long
execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''',
REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), '''');
ERROR HY000: Cannot open
create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s';
select *from t;
ERROR HY000: Got error 174 'MakeSQL: Wrong place holders specification' from CONNECT
drop table t;
create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1,%n FROM DUAL WHERE %s';
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]
create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1 FROM DUAL WHERE %s';
select *from t;
1
1
drop table t;
create table beers (
`Name` char(16) xpath='brandName',
`Origin` char(16) xpath='origin',
`Description` char(32) xpath='details')
engine=CONNECT table_type=XML file_name='MYSQLTEST_VARDIR/tmp/beer.xml'
tabname='table' option_list='rownode=tr,colnode=td%n';
select * from beers;
Name Origin Description
NULL NULL NULL
NULL NULL NULL
drop table beers;
create table beers (
`Name` char(16) xpath='brandName',
`Origin` char(16) xpath='origin',
`Description` char(32) xpath='details')
engine=CONNECT table_type=XML file_name='MYSQLTEST_VARDIR/tmp/beer.xml'
tabname='table' option_list='rownode=tr,colnode=td';
insert into beers values('11','22','33');
drop table beers;
execute immediate CONCAT('create table jsampall
(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'')
engine=CONNECT table_type=JSON
file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json''');
select author from jsampall;
author
Jean-Christophe Bernadacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
William J. Pardi
drop table jsampall;
141 changes: 141 additions & 0 deletions storage/connect/mysql-test/connect/t/misc.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

# Overlong table type
--error ER_UNKNOWN_ERROR
execute immediate concat('create table t engine=CONNECT table_type=JSON',REPEAT('1',5000),
' FILE_NAME=''users.json'' HTTP=''http://localhost:4142'' URI=''/users''');

# Overlong subtype
--error ER_UNKNOWN_ERROR
execute immediate concat('create table t engine=CONNECT table_type=OEM module=''libname''
Option_list=''Myopt=foo'' subtype=''MYTYPE',REPEAT('1', 10000), '''');


# Overlong filename
--error ER_UNKNOWN_ERROR
execute immediate concat('create table t engine=CONNECT table_type=DBF file_name=''',
REPLACE(@@secure_file_priv,'\\','/'),'cust.dbf', REPEAT('1', 10000), '''');


# Format string in SRCDEF
--replace_result $MASTER_MYPORT MASTER_MYPORT
eval create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1,''%n'' FROM DUAL WHERE %s';
--error ER_GET_ERRMSG
select *from t;
drop table t;

--replace_result $MASTER_MYPORT MASTER_MYPORT
--error ER_UNKNOWN_ERROR
eval create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1,%n FROM DUAL WHERE %s';

--replace_result $MASTER_MYPORT MASTER_MYPORT
eval create table t engine=connect table_type=mysql
CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/foobar'
SRCDEF='SELECT 1 FROM DUAL WHERE %s';
select *from t;
drop table t;

write_file $MYSQLTEST_VARDIR/tmp/beer.xml;
<?xml version="1.0"?>
<Beers>
<table>
<th><td>Name</td><td>Origin</td><td>Description</td></th>
<tr>
<td><brandName>Huntsman</brandName></td>
<td><origin>Bath, UK</origin></td>
<td><details>Wonderful hop, light alcohol</details></td>
</tr>
<tr>
<td><brandName>Tuborg</brandName></td>
<td><origin>Danmark</origin></td>
<td><details>In small bottles</details></td>
</tr>
</table>
</Beers>
EOF

--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
# Format string in colnode
eval create table beers (
`Name` char(16) xpath='brandName',
`Origin` char(16) xpath='origin',
`Description` char(32) xpath='details')
engine=CONNECT table_type=XML file_name='$MYSQLTEST_VARDIR/tmp/beer.xml'
tabname='table' option_list='rownode=tr,colnode=td%n';
select * from beers;
drop table beers;

--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval create table beers (
`Name` char(16) xpath='brandName',
`Origin` char(16) xpath='origin',
`Description` char(32) xpath='details')
engine=CONNECT table_type=XML file_name='$MYSQLTEST_VARDIR/tmp/beer.xml'
tabname='table' option_list='rownode=tr,colnode=td';
insert into beers values('11','22','33');
drop table beers;

remove_file $MYSQLTEST_VARDIR/tmp/beer.xml;

write_file $MYSQLTEST_VARDIR/tmp/test.json;
[
{
"ISBN": "9782212090819",
"LANG": "fr",
"SUBJECT": "applications",
"AUTHOR": [
{
"FIRSTNAME": "Jean-Christophe",
"LASTNAME": "Bernadac"
},
{
"FIRSTNAME": "François",
"LASTNAME": "Knab"
}
],
"TITLE": "Construire une application XML",
"PUBLISHER": {
"NAME": "Eyrolles",
"PLACE": "Paris"
},
"DATEPUB": 1999
},
{
"ISBN": "9782840825685",
"LANG": "fr",
"SUBJECT": "applications",
"AUTHOR": [
{
"FIRSTNAME": "William J.",
"LASTNAME": "Pardi"
}
],
"TITLE": "XML en Action",
"TRANSLATED": {
"PREFIX": "adapté de l'anglais par",
"TRANSLATOR": {
"FIRSTNAME": "James",
"LASTNAME": "Guerin"
}
},
"PUBLISHER": {
"NAME": "Microsoft Press",
"PLACE": "Paris"
},
"DATEPUB": 1999
}
]
EOF

execute immediate CONCAT('create table jsampall
(Author char(128) jpath=''$.AUTHOR["', REPEAT('a',10000),'"]'')
engine=CONNECT table_type=JSON
file_name=''',REPLACE(@@secure_file_priv,'\\','/'),'tmp/test.json''');

select author from jsampall;
drop table jsampall;
remove_file $MYSQLTEST_VARDIR/tmp/test.json;

6 changes: 6 additions & 0 deletions storage/connect/plugutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath)
if (trace(2))
htrc("prefix=%s fn=%s path=%s\n", prefix, FileName, defpath);

if (strlen(FileName) >= _MAX_PATH)
{
*pBuff= 0; /* Hope this is treated as error of some kind*/
return FileName;
}

if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) {
strcpy(pBuff, FileName); // Remote file
return pBuff;
Expand Down
7 changes: 6 additions & 1 deletion storage/connect/reldef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info)
if (check_valid_path(module, strlen(module))) {
strcpy(g->Message, "Module cannot contain a path");
return NULL;
} else
}
else if (strlen(subtype)+1+3 >= sizeof(getname)) {
strcpy(g->Message, "Subtype string too long");
return NULL;
}
else
PlugSetPath(soname, module, GetPluginDir());

// The exported name is always in uppercase
Expand Down
2 changes: 1 addition & 1 deletion storage/connect/tabbson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1788,7 +1788,7 @@ bool BSONCOL::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s for %s", p, Name);
return true;
} // endif p

Expand Down
52 changes: 48 additions & 4 deletions storage/connect/tabext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,37 @@ int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
return 0;
} // end of Decode

/*
Count number of %s placeholders in string.
Returns -1 if other sprintf placeholders are found, .g %d
*/
static int count_placeholders(const char *fmt)
{
int cnt= 0;
for (const char *p=fmt; *p; p++)
{
if (*p == '%')
{
switch (p[1])
{
case 's':
/* %s found */
cnt++;
p++;
break;
case '%':
/* masking char for % found */
p++;
break;
default:
/* some other placeholder found */
return -1;
}
}
}
return cnt;
}

/***********************************************************************/
/* MakeSrcdef: make the SQL statement from SRDEF option. */
/***********************************************************************/
Expand All @@ -310,16 +341,29 @@ bool TDBEXT::MakeSrcdef(PGLOBAL g)
? To_CondFil->Having : PlugDup(g, "1=1");
} // endif ph

if (!stricmp(ph, "W")) {
int n_placeholders = count_placeholders(Srcdef);
if (n_placeholders < 0)
{
strcpy(g->Message, "MakeSQL: Wrong place holders specification");
return true;
}

if (!stricmp(ph, "W") && n_placeholders <= 1) {
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
} else if (!stricmp(ph, "WH")) {
}
else if (!stricmp(ph, "WH") && n_placeholders <= 2)
{
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
} else if (!stricmp(ph, "H")) {
}
else if (!stricmp(ph, "H") && n_placeholders <= 1)
{
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
} else if (!stricmp(ph, "HW")) {
}
else if (!stricmp(ph, "HW") && n_placeholders <= 2)
{
Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
} else {
Expand Down
2 changes: 1 addition & 1 deletion storage/connect/tabjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
p[--n] = 0;
} else if (!IsNum(p)) {
// Wrong array specification
sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
snprintf(g->Message, sizeof(g->Message), "Invalid array specification %s for %s", p, Name);
return true;
} // endif p

Expand Down
5 changes: 5 additions & 0 deletions storage/connect/tabmysql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,11 @@ bool TDBMYSQL::OpenDB(PGLOBAL g)
/*********************************************************************/
if (Mode == MODE_READ || Mode == MODE_READX) {
MakeSelect(g, Mode == MODE_READX);
if (Mode == MODE_READ && !Query)
{
Myc.Close();
return true;
}
m_Rc = (Mode == MODE_READ)
? Myc.ExecSQL(g, Query->GetStr()) : RC_OK;

Expand Down
10 changes: 7 additions & 3 deletions storage/connect/tabxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1511,9 +1511,13 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
if (!mode)
// Take care of an eventual extra column node a la html
if (Tdbp->Colname) {
sprintf(pbuf, Tdbp->Colname, Rank + ((Tdbp->Usedom) ? 0 : 1));
strcat(pbuf, "/");
} // endif Colname
char *p = strstr(Tdbp->Colname, "%d");
if (p)
snprintf(pbuf, len + 3, "%.*s%d%s/", (int) (p - Tdbp->Colname), Tdbp->Colname,
Rank + (Tdbp->Usedom ? 0 : 1), p + 2);
else
snprintf(pbuf, len + 3, "%s/", Tdbp->Colname);
} // endif Colname

if (Xname) {
if (Type == 2) {
Expand Down

0 comments on commit 2925d0f

Please sign in to comment.