Comment 5 for bug 1565567

Revision history for this message
Rafael David Tinoco (rafaeldtinoco) wrote :

It was brought to my attention a crash just like this one. Here is my analsysis:

## INTRODUCTION

# From plugins/sudoers/pwutil.c:

/*
 * Get a password entry by uid and allocate space for it.
 */
struct passwd *
sudo_getpwuid(uid_t uid)
{
    struct cache_item key, *item;
    struct rbnode *node;
    debug_decl(sudo_getpwuid, SUDOERS_DEBUG_NSS)

    key.k.uid = uid;
    getauthregistry(IDtouser(uid), key.registry);
    if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
        item = node->data;
        sudo_debug_printf(SUDO_DEBUG_DEBUG,
            "%s: uid %u [%s] -> user %s [%s] (cache hit)", __func__,
            (unsigned int)uid, key.registry, item->d.pw->pw_name,
            item->registry);
        goto done;
    }

being the last frame in the debugger:

#0 0x00007fa01c0a6944 in sudo_getgrgid (gid=7241) at /build/sudo-g3ghsu/sudo-1.8.16/plugins/sudoers/pwutil.c:462
        key = {refcnt = 1275378544, registry = "\000V\000\000\330\f\005L\027V\000\000\000\000\000", k = {uid = 7241,
            gid = 7241, name = 0x28b4cb5700001c49 <error: Cannot access memory at address 0x28b4cb5700001c49>}, d = {
            pw = 0x7ffffd9d43d0, gr = 0x7ffffd9d43d0, grlist = 0x7ffffd9d43d0}}
        item = 0x56174c050700
        node = <optimized out>
        sudo_debug_subsys = 0
        __func__ = "sudo_getgrgid"

We can see that all local variables are accessible but an union:

/*
 * Generic cache element.
 */
struct cache_item {
    unsigned int refcnt;
    char registry[16];
    /* key */
    union {
        uid_t uid;
        gid_t gid;
        char *name;
    } k;
    /* datum */
    union {
        struct passwd *pw;
        struct group *gr;
        struct group_list *grlist;
    } d;
};

(gdb) print item
$35 = (struct cache_item *) 0x56174c050700

(gdb) print item->d
$36 = {pw = 0x0, gr = 0x0, grlist = 0x0}

The union pointer "d" could be either a struct passwd, a struct group or a struct group_list (union nature).

BUT, we can see that, from sudo_getpwuid, it is being used as a struct passwd (d.pw):

        sudo_debug_printf(SUDO_DEBUG_DEBUG,
            "%s: uid %u [%s] -> user %s [%s] (cache hit)", __func__,
            (unsigned int)uid, key.registry, item->d.pw->pw_name,
            item->registry);

Meaning that, probably, the password structure, for this user, wasn't filled in.

I can tell that because the "node" (from the tree) seems good:

    if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
        item = node->data;

(gdb) print item->k
$38 = {uid = 7241, gid = 7241, name = 0x1c49 ""}

since uid 7241 and gid 7241 seems reasonable.

But not the "item->d" union.

So we are only missing:

        struct passwd *pw;

From the node.

"struct passwd" is (from /usr/include/pwd.h):

/* The passwd structure. */
struct passwd
{
  char *pw_name; /* Username. */
  char *pw_passwd; /* Password. */
  __uid_t pw_uid; /* User ID. */
  __gid_t pw_gid; /* Group ID. */
  char *pw_gecos; /* Real name. */
  char *pw_dir; /* Home directory. */
  char *pw_shell; /* Shell program. */
};

And tells us that it is/was an easy way for the debug message to get username from uid.

Now, lets check when this struct should have been filled in:
item comes from "node->data", a generic redblack tree node.