From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> To: Chris Sosnin <k.sosnin@tarantool.org>, tarantool-patches@dev.tarantool.org Subject: Re: [Tarantool-patches] [PATCH] sql: remove grants associated with the table Date: Wed, 18 Dec 2019 00:13:12 +0100 [thread overview] Message-ID: <de9b91f5-8029-bc1a-51b4-a36b8627637b@tarantool.org> (raw) In-Reply-To: <20191211095008.90358-1-k.sosnin@tarantool.org> Hi! Thanks for the fixes! See N comments below, 2 my commits in the end, and on top of your branch. > Dropping table with sql removes everything > associated with it but grants, which is > inconsistent. Generating code for it fixes this bug. > > Closes #4546 > --- > branch: https://github.com/tarantool/tarantool/tree/ksosnin/gh-4546-sql-drop-grants > issue: https://github.com/tarantool/tarantool/issues/4546 > > src/box/sql/build.c | 47 +++++++++++++++++++++++ > src/box/user.cc | 7 ++++ > src/box/user.h | 4 ++ > test/sql/gh-4546-sql-drop-grants.result | 40 +++++++++++++++++++ > test/sql/gh-4546-sql-drop-grants.test.lua | 16 ++++++++ > 5 files changed, 114 insertions(+) > create mode 100644 test/sql/gh-4546-sql-drop-grants.result > create mode 100644 test/sql/gh-4546-sql-drop-grants.test.lua > > diff --git a/src/box/sql/build.c b/src/box/sql/build.c > index 51cd7ce63..af937de3b 100644 > --- a/src/box/sql/build.c > +++ b/src/box/sql/build.c > @@ -1523,6 +1524,42 @@ vdbe_emit_ck_constraint_drop(struct Parse *parser, const char *ck_name, > sqlReleaseTempRange(parser, key_reg, 3); > } > > +/** > + * Generate VDBE program to revoke all > + * privileges associated with the given object. > + * > + * @param parser Parsing context. > + * @param object_type Object type > + * @param object_id Object id > + * @param access Access array associated with an object > + */ > +static void > +vdbe_emit_revoke_object(struct Parse *parser, const char *object_type, > + uint32_t object_id, struct access access[]) > +{ > + struct Vdbe *v = sqlGetVdbe(parser); > + assert(v != NULL); > + /* > + * Get uid of users through access array > + * and generate code to delete corresponding > + * entries from _priv > + */ > + int key_reg = sqlGetTempRange(parser, 4); 1. I run some tests and appeared, that VdbeComment below asserts, when the object didn't have grants. I've fixed it in my commit. > + for (uint8_t token = 0; token < BOX_USER_MAX; ++token) { > + if (!access[token].granted) > + continue; > + const struct user *user = user_find_by_token(token); > + sqlVdbeAddOp2(v, OP_Integer, user->def->uid, key_reg); > + sqlVdbeAddOp4(v, OP_String8, 0, key_reg + 1, 0, > + object_type, P4_STATIC); > + sqlVdbeAddOp2(v, OP_Integer, object_id, key_reg + 2); > + sqlVdbeAddOp3(v, OP_MakeRecord, key_reg, 3, key_reg + 3); > + sqlVdbeAddOp2(v, OP_SDelete, BOX_PRIV_ID, key_reg + 3); > + } > + VdbeComment((v, "Remove %s grants", object_type)); > + sqlReleaseTempRange(parser, key_reg, 4); > +} > + > /** > * Generate code to drop a table. > * This routine includes dropping triggers, sequences, > @@ -1565,6 +1608,10 @@ sql_code_drop_table(struct Parse *parse_context, struct space *space, > sqlVdbeAddOp2(v, OP_Integer, space_id, space_id_reg); > sqlVdbeAddOp1(v, OP_CheckViewReferences, space_id_reg); > if (space->sequence != NULL) { > + /* Delete entries from _priv */ > + vdbe_emit_revoke_object(parse_context, "sequence", > + space->sequence->def->id, > + space->sequence->access); 2. I took a look at this code again, and realized, that sequence problem is more severe. This code deletes a sequence even if it does not belong to the space, i.e. was not generated automatically. I've fixed that in a separate commit. > /* Delete entry from _sequence_data. */ > int sequence_id_reg = ++parse_context->nMem; > sqlVdbeAddOp2(v, OP_Integer, space->sequence->def->id, > diff --git a/test/sql/gh-4546-sql-drop-grants.test.lua b/test/sql/gh-4546-sql-drop-grants.test.lua > new file mode 100644 > index 000000000..5ac4b5701 > --- /dev/null > +++ b/test/sql/gh-4546-sql-drop-grants.test.lua > @@ -0,0 +1,16 @@ > +test_run = require('test_run').new() > +engine = test_run:get_cfg('engine') 3. Engine is unused. To actually use it you need to give it to create_space() arguments. I've fixed it in my commit. > +box.execute('pragma sql_default_engine=\''..engine..'\'') 4. Since this test does not create spaces via SQL, this setting becomes not needed. I've drop it. > + > +-- If we drop the table with sql, all associated > +-- grants must be deleted so we don't recieve an error > + > +box.schema.user.create('test_user1') > +box.schema.user.create('test_user2') > +test_space = box.schema.create_space('T', {format = {{'i', 'integer'}}}) > +seq = box.schema.sequence.create('S') > +ind = test_space:create_index('I', {sequence = 'S'}) > +box.schema.user.grant('test_user1', 'write', 'sequence', 'S') > +box.schema.user.grant('test_user1', 'read', 'space', 'T') > +box.schema.user.grant('test_user2', 'write', 'space', 'T') > +box.execute([[DROP TABLE T;]]) 5. Test users are not dropped in the end of the test. I've fixed it in my commit. > -- > 2.21.0 (Apple Git-122.2) > See my 2 commits below. First is review fixes for your commit. Please, review it and squash if you agree with the fixes. Second commit is independent one. Please, review it, but do not squash. Instead, change author of the commit to yourself. If you have comments on the second commit - bring them up and lets discuss. If you agree with both commits, and you've done squash and the author change, then send for a second review to Nikita. First commit: =================================================================== commit 717ad6bbc382a798ef94d6a233e3b6464adc066b Author: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Tue Dec 17 23:13:40 2019 +0100 Review fixes diff --git a/src/box/sql/build.c b/src/box/sql/build.c index af937de3b..f1433645a 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -1529,13 +1529,13 @@ vdbe_emit_ck_constraint_drop(struct Parse *parser, const char *ck_name, * privileges associated with the given object. * * @param parser Parsing context. - * @param object_type Object type - * @param object_id Object id - * @param access Access array associated with an object + * @param object_type Object type. + * @param object_id Object id. + * @param access Access array associated with an object. */ static void vdbe_emit_revoke_object(struct Parse *parser, const char *object_type, - uint32_t object_id, struct access access[]) + uint32_t object_id, struct access *access) { struct Vdbe *v = sqlGetVdbe(parser); assert(v != NULL); @@ -1545,9 +1545,11 @@ vdbe_emit_revoke_object(struct Parse *parser, const char *object_type, * entries from _priv */ int key_reg = sqlGetTempRange(parser, 4); + bool had_grants = false; for (uint8_t token = 0; token < BOX_USER_MAX; ++token) { if (!access[token].granted) continue; + had_grants = true; const struct user *user = user_find_by_token(token); sqlVdbeAddOp2(v, OP_Integer, user->def->uid, key_reg); sqlVdbeAddOp4(v, OP_String8, 0, key_reg + 1, 0, @@ -1556,7 +1558,8 @@ vdbe_emit_revoke_object(struct Parse *parser, const char *object_type, sqlVdbeAddOp3(v, OP_MakeRecord, key_reg, 3, key_reg + 3); sqlVdbeAddOp2(v, OP_SDelete, BOX_PRIV_ID, key_reg + 3); } - VdbeComment((v, "Remove %s grants", object_type)); + if (had_grants) + VdbeComment((v, "Remove %s grants", object_type)); sqlReleaseTempRange(parser, key_reg, 4); } @@ -1608,10 +1611,6 @@ sql_code_drop_table(struct Parse *parse_context, struct space *space, sqlVdbeAddOp2(v, OP_Integer, space_id, space_id_reg); sqlVdbeAddOp1(v, OP_CheckViewReferences, space_id_reg); if (space->sequence != NULL) { - /* Delete entries from _priv */ - vdbe_emit_revoke_object(parse_context, "sequence", - space->sequence->def->id, - space->sequence->access); /* Delete entry from _sequence_data. */ int sequence_id_reg = ++parse_context->nMem; sqlVdbeAddOp2(v, OP_Integer, space->sequence->def->id, diff --git a/test/sql/gh-4546-sql-drop-grants.result b/test/sql/gh-4546-sql-drop-grants.result index ca95ed0f9..04d9ef172 100644 --- a/test/sql/gh-4546-sql-drop-grants.result +++ b/test/sql/gh-4546-sql-drop-grants.result @@ -4,19 +4,20 @@ test_run = require('test_run').new() engine = test_run:get_cfg('engine') --- ... -box.execute('pragma sql_default_engine=\''..engine..'\'') ---- -- row_count: 0 -... --- If we drop the table with sql, all associated --- grants must be deleted so we don't recieve an error +-- +-- gh-4546: DROP TABLE must delete all privileges given on that +-- table to any user. +-- box.schema.user.create('test_user1') --- ... box.schema.user.create('test_user2') --- ... -test_space = box.schema.create_space('T', {format = {{'i', 'integer'}}}) +test_space = box.schema.create_space('T', { \ + engine = engine, \ + format = {{'i', 'integer'}} \ +}) --- ... seq = box.schema.sequence.create('S') @@ -25,9 +26,6 @@ seq = box.schema.sequence.create('S') ind = test_space:create_index('I', {sequence = 'S'}) --- ... -box.schema.user.grant('test_user1', 'write', 'sequence', 'S') ---- -... box.schema.user.grant('test_user1', 'read', 'space', 'T') --- ... @@ -38,3 +36,13 @@ box.execute([[DROP TABLE T;]]) --- - row_count: 1 ... +box.schema.user.drop('test_user1') +--- +... +box.schema.user.drop('test_user2') +--- +... +box.space._sequence:select{} +--- +- [] +... diff --git a/test/sql/gh-4546-sql-drop-grants.test.lua b/test/sql/gh-4546-sql-drop-grants.test.lua index 5ac4b5701..966733718 100644 --- a/test/sql/gh-4546-sql-drop-grants.test.lua +++ b/test/sql/gh-4546-sql-drop-grants.test.lua @@ -1,16 +1,22 @@ test_run = require('test_run').new() engine = test_run:get_cfg('engine') -box.execute('pragma sql_default_engine=\''..engine..'\'') --- If we drop the table with sql, all associated --- grants must be deleted so we don't recieve an error +-- +-- gh-4546: DROP TABLE must delete all privileges given on that +-- table to any user. +-- box.schema.user.create('test_user1') box.schema.user.create('test_user2') -test_space = box.schema.create_space('T', {format = {{'i', 'integer'}}}) +test_space = box.schema.create_space('T', { \ + engine = engine, \ + format = {{'i', 'integer'}} \ +}) seq = box.schema.sequence.create('S') ind = test_space:create_index('I', {sequence = 'S'}) -box.schema.user.grant('test_user1', 'write', 'sequence', 'S') box.schema.user.grant('test_user1', 'read', 'space', 'T') box.schema.user.grant('test_user2', 'write', 'space', 'T') box.execute([[DROP TABLE T;]]) +box.schema.user.drop('test_user1') +box.schema.user.drop('test_user2') +box.space._sequence:select{} =================================================================== Second commit: =================================================================== commit 6550d9034dc5cce16f824379b28ce5abd138c6aa Author: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Tue Dec 17 23:59:00 2019 +0100 sql: drop only generated sequence in DROP TABLE It is possible to create a sequence manually, and give it to a newly created index as a source of unique identifiers. Such sequences are not owned by a space, and therefore shouldn't be deleted when the space is dropped. They are not dropped when space:drop() in Lua is called, but were dropped in SQL 'DROP TABLE' before this patch. Now Lua and SQL are consistent in that case. Follow up #4546 diff --git a/src/box/sql/build.c b/src/box/sql/build.c index f1433645a..93aae0894 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -1611,26 +1611,33 @@ sql_code_drop_table(struct Parse *parse_context, struct space *space, sqlVdbeAddOp2(v, OP_Integer, space_id, space_id_reg); sqlVdbeAddOp1(v, OP_CheckViewReferences, space_id_reg); if (space->sequence != NULL) { - /* Delete entry from _sequence_data. */ - int sequence_id_reg = ++parse_context->nMem; - sqlVdbeAddOp2(v, OP_Integer, space->sequence->def->id, - sequence_id_reg); - sqlVdbeAddOp3(v, OP_MakeRecord, sequence_id_reg, 1, - idx_rec_reg); - sqlVdbeAddOp2(v, OP_SDelete, BOX_SEQUENCE_DATA_ID, - idx_rec_reg); - VdbeComment((v, "Delete entry from _sequence_data")); /* Delete entry from _space_sequence. */ sqlVdbeAddOp3(v, OP_MakeRecord, space_id_reg, 1, idx_rec_reg); sqlVdbeAddOp2(v, OP_SDelete, BOX_SPACE_SEQUENCE_ID, idx_rec_reg); VdbeComment((v, "Delete entry from _space_sequence")); - /* Delete entry by id from _sequence. */ - sqlVdbeAddOp3(v, OP_MakeRecord, sequence_id_reg, 1, - idx_rec_reg); - sqlVdbeAddOp2(v, OP_SDelete, BOX_SEQUENCE_ID, idx_rec_reg); - VdbeComment((v, "Delete entry from _sequence")); + if (space->sequence->is_generated) { + /* Delete entry from _sequence_data. */ + int sequence_id_reg = ++parse_context->nMem; + sqlVdbeAddOp2(v, OP_Integer, space->sequence->def->id, + sequence_id_reg); + sqlVdbeAddOp3(v, OP_MakeRecord, sequence_id_reg, 1, + idx_rec_reg); + sqlVdbeAddOp2(v, OP_SDelete, BOX_SEQUENCE_DATA_ID, + idx_rec_reg); + VdbeComment((v, "Delete entry from _sequence_data")); + /* Delete entries from _priv */ + vdbe_emit_revoke_object(parse_context, "sequence", + space->sequence->def->id, + space->sequence->access); + /* Delete entry by id from _sequence. */ + sqlVdbeAddOp3(v, OP_MakeRecord, sequence_id_reg, 1, + idx_rec_reg); + sqlVdbeAddOp2(v, OP_SDelete, BOX_SEQUENCE_ID, + idx_rec_reg); + VdbeComment((v, "Delete entry from _sequence")); + } } /* Delete all child FK constraints. */ struct fk_constraint *child_fk; diff --git a/test/sql/autoincrement.result b/test/sql/autoincrement.result new file mode 100644 index 000000000..ca3d6f3cf --- /dev/null +++ b/test/sql/autoincrement.result @@ -0,0 +1,80 @@ +-- test-run result file version 2 +test_run = require('test_run').new() + | --- + | ... +engine = test_run:get_cfg('engine') + | --- + | ... + +-- +-- Not automatic sequence should not be removed by DROP TABLE. +-- +box.schema.user.create('user1') + | --- + | ... +test_space = box.schema.create_space('T', { \ + engine = engine, \ + format = {{'i', 'integer'}} \ +}) + | --- + | ... +seq = box.schema.sequence.create('S') + | --- + | ... +ind = test_space:create_index('I', {sequence = 'S'}) + | --- + | ... +box.schema.user.grant('user1', 'write', 'sequence', 'S') + | --- + | ... +box.execute('DROP TABLE t'); + | --- + | - row_count: 1 + | ... +seqs = box.space._sequence:select{} + | --- + | ... +#seqs == 1 and seqs[1].name == seq.name or seqs + | --- + | - true + | ... +seq:drop() + | --- + | ... + +-- +-- Automatic sequence should be removed at DROP TABLE, together +-- with all the grants. +-- +box.execute('CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)') + | --- + | - row_count: 1 + | ... +seqs = box.space._sequence:select{} + | --- + | ... +#seqs == 1 or seqs + | --- + | - true + | ... +seq = seqs[1].name + | --- + | ... +box.schema.user.grant('user1', 'write', 'sequence', seq) + | --- + | ... +box.execute('DROP TABLE t') + | --- + | - row_count: 1 + | ... +seqs = box.space._sequence:select{} + | --- + | ... +#seqs == 0 or seqs + | --- + | - true + | ... + +box.schema.user.drop('user1') + | --- + | ... diff --git a/test/sql/autoincrement.test.lua b/test/sql/autoincrement.test.lua new file mode 100644 index 000000000..63a902aea --- /dev/null +++ b/test/sql/autoincrement.test.lua @@ -0,0 +1,33 @@ +test_run = require('test_run').new() +engine = test_run:get_cfg('engine') + +-- +-- Not automatic sequence should not be removed by DROP TABLE. +-- +box.schema.user.create('user1') +test_space = box.schema.create_space('T', { \ + engine = engine, \ + format = {{'i', 'integer'}} \ +}) +seq = box.schema.sequence.create('S') +ind = test_space:create_index('I', {sequence = 'S'}) +box.schema.user.grant('user1', 'write', 'sequence', 'S') +box.execute('DROP TABLE t'); +seqs = box.space._sequence:select{} +#seqs == 1 and seqs[1].name == seq.name or seqs +seq:drop() + +-- +-- Automatic sequence should be removed at DROP TABLE, together +-- with all the grants. +-- +box.execute('CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)') +seqs = box.space._sequence:select{} +#seqs == 1 or seqs +seq = seqs[1].name +box.schema.user.grant('user1', 'write', 'sequence', seq) +box.execute('DROP TABLE t') +seqs = box.space._sequence:select{} +#seqs == 0 or seqs + +box.schema.user.drop('user1') diff --git a/test/sql/gh-4546-sql-drop-grants.result b/test/sql/gh-4546-sql-drop-grants.result index 04d9ef172..3ba26e380 100644 --- a/test/sql/gh-4546-sql-drop-grants.result +++ b/test/sql/gh-4546-sql-drop-grants.result @@ -42,7 +42,10 @@ box.schema.user.drop('test_user1') box.schema.user.drop('test_user2') --- ... -box.space._sequence:select{} +seqs = box.space._sequence:select{} --- -- [] +... +#seqs == 1 and seqs[1].name == seq.name or seqs +--- +- true ... diff --git a/test/sql/gh-4546-sql-drop-grants.test.lua b/test/sql/gh-4546-sql-drop-grants.test.lua index 966733718..fc2c27e08 100644 --- a/test/sql/gh-4546-sql-drop-grants.test.lua +++ b/test/sql/gh-4546-sql-drop-grants.test.lua @@ -19,4 +19,5 @@ box.schema.user.grant('test_user2', 'write', 'space', 'T') box.execute([[DROP TABLE T;]]) box.schema.user.drop('test_user1') box.schema.user.drop('test_user2') -box.space._sequence:select{} +seqs = box.space._sequence:select{} +#seqs == 1 and seqs[1].name == seq.name or seqs
next prev parent reply other threads:[~2019-12-17 23:13 UTC|newest] Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-12-06 12:53 Chris Sosnin 2019-12-07 10:29 ` Chris Sosnin 2019-12-10 23:45 ` Vladislav Shpilevoy 2019-12-11 9:50 ` Chris Sosnin 2019-12-17 23:13 ` Vladislav Shpilevoy [this message] 2019-12-17 23:13 ` Vladislav Shpilevoy 2019-12-18 11:00 ` [Tarantool-patches] [PATCH 0/2] sql: revoke table privileges on drop Chris Sosnin 2019-12-18 11:00 ` [Tarantool-patches] [PATCH 1/2] sql: remove grants associated with the table Chris Sosnin 2019-12-24 1:37 ` Nikita Pettik 2019-12-24 16:47 ` Vladislav Shpilevoy 2019-12-18 11:00 ` [Tarantool-patches] [PATCH 2/2] sql: drop only generated sequence in DROP TABLE Chris Sosnin 2019-12-24 1:23 ` Nikita Pettik 2019-12-24 16:26 ` Vladislav Shpilevoy 2019-12-24 23:19 ` Nikita Pettik
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=de9b91f5-8029-bc1a-51b4-a36b8627637b@tarantool.org \ --to=v.shpilevoy@tarantool.org \ --cc=k.sosnin@tarantool.org \ --cc=tarantool-patches@dev.tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH] sql: remove grants associated with the table' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox