Skip to content
  • Nisha Gopalakrishnan's avatar
    05824063
    BUG#28438114: SET READ_ONLY=1 SOMETIMES DOESN'T BLOCK CONCURRENT DDL. · 05824063
    Nisha Gopalakrishnan authored
    Analysis
    ========
    SET READ_ONLY=1/SUPER_READ_ONLY = 1 under certain conditions does not
    block concurrent DDL executed by users without SUPER privileges. Consider
    the following scenario:
    
    connection 1(SUPER user)
    FLUSH TABLES WITH READ LOCK;
    
    connection 2:(Non SUPER user)
    CREATE TABLE t1 (fld1 INT); ---> Waits for GRL
    
    connection 3: (SUPER user)
    SET READ_ONLY=1; --> Succeeds
    
    connection 1(SUPER user)
    UNLOCK TABLES; --> Unblocks connection 2.
    
    CREATE TABLE tries to acquire IX in the GLOBAL namespace and is blocked
    because of the SHARED lock GLOBAL namespace  held by FLUSH TABLES.
    SET READ_ONLY succeeds because the SHARED lock in GLOBAL and COMMIT
    namespace is granted. UNLOCK TABLES then releases the GRL held by
    FLUSH TABLES, which causes the the CREATE TABLE statement to resume
    without checking for the read_only state. Thus the CREATE TABLE statement
    succeeds even though the read_only has been enabled.
    
    This is a typical race condition situation where DDL checks 'read only' flag
    before acquiring IX lock in the GLOBAL namespace which protects from this flag
    being changed concurrently.
    
    This problem doesn't affect DML operations as there is an additional check for
    'read_only' flag for such statements in mysql_lock_tables() (i.e. when IX lock
    in the GLOBAL namespace already has been acquired).
    
    Please note that this problem is less prominent in 8.0, where it affects only DDL
    which doesn't update any user or system table (for example, "DROP TABLE IF EXISTS
    no_such_table").
    
    Fix
    ===
    The read_only state is checked after the IX lock is acquired in the GLOBAL
    namespace in the following functions: lock_schema_name(), lock_tablespace_name()
    and lock_table_names() which provides protection against concurrent modification
    of the 'read_only' flag.
    
    Change-Id: I49a45aa627972d55e11b348bc2f5e5714215eae3
    05824063
    BUG#28438114: SET READ_ONLY=1 SOMETIMES DOESN'T BLOCK CONCURRENT DDL.
    Nisha Gopalakrishnan authored
    Analysis
    ========
    SET READ_ONLY=1/SUPER_READ_ONLY = 1 under certain conditions does not
    block concurrent DDL executed by users without SUPER privileges. Consider
    the following scenario:
    
    connection 1(SUPER user)
    FLUSH TABLES WITH READ LOCK;
    
    connection 2:(Non SUPER user)
    CREATE TABLE t1 (fld1 INT); ---> Waits for GRL
    
    connection 3: (SUPER user)
    SET READ_ONLY=1; --> Succeeds
    
    connection 1(SUPER user)
    UNLOCK TABLES; --> Unblocks connection 2.
    
    CREATE TABLE tries to acquire IX in the GLOBAL namespace and is blocked
    because of the SHARED lock GLOBAL namespace  held by FLUSH TABLES.
    SET READ_ONLY succeeds because the SHARED lock in GLOBAL and COMMIT
    namespace is granted. UNLOCK TABLES then releases the GRL held by
    FLUSH TABLES, which causes the the CREATE TABLE statement to resume
    without checking for the read_only state. Thus the CREATE TABLE statement
    succeeds even though the read_only has been enabled.
    
    This is a typical race condition situation where DDL checks 'read only' flag
    before acquiring IX lock in the GLOBAL namespace which protects from this flag
    being changed concurrently.
    
    This problem doesn't affect DML operations as there is an additional check for
    'read_only' flag for such statements in mysql_lock_tables() (i.e. when IX lock
    in the GLOBAL namespace already has been acquired).
    
    Please note that this problem is less prominent in 8.0, where it affects only DDL
    which doesn't update any user or system table (for example, "DROP TABLE IF EXISTS
    no_such_table").
    
    Fix
    ===
    The read_only state is checked after the IX lock is acquired in the GLOBAL
    namespace in the following functions: lock_schema_name(), lock_tablespace_name()
    and lock_table_names() which provides protection against concurrent modification
    of the 'read_only' flag.
    
    Change-Id: I49a45aa627972d55e11b348bc2f5e5714215eae3
Loading