libresolv res_init() does not correctly inititalize internals
| Affects | Status | Importance | Assigned to | Milestone | |
|---|---|---|---|---|---|
| | glibc (Ubuntu) |
Undecided
|
Unassigned | ||
Bug Description
As reported here: https:/
The bug, however, is not in the sourceware sourcecode, but in the Ubuntu one.
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)
if (!_res.retry)
if (!(_res.options & RES_INIT))
else if (_res.nscount > 0)
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(
It does this:
static time_t last_mtime;
struct stat statbuf;
int ret;
if (resp->options & RES_INIT) {
ret = stat (_PATH_RESCONF, &statbuf);
if ((ret == 0) && (last_mtime != statbuf.st_mtime)) {
}
if (__res_initstamp != resp->_
}
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().
(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
# define nsaddr nsaddr_list[0] /* for backward compatibility */
u_short id; /* current message id */
/* 2 byte hole here. */
char *dnsrch[
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 */
| Joshua Rogers (megamansec) wrote : | #1 |
This bug is missing log files that will aid in diagnosing the problem. From a terminal window please run:
apport-collect 1432378
and then change the status of the bug to 'Confirmed'.
If, due to the nature of the issue you have encountered, you are unable to run this command, please add a comment stating that fact and change the bug status to 'Confirmed'.
This change has been made by an automated script, maintained by the Ubuntu Kernel Team.
| Changed in linux (Ubuntu): | |
| status: | New → Incomplete |
| Joshua Rogers (megamansec) wrote : | #3 |
No logs required.
| Changed in linux (Ubuntu): | |
| status: | Incomplete → Confirmed |
| affects: | linux (Ubuntu) → glibc (Ubuntu) |
| Joshua Rogers (megamansec) wrote : | #4 |
tl;dr:
res_init() does not correctly initialize the _res struct.
The code:
res_init();
} else {
}
outputs "RES_INIT set." correctly, and that bit is set. res_init() does all of its setting through res_init.c, https:/
That's all fine and dandy. -- (The actual resetting happens through the function __res_vinit())
However, res_init() neglects to set things that the ubuntu-specific eglibc requires for it to be a valid struct, such as the last modified time of /etc/resolv.conf -- "last_mtime".
Thus, the first call to res_query() resets the _res struct, effectively making any changes before it and after the original res_init(), useless.
As we can see in res_data.c, https:/
In the comments for that __res_maybe_init() function:
/* Initialize resp if RES_INIT is not yet set or if res_init in some other
thread requested re-initializing. */
On the first run of __res_maybe_
>>>>>> if ((ret == 0) && (last_mtime != statbuf.st_mtime)) { <<<<<<<
}
if (__res_initstamp != resp->_
}
even shorter tl;dr:
'last_mtime' is an ubuntu-specific feature added to eglibc's resolv library, which is only set inside the __res_maybe_init() function.
When calling res_init(), it does not set 'last_mtime', as that uses __res_vinit(), not __res_maybe_init().
When calling res_query() for the first time, all the changes made to the _res struct are wiped, with the exception of int retrans, int retry, u_long options. This is because res_query uses __res_maybe_init(), which will reset _res if 'last_mtime' has not been set(or is old)
A quick fix is to replace __res_vinit()'s usage within the res_query() function with __res_maybe_init(), which takes the exact same parameters.
| Joshua Rogers (megamansec) wrote : | #5 |
The bug has been present since what looks like 2006...
http://
It's probably present in Debian too: http://


Link to the eglibc file that Ubuntu uses: http:// www.eglibc. org/cgi- bin/viewvc. cgi/branches/ eglibc- 2_19/libc/ resolv/ res_libc. c?view= markup