FirebirdSQL / firebird

Firebird server, client and tools
https://firebirdsql.org
1.26k stars 217 forks source link

Invalid cache of field privileges in procedure request after their changes [CORE5108] #5392

Open firebird-automations opened 8 years ago

firebird-automations commented 8 years ago

Submitted by: @romansimakov

To reproduce it on SuperServer execute: ------------------------------------------------------- roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> create table t(i integer); SQL> insert into t values (1); SQL> commit; SQL> ^Droman:bin$ roman:bin$ ./gsec GSEC> add test -pw test GSEC> roman:bin$ roman:bin$ ./isql -user test -password test Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb', User: test SQL> set term ^; SQL> edit^ SQL> set term ;^ SQL> commit; SQL> show procedures; Procedure Name Invalid Dependency, Type ================================= ======= ===================================== P T, Table SQL> execute procedure p; Statement failed, SQLSTATE = 28000 no permission for update/write access to TABLE T SQL> ^Droman:bin$ roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> grant update(i) on t to test; SQL> commit; SQL> ^Droman:bin$ roman:bin$ ./isql -user test -password test Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb', User: test SQL> execute procedure p; Statement failed, SQLSTATE = 28000 no permission for update/write access to COLUMN T.I SQL> update t set i = 3; SQL> ^Droman:bin$ roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> select * from t;

       I

============ 3 ------------------------------------------------------- Procedure which is used in test case declared as: create procedure p as begin update t set i = 2; end

firebird-automations commented 8 years ago
Modified by: @romansimakov assignee: Roman Simakov \[ roman\-simakov \]
firebird-automations commented 8 years ago

Commented by: @romansimakov

When procedure is compiled fields use default security class, but after granting field level privileges their security classes are changed which cause to check relation security class instead of field security class. I suggest to make field security class permanent and generate them when field is defining like in patch:

Author: Roman Simakov <mailto:roman.simakov@gmail.com> Date: Fri Feb 5 16:43:56 2016 +0300

Fixed [CORE5108](https://github.com/FirebirdSQL/firebird/issues?q=CORE5108+in%3Atitle)\.

diff --git a/src/jrd/drq.h b/src/jrd/drq.h index f034ee9..f067998 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -219,6 +219,7 @@ const int drq_l_xcp_name = 165; // lookup exception name const int drq_l_gen_name = 166; // lookup generator name const int drq_e_grant3 = 167; // revoke all on all const int drq_s2_difference = 168; // Store backup difference file, DYN_mod's change_backup_mode -const int drq_MAX = 169; +const int drq_g_nxt_fsc_id = 169; // generate next field security class id +const int drq_MAX = 170;

⁠endif // JRD_DRQ_H

diff --git a/src/jrd/dyn_def.epp b/src/jrd/dyn_def.epp index 39bfc12..3bbca45 100644 --- a/src/jrd/dyn_def.epp +++ b/src/jrd/dyn_def.epp @@ -2761,6 +2761,14 @@ void DYN_define_local_field(Global* gbl, DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL); }

+ // If security class is not defined explicitly we generate it automatically + if (RFR.RDB$SECURITY_CLASS.NULL) + { + RFR.RDB$SECURITY_CLASS.NULL = FALSE; + sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, + DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_fsc_id, "RDB$SECURITY_CLASS")); + } + if (has_default && DYN_UTIL_is_array(tdbb, gbl, RFR.RDB$FIELD_SOURCE)) { DYN_error_punt(false, 226, RFR.RDB$FIELD_SOURCE); @@ -4050,6 +4058,10 @@ void DYN_define_sql_field(Global* gbl, RFR.RDB$DEFAULT_VALUE.NULL = TRUE; RFR.RDB$COLLATION_ID.NULL = TRUE;

+ RFR.RDB$SECURITY_CLASS.NULL = FALSE; + sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, + DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_fsc_id, "RDB$SECURITY_CLASS")); + old_request = request; const SSHORT old_id = id; request = CMP_find_request(tdbb, drq_s_sql_gfld, DYN_REQUESTS);

firebird-automations commented 7 years ago

Commented by: @romansimakov

https://github.com/FirebirdSQL/firebird/pull/81

I implemented another way to fix. If field level permissions were changed we reset metadata cache. I did not implement selection of procedures to reset which depend on changed field since it overhead which may not be good and cost about the same as restore metadata cache.