# UNDF: UNDF-2026-000000175 --- a/sql/auth/sql_authorization.cc +++ b/sql/auth/sql_authorization.cc @@ -4875,16 +4875,26 @@ mysql_show_grants(THD *thd, LEX_USER *lex_user, if (have_using_clause) { std::vector mandatory_roles; get_mandatory_roles(&mandatory_roles); List_of_granted_roles granted_roles; get_granted_roles(lex_user, &granted_roles); - for (auto &role_ref : using_roles) { - std::string authid(create_authid_str_from(role_ref)); - if (find(granted_roles.begin(), granted_roles.end(), authid) == - granted_roles.end()) { - if (std::find_if(mandatory_roles.begin(), mandatory_roles.end(), - [&](const Role_id &id) -> bool { - std::string id_str, rid_str; - id.auth_str(&id_str); - Role_id rid(role_ref.first, role_ref.second); - rid.auth_str(&rid_str); - return (Role_id(role_ref.first, role_ref.second) == - id); - }) == mandatory_roles.end()) { + // CWE-407 fix (mysql-0001): build O(1) lookup sets before the loop so + // membership checks are not O(G) and O(M) per using_role element. + std::unordered_set granted_set; + for (const auto &gr : granted_roles) { + granted_set.insert(gr.first); // gr.first is the authid string + } + std::unordered_set mandatory_set; + for (const auto &rid : mandatory_roles) { + std::string s; + rid.auth_str(&s); + mandatory_set.insert(s); + } + for (auto &role_ref : using_roles) { + std::string authid(create_authid_str_from(role_ref)); + if (granted_set.find(authid) == granted_set.end()) { + std::string rid_str; + Role_id(role_ref.first, role_ref.second).auth_str(&rid_str); + if (mandatory_set.find(rid_str) == mandatory_set.end()) { my_error(ER_ROLE_NOT_GRANTED, MYF(0), role_ref.first.str, role_ref.second.str, lex_user->user.str, lex_user->host.str); return true; } } } }