Commit 3f7483e8 authored by Simon Kelley's avatar Simon Kelley

Handle integer overflow in uid counter. Fixes rare crashes in cache code.

parent 0c8584ea
...@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL; ...@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error; static int cache_inserted = 0, cache_live_freed = 0, insert_error;
static union bigname *big_free = NULL; static union bigname *big_free = NULL;
static int bignames_left, hash_size; static int bignames_left, hash_size;
static int uid = 1;
/* type->string mapping: this is also used by the name-hash function as a mixing table. */ /* type->string mapping: this is also used by the name-hash function as a mixing table. */
static const struct { static const struct {
...@@ -73,6 +72,17 @@ static void cache_link(struct crec *crecp); ...@@ -73,6 +72,17 @@ static void cache_link(struct crec *crecp);
static void rehash(int size); static void rehash(int size);
static void cache_hash(struct crec *crecp); static void cache_hash(struct crec *crecp);
static unsigned int next_uid(void)
{
static unsigned int uid = 1;
/* uid == 0 used to indicate CNAME to interface name. */
if (uid == 0)
uid++;
return uid++;
}
void cache_init(void) void cache_init(void)
{ {
struct crec *crecp; struct crec *crecp;
...@@ -88,7 +98,7 @@ void cache_init(void) ...@@ -88,7 +98,7 @@ void cache_init(void)
{ {
cache_link(crecp); cache_link(crecp);
crecp->flags = 0; crecp->flags = 0;
crecp->uid = uid++; crecp->uid = next_uid();
} }
} }
...@@ -192,10 +202,7 @@ static void cache_free(struct crec *crecp) ...@@ -192,10 +202,7 @@ static void cache_free(struct crec *crecp)
{ {
crecp->flags &= ~F_FORWARD; crecp->flags &= ~F_FORWARD;
crecp->flags &= ~F_REVERSE; crecp->flags &= ~F_REVERSE;
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
if (uid == -1)
uid++;
if (cache_tail) if (cache_tail)
cache_tail->next = crecp; cache_tail->next = crecp;
...@@ -256,7 +263,7 @@ char *cache_get_name(struct crec *crecp) ...@@ -256,7 +263,7 @@ char *cache_get_name(struct crec *crecp)
char *cache_get_cname_target(struct crec *crecp) char *cache_get_cname_target(struct crec *crecp)
{ {
if (crecp->addr.cname.uid != -1) if (crecp->addr.cname.uid != 0)
return cache_get_name(crecp->addr.cname.target.cache); return cache_get_name(crecp->addr.cname.target.cache);
return crecp->addr.cname.target.int_name->name; return crecp->addr.cname.target.int_name->name;
...@@ -289,7 +296,7 @@ struct crec *cache_enumerate(int init) ...@@ -289,7 +296,7 @@ struct crec *cache_enumerate(int init)
static int is_outdated_cname_pointer(struct crec *crecp) static int is_outdated_cname_pointer(struct crec *crecp)
{ {
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1) if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == 0)
return 0; return 0;
/* NB. record may be reused as DS or DNSKEY, where uid is /* NB. record may be reused as DS or DNSKEY, where uid is
...@@ -1034,7 +1041,7 @@ void cache_reload(void) ...@@ -1034,7 +1041,7 @@ void cache_reload(void)
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
cache->name.namep = a->alias; cache->name.namep = a->alias;
cache->addr.cname.target.int_name = intr; cache->addr.cname.target.int_name = intr;
cache->addr.cname.uid = -1; cache->addr.cname.uid = 0;
cache_hash(cache); cache_hash(cache);
add_hosts_cname(cache); /* handle chains */ add_hosts_cname(cache); /* handle chains */
} }
...@@ -1242,7 +1249,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, ...@@ -1242,7 +1249,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
crec->ttd = ttd; crec->ttd = ttd;
crec->addr.addr = *host_address; crec->addr.addr = *host_address;
crec->name.namep = host_name; crec->name.namep = host_name;
crec->uid = uid++; crec->uid = next_uid();
cache_hash(crec); cache_hash(crec);
add_dhcp_cname(crec, ttd); add_dhcp_cname(crec, ttd);
......
...@@ -367,7 +367,7 @@ struct crec { ...@@ -367,7 +367,7 @@ struct crec {
struct crec *cache; struct crec *cache;
struct interface_name *int_name; struct interface_name *int_name;
} target; } target;
int uid; /* -1 if union is interface-name */ unsigned int uid; /* 0 if union is interface-name */
} cname; } cname;
struct { struct {
struct blockdata *keydata; struct blockdata *keydata;
...@@ -388,7 +388,7 @@ struct crec { ...@@ -388,7 +388,7 @@ struct crec {
} addr; } addr;
time_t ttd; /* time to die */ time_t ttd; /* time to die */
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */ /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
int uid; unsigned int uid;
unsigned short flags; unsigned short flags;
union { union {
char sname[SMALLDNAME]; char sname[SMALLDNAME];
......
...@@ -827,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -827,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)) for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
if (crecp->addr.key.algo == algo && if (crecp->addr.key.algo == algo &&
crecp->addr.key.keytag == key_tag && crecp->addr.key.keytag == key_tag &&
crecp->uid == class && crecp->uid == (unsigned int)class &&
verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo)) verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE; return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
} }
...@@ -932,7 +932,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch ...@@ -932,7 +932,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
if (recp1->addr.ds.algo == algo && if (recp1->addr.ds.algo == algo &&
recp1->addr.ds.keytag == keytag && recp1->addr.ds.keytag == keytag &&
recp1->uid == class && recp1->uid == (unsigned int)class &&
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) && (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
hash_init(hash, &ctx, &digest)) hash_init(hash, &ctx, &digest))
......
...@@ -1456,7 +1456,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1456,7 +1456,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{ {
char *name = daemon->namebuff; char *name = daemon->namebuff;
unsigned char *p, *ansp, *pheader; unsigned char *p, *ansp, *pheader;
int qtype, qclass; unsigned int qtype, qclass;
struct all_addr addr; struct all_addr addr;
int nameoffset; int nameoffset;
unsigned short flag; unsigned short flag;
...@@ -2016,7 +2016,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -2016,7 +2016,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
strcpy(name, cname_target); strcpy(name, cname_target);
/* check if target interface_name */ /* check if target interface_name */
if (crecp->addr.cname.uid == -1) if (crecp->addr.cname.uid == 0)
goto intname_restart; goto intname_restart;
else else
goto cname_restart; goto cname_restart;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment