Skip to content

Commit acc4fbb

Browse files
committed
Bug#18790730 - CROSS-DATABASE FOREIGN KEY WITHOUT PERMISSIONS
CHECK. Merging from 5.6 to trunk.
2 parents 3433268 + cf4231a commit acc4fbb

File tree

5 files changed

+135
-2
lines changed

5 files changed

+135
-2
lines changed

sql/handler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,8 @@ struct handlerton
999999
*/
10001000

10011001
#define HTON_SUPPORTS_EXTENDED_KEYS (1 << 10)
1002+
// Engine supports foreign key constraint.
1003+
#define HTON_SUPPORTS_FOREIGN_KEYS (1 << 11)
10021004

10031005

10041006
enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,

sql/sql_parse.cc

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5751,6 +5751,118 @@ bool check_global_access(THD *thd, ulong want_access)
57515751
#endif
57525752
}
57535753

5754+
5755+
/**
5756+
Checks foreign key's parent table access.
5757+
5758+
@param thd [in] Thread handler
5759+
@param create_info [in] Create information (like MAX_ROWS, ENGINE or
5760+
temporary table flag)
5761+
@param alter_info [in] Initial list of columns and indexes for the
5762+
table to be created
5763+
5764+
@retval
5765+
false ok.
5766+
@retval
5767+
true error or access denied. Error is sent to client in this case.
5768+
*/
5769+
bool check_fk_parent_table_access(THD *thd,
5770+
HA_CREATE_INFO *create_info,
5771+
Alter_info *alter_info)
5772+
{
5773+
Key *key;
5774+
List_iterator<Key> key_iterator(alter_info->key_list);
5775+
handlerton *db_type= create_info->db_type ? create_info->db_type :
5776+
ha_default_handlerton(thd);
5777+
5778+
// Return if engine does not support Foreign key Constraint.
5779+
if (!ha_check_storage_engine_flag(db_type, HTON_SUPPORTS_FOREIGN_KEYS))
5780+
return false;
5781+
5782+
while ((key= key_iterator++))
5783+
{
5784+
if (key->type == Key::FOREIGN_KEY)
5785+
{
5786+
TABLE_LIST parent_table;
5787+
bool is_qualified_table_name;
5788+
Foreign_key *fk_key= (Foreign_key *)key;
5789+
LEX_STRING db_name;
5790+
LEX_STRING table_name= { fk_key->ref_table.str,
5791+
fk_key->ref_table.length };
5792+
const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL |
5793+
DELETE_ACL | REFERENCES_ACL);
5794+
5795+
// Check if tablename is valid or not.
5796+
DBUG_ASSERT(table_name.str != NULL);
5797+
if (check_table_name(table_name.str, table_name.length, false))
5798+
{
5799+
my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
5800+
return true;
5801+
}
5802+
5803+
if (fk_key->ref_db.str)
5804+
{
5805+
is_qualified_table_name= true;
5806+
db_name.str= (char *) thd->memdup(fk_key->ref_db.str,
5807+
fk_key->ref_db.length+1);
5808+
db_name.length= fk_key->ref_db.length;
5809+
5810+
// Check if database name is valid or not.
5811+
if (fk_key->ref_db.str && check_and_convert_db_name(&db_name, false))
5812+
return true;
5813+
}
5814+
else if (thd->lex->copy_db_to(&db_name.str, &db_name.length))
5815+
return true;
5816+
else
5817+
is_qualified_table_name= false;
5818+
5819+
// if lower_case_table_names is set then convert tablename to lower case.
5820+
if (lower_case_table_names)
5821+
{
5822+
table_name.str= (char *) thd->memdup(fk_key->ref_table.str,
5823+
fk_key->ref_table.length+1);
5824+
table_name.length= my_casedn_str(files_charset_info, table_name.str);
5825+
}
5826+
5827+
parent_table.init_one_table(db_name.str, db_name.length,
5828+
table_name.str, table_name.length,
5829+
table_name.str, TL_IGNORE);
5830+
5831+
/*
5832+
Check if user has any of the "privileges" at table level on
5833+
"parent_table".
5834+
Having privilege on any of the parent_table column is not
5835+
enough so checking whether user has any of the "privileges"
5836+
at table level only here.
5837+
*/
5838+
if (check_some_access(thd, privileges, &parent_table) ||
5839+
parent_table.grant.want_privilege)
5840+
{
5841+
if (is_qualified_table_name)
5842+
{
5843+
const size_t qualified_table_name_len= NAME_LEN + 1 + NAME_LEN + 1;
5844+
char *qualified_table_name= (char *) thd->alloc(qualified_table_name_len);
5845+
5846+
my_snprintf(qualified_table_name, qualified_table_name_len, "%s.%s",
5847+
db_name.str, table_name.str);
5848+
table_name.str= qualified_table_name;
5849+
}
5850+
5851+
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
5852+
"REFERENCES",
5853+
thd->security_ctx->priv_user,
5854+
thd->security_ctx->host_or_ip,
5855+
table_name.str);
5856+
5857+
return true;
5858+
}
5859+
}
5860+
}
5861+
5862+
return false;
5863+
}
5864+
5865+
57545866
/****************************************************************************
57555867
Check stack size; Send error if there isn't enough stack to continue
57565868
****************************************************************************/
@@ -7803,8 +7915,11 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
78037915
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
78047916
goto err;
78057917
}
7806-
error= FALSE;
78077918

7919+
if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info))
7920+
goto err;
7921+
7922+
error= FALSE;
78087923
err:
78097924
DBUG_RETURN(error);
78107925
}

sql/sql_parse.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables);
4949
bool insert_precheck(THD *thd, TABLE_LIST *tables);
5050
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
5151
TABLE_LIST *create_table);
52+
bool check_fk_parent_table_access(THD *thd,
53+
HA_CREATE_INFO *create_info,
54+
Alter_info *alter_info);
5255

5356
bool parse_sql(THD *thd,
5457
Parser_state *parser_state,

sql/sql_table.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7996,6 +7996,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
79967996
DBUG_RETURN(true);
79977997
}
79987998

7999+
/*
8000+
If foreign key is added then check permission to access parent table.
8001+
8002+
In function "check_fk_parent_table_access", create_info->db_type is used
8003+
to identify whether engine supports FK constraint or not. Since
8004+
create_info->db_type is set here, check to parent table access is delayed
8005+
till this point for the alter operation.
8006+
*/
8007+
if ((alter_info->flags & Alter_info::ADD_FOREIGN_KEY) &&
8008+
check_fk_parent_table_access(thd, create_info, alter_info))
8009+
DBUG_RETURN(true);
8010+
79998011
/*
80008012
If this is an ALTER TABLE and no explicit row type specified reuse
80018013
the table's row type.

storage/innobase/handler/ha_innodb.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2828,7 +2828,8 @@ innobase_init(
28282828

28292829
innobase_hton->flush_logs = innobase_flush_logs;
28302830
innobase_hton->show_status = innobase_show_status;
2831-
innobase_hton->flags = HTON_SUPPORTS_EXTENDED_KEYS;
2831+
innobase_hton->flags =
2832+
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS;
28322833

28332834
innobase_hton->release_temporary_latches =
28342835
innobase_release_temporary_latches;

0 commit comments

Comments
 (0)