Bug 18126 - libresolv res_init() does not correctly inititalize internals
Summary: libresolv res_init() does not correctly inititalize internals
Status: RESOLVED INVALID
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-14 13:51 UTC by Joshua Rogers
Modified: 2015-03-19 09:27 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joshua Rogers 2015-03-14 13:51:00 UTC
Contrary to what one would think, res_init() does not correctly inititialize the internals for further use by the libresolv family, and others.

When you call res_init(), it correctly "keeps" these:

        if (!_res.retrans)
                _res.retrans = RES_TIMEOUT;
        if (!_res.retry)
                _res.retry = 4;
        if (!(_res.options & RES_INIT))
                _res.options = RES_DEFAULT;
        else if (_res.nscount > 0)
                __res_iclose (&_res, true);     /* Close any VC sockets.  */


then calls __res_vinit():

        return (__res_vinit(&_res, 1));



However, programs that use the libresolv family and others, use the hidden function, "__res_maybe_init".

__res_maybe_init determines if res_init(__res_vinit()) needs to be called or not.

It does this:

        static time_t last_mtime;
        struct stat statbuf;
        int ret;

        if (resp->options & RES_INIT) {
                ret = stat (_PATH_RESCONF, &statbuf);
                __libc_lock_lock (lock);
                if ((ret == 0) && (last_mtime != statbuf.st_mtim.tv_sec)) {
                        last_mtime = statbuf.st_mtime;
                        atomicinc (__res_initstamp);
                }
                __libc_lock_unlock (lock);
                if (__res_initstamp != resp->_u._ext.initstamp) {
                        if (resp->nscount > 0)
                                __res_iclose (resp, true);
                        return __res_vinit (resp, 1);
                }
                return 0;


Since the internals have been initialized by res_init(), we don't need to reinitalize, normally. The program checks if we do need to reinitalize, such as due to the change in modifcation date of /etc/resolv.conf.

However, "last_mtime" is never set when using res_init(), so upon the first run of __res_maybe_init(), it will always run __res_vinit(). This will wipe all changes except for the ones that are kept, mentioned above.


"last_mtime" should be taken into consideration and handled, when calling res_init().
Comment 1 Joshua Rogers 2015-03-14 13:56:33 UTC
Sorry, 

if ((ret == 0) && (last_mtime != statbuf.st_mtim.tv_sec)) {

should be

if ((ret == 0) && (last_mtime != statbuf.st_mtime)) {
Comment 2 Joshua Rogers 2015-03-15 14:08:16 UTC
(for reference)
Only these are kept on res_init(), and thus are only kept with the first call to __res_maybe_init:
        int     retrans;                /* retransmition time interval */
        int     retry;                  /* number of times to retransmit */
        u_long  options;                /* option flags - see below. */



These are wiped, due to this bug:

        int     nscount;                /* number of name servers */
        struct sockaddr_in
                nsaddr_list[MAXNS];     /* address of name server */
# define nsaddr nsaddr_list[0]          /* for backward compatibility */
        u_short id;                     /* current message id */
        /* 2 byte hole here.  */
        char    *dnsrch[MAXDNSRCH+1];   /* components of domain to search */
        char    defdname[256];          /* default domain (deprecated) */
        u_long  pfcode;                 /* RES_PRF_ flags - see below. */
        unsigned ndots:4;               /* threshold for initial abs. query */
        unsigned nsort:4;               /* number of elements in sort_list[] */
        unsigned ipv6_unavail:1;        /* connecting to IPv6 server failed */
Comment 3 Joshua Rogers 2015-03-15 15:43:13 UTC
This bug is not in the latest respoistory, and is most likely Ubuntu-specific.

https://sourceware.org/git/?p=glibc.git;a=blob;f=resolv/res_libc.c;h=ee3fa2114b7051b86f6f9676f1151d1435dedb9d;hb=HEAD#l94

Reported here: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1432378