• Vicențiu Ciorbaru's avatar
    MDEV-12366: FLUSH PRIVILEGES can break hierarchy of roles · be758322
    Vicențiu Ciorbaru authored
    Whenever we call merge_role_privileges on a role, we make use of
    the role->counter variable to check if all it's children have had their
    privileges merged. Only if all children have had their privileges merged,
    do we update the privileges on parent. This is done to prevent extra work.
    The same idea is employed during flush privileges. You only begin merging
    from "leaf" roles. The recursive calls will merge their parents at some point.
    A problem arises when we try to "re-merge" a parent. Take the following graph:
    
    {noformat}
         A (0)  ----  C (2) ---- D (2)  ---- USER
                     /          /
         B (0)  ----/          /
                              /
         E (0) --------------/
    {noformat}
    
    In parentheses we have the "counter" value right before we start to iterate
    through the roles hash and propagate values. It represents the number of roles
    granted to the current role. The order in which we iterate through the roles
    hash is alphabetical.
    
    * First merge A, which leads to decreasing the counter for C to 1. Since C is
    not 0, we don't proceed with merging into C.
    
    * Second we merge B, which leads to decreasing the counter for C to 0. Now
    we proceed with merging into C. This leads to reducing the counter for D to 1
    as part of C merge process.
    
    * Third as we iterate through the hash, we see that C has counter 0, thus we
    start the merge process *again*. This leads to reducing the counter for
    D to 0! We then attempt to merge D.
    
    * Fourth we start merging E. When E sees D as it's parent (according to the code)
    it attempts to reduce D's counter, which leads to overflow. Now D's counter is
    a very large number, thus E's privileges are not forwarded to D yet.
    
    To correct this behavior we must make sure to only start merging from initial
    leaf nodes.
    be758322
flush_roles-12366.result 12.6 KB