Re: Missing warning on revokes with grant options - Mailing list pgsql-hackers

From Joseph Koshakow
Subject Re: Missing warning on revokes with grant options
Date
Msg-id CAAvxfHdeEoYheEmrjqwCrxC8px1JTWAR-9z6ueywRXEjwmVJVA@mail.gmail.com
Whole thread Raw
In response to Re: Missing warning on revokes with grant options  (Joseph Koshakow <koshy44@gmail.com>)
Responses Re: Missing warning on revokes with grant options
List pgsql-hackers
On Thu, May 18, 2023 at 7:17 PM Joseph Koshakow <koshy44@gmail.com> wrote:
>
>    I looked into this function and that is correct. We fail to find a
>    match for the revoked privilege here:
>
>    /*
>    * Search the ACL for an existing entry for this grantee and grantor. If
>    * one exists, just modify the entry in-place (well, in the same position,
>    * since we actually return a copy); otherwise, insert the new entry at
>    * the end.
>    */
>
>    for (dst = 0; dst < num; ++dst)
>    {
>    if (aclitem_match(mod_aip, old_aip + dst))
>    {
>    /* found a match, so modify existing item */
>    new_acl = allocacl(num);
>    new_aip = ACL_DAT(new_acl);
>    memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
>    break;
>    }
>    }
>
>    Seeing that there was no match, we add a new empty privilege to the end
>    of the existing ACL list here:
>
>    if (dst == num)
>    {
>    /* need to append a new item */
>    new_acl = allocacl(num + 1);
>    new_aip = ACL_DAT(new_acl);
>    memcpy(new_aip, old_aip, num * sizeof(AclItem));
>
>    /* initialize the new entry with no permissions */
>    new_aip[dst].ai_grantee = mod_aip->ai_grantee;
>    new_aip[dst].ai_grantor = mod_aip->ai_grantor;
>    ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
>      ACL_NO_RIGHTS, ACL_NO_RIGHTS);
>    num++; /* set num to the size of new_acl */
>    }
>
>    We then try and revoke the specified privileges from the new empty
>    privilege, leaving it empty (modechg will equal ACL_MODECHG_DEL here):
>
>    old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
>    old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
>
>    /* apply the specified permissions change */
>    switch (modechg)
>    {
>    case ACL_MODECHG_ADD:
>    ACLITEM_SET_RIGHTS(new_aip[dst],
>      old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
>    break;
>    case ACL_MODECHG_DEL:
>    ACLITEM_SET_RIGHTS(new_aip[dst],
>      old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
>    break;
>    case ACL_MODECHG_EQL:
>    ACLITEM_SET_RIGHTS(new_aip[dst],
>      ACLITEM_GET_RIGHTS(*mod_aip));
>    break;
>    }
>
>    Then since the new privilege remains empty, we remove it from the ACL
>    list:
>
>    new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
>    new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
>
>    /*
>    * If the adjusted entry has no permissions, delete it from the list.
>    */
>    if (new_rights == ACL_NO_RIGHTS)
>    {
>    memmove(new_aip + dst,
>    new_aip + dst + 1,
>    (num - dst - 1) * sizeof(AclItem));
>    /* Adjust array size to be 'num - 1' items */
>    ARR_DIMS(new_acl)[0] = num - 1;
>    SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
>    }

Sorry about the unformatted code, here's the entire quoted section
again with proper formatting:

I looked into this function and that is correct. We fail to find a
match for the revoked privilege here:

    /*
     * Search the ACL for an existing entry for this grantee and grantor. If
     * one exists, just modify the entry in-place (well, in the same position,
     * since we actually return a copy); otherwise, insert the new entry at
     * the end.
     */

    for (dst = 0; dst < num; ++dst)
    {
        if (aclitem_match(mod_aip, old_aip + dst))
        {
            /* found a match, so modify existing item */
            new_acl = allocacl(num);
            new_aip = ACL_DAT(new_acl);
            memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
            break;
        }
    }

Seeing that there was no match, we add a new empty privilege to the end
of the existing ACL list here:

    if (dst == num)
    {
        /* need to append a new item */
        new_acl = allocacl(num + 1);
        new_aip = ACL_DAT(new_acl);
        memcpy(new_aip, old_aip, num * sizeof(AclItem));

        /* initialize the new entry with no permissions */
        new_aip[dst].ai_grantee = mod_aip->ai_grantee;
        new_aip[dst].ai_grantor = mod_aip->ai_grantor;
        ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
                                   ACL_NO_RIGHTS, ACL_NO_RIGHTS);
        num++;                    /* set num to the size of new_acl */
    }

We then try and revoke the specified privileges from the new empty
privilege, leaving it empty (modechg will equal ACL_MODECHG_DEL here):

    old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
    old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);

    /* apply the specified permissions change */
    switch (modechg)
    {
        case ACL_MODECHG_ADD:
            ACLITEM_SET_RIGHTS(new_aip[dst],
                               old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
            break;
        case ACL_MODECHG_DEL:
            ACLITEM_SET_RIGHTS(new_aip[dst],
                               old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
            break;
        case ACL_MODECHG_EQL:
            ACLITEM_SET_RIGHTS(new_aip[dst],
                               ACLITEM_GET_RIGHTS(*mod_aip));
            break;
    }

Then since the new privilege remains empty, we remove it from the ACL
list:

    new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
    new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);

    /*
     * If the adjusted entry has no permissions, delete it from the list.
     */
    if (new_rights == ACL_NO_RIGHTS)
    {
        memmove(new_aip + dst,
                new_aip + dst + 1,
                (num - dst - 1) * sizeof(AclItem));
        /* Adjust array size to be 'num - 1' items */
        ARR_DIMS(new_acl)[0] = num - 1;
        SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
    }

Thanks,
Joe Koshakow

pgsql-hackers by date:

Previous
From: Joseph Koshakow
Date:
Subject: Re: Missing warning on revokes with grant options
Next
From: Matthias van de Meent
Date:
Subject: Re: PG 16 draft release notes ready