Bug 361 - visudo -c may enter endless loop due to mysteriously created duplicate sentinel node in redblack tree
visudo -c may enter endless loop due to mysteriously created duplicate sentin...
Status: RESOLVED FIXED
Product: Sudo
Classification: Unclassified
Component: Visudo
1.7.1
Other FreeBSD
: high high
Assigned To: Todd C. Miller
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2009-06-26 13:49 MDT by Jan Schaumann
Modified: 2009-07-28 14:24 MDT (History)
0 users

See Also:


Attachments
sudoers file triggering the problem (372 bytes, text/plain)
2009-06-26 13:49 MDT, Jan Schaumann
Details
patch to avoid touching the root node during fixup after deletion (532 bytes, patch)
2009-06-26 16:42 MDT, Todd C. Miller
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Schaumann 2009-06-26 13:49:42 MDT
Created attachment 259 [details]
sudoers file triggering the problem

If you run

visudo -q -c -f ./sudoers

on the attached sudoers file, visudo as of sudo-1.7.1 will enter an infinite loop.  This happens after

visudo.c::alias_remove_recursive

    a = alias_remove(name, type);
    if (a)
        rbinsert(alias_freelist, a)


in redblack.c::rbinsert


    while (node != rbnil(tree)) {
        parent = node;
        if ((res = tree->compar(data, node->data)) == 0)
            return(node);
        node = res < 0 ? node->left : node->right;
    }


For unknown reasons, the attached sudoers file appears to cause another sentinel node to get created, so that at this point the loop will continue:

After traversing the tree seemingly correctly for a while:

Run till exit from #0  alias_compare (v1=0x531580, v2=0x52e9a0) at
./alias.c:71
0x000000000040a933 in rbinsert (tree=0x522680, data=0x531580) at
./redblack.c:186
186     ./redblack.c: No such file or directory.
        in ./redblack.c
Value returned is $33 = 3


We get to a point, where:

186     in ./redblack.c
(gdb)
alias_compare (v1=0x531580, v2=0x0) at ./alias.c:67


Since we're looping until the node we're looking at is the "sentinel"
node initialized as

    /*
     * We use a self-referencing sentinel node called nil to simplify
     * the
     * code by avoiding the need to check for NULL pointers.
     */
    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
    tree->nil.color = black;
    tree->nil.data = NULL;


but somehow we ended up with a *different* self-referential node:

(gdb) p tree->nil
$48 = {left = 0x5226b0, right = 0x5226b0, parent = 0x5226b0, data = 0x0,
color = black}
(gdb) p node->left
$49 = (struct rbnode *) 0x522630
(gdb) p node->right
$50 = (struct rbnode *) 0x522630
(gdb) p node->parent
$51 = (struct rbnode *) 0x522630

this loop continues forever, since "alias_compare" will now always
return a negative value (data is NULL), and the node will use its left
child to continue looping.  Since its left child == itself == its
right child == parent, we never break the loop.


Now here's the kicker:  the order in which the statements in the sudoers file occur matter.  That is, if I shuffle any of the statements, this bug won't be triggered.


This bug was confirmed on FreeBSD 6.4 amd64 as well as Mac OS X (Darwin 9.7.0, intel).

This bug does not exist in sudo-1.7.0 (since the recursion on checking was introduced in 1.7.1).

The attached file contains obviously useless aliases -- however, I had a file with the exact same directives with more meaningful names and actual userlists that caused this.


The alphabetical and logical order in the file appears to be related to triggering this bug, so it's conceivable that somewhere down the line this has something to do with string comparison?
Comment 1 Todd C. Miller 2009-06-26 15:55:03 MDT
valgrind finds what appears to be a use after free bug using that sudoers file which may be related.
Comment 2 Todd C. Miller 2009-06-26 16:42:10 MDT
Created attachment 260 [details]
patch to avoid touching the root node during fixup after deletion
Comment 3 Todd C. Miller 2009-06-26 16:42:57 MDT
I've just committed the fix (see attachment) that will be in 1.7.2.
Comment 4 Jan Schaumann 2009-06-26 18:25:39 MDT
Confirmed that the suggested patch fixes the problem for me.
Thanks a lot for the very quick solution!
Comment 5 Todd C. Miller 2009-07-28 14:23:38 MDT
Fixed in sudo 1.7.2