diff --git a/CHANGES b/CHANGES index 7ea7706985..099d3ca434 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2474. [bug] ACL structures could be allocated with insufficient + space, causing an array overrun. [RT #18765] + 2473. [port] linux: raise the limit on open files to the possible maximum value before spawning threads; 'files' specified in named.conf doesn't seem to work with diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c index ead4a70f9a..b0472bce74 100644 --- a/lib/isccfg/aclconf.c +++ b/lib/isccfg/aclconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: aclconf.c,v 1.21 2008/09/01 05:36:00 marka Exp $ */ +/* $Id: aclconf.c,v 1.22 2008/10/24 02:28:55 each Exp $ */ #include @@ -160,6 +160,51 @@ convert_keyname(const cfg_obj_t *keyobj, isc_log_t *lctx, isc_mem_t *mctx, return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname)); } +/* + * Recursively pre-parse an ACL definition to find the total number + * of non-IP-prefix elements (localhost, localnets, key) in all nested + * ACLs, so that the parent will have enough space allocated for the + * elements table after all the nested ACLs have been merged in to the + * parent. + */ +static int +count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx) +{ + const cfg_listelt_t *elt; + const cfg_obj_t *cacl = NULL; + isc_result_t result; + int n = 0; + + for (elt = cfg_list_first(caml); + elt != NULL; + elt = cfg_list_next(elt)) { + const cfg_obj_t *ce = cfg_listelt_value(elt); + + /* negated element; just get the value. */ + if (cfg_obj_istuple(ce)) + ce = cfg_tuple_get(ce, "value"); + + if (cfg_obj_istype(ce, &cfg_type_keyref)) { + n++; + } else if (cfg_obj_islist(ce)) { + n += count_acl_elements(ce, cctx); + } else if (cfg_obj_isstring(ce)) { + const char *name = cfg_obj_asstring(ce); + if (strcasecmp(name, "localhost") == 0 || + strcasecmp(name, "localnets") == 0) { + n++; + } else if (strcasecmp(name, "any") != 0 && + strcasecmp(name, "none") != 0) { + result = get_acl_def(cctx, name, &cacl); + if (result == ISC_R_SUCCESS) + n += count_acl_elements(cacl, cctx) + 1; + } + } + } + + return n; +} + isc_result_t cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx, @@ -194,14 +239,18 @@ cfg_acl_fromconfig(const cfg_obj_t *caml, } else { /* * Need to allocate a new ACL structure. Count the items - * in the ACL definition and allocate space for that many - * elements (even though some or all of them may end up in - * the iptable instead of the element array). + * in the ACL definition that will require space in the + * elemnts table. (Note that if nest_level is nonzero, + * *everything* goes in the elements table.) */ - isc_boolean_t recurse = ISC_TF(nest_level == 0); - result = dns_acl_create(mctx, - cfg_list_length(caml, recurse), - &dacl); + int nelem; + + if (nest_level == 0) + nelem = count_acl_elements(caml, cctx); + else + nelem = cfg_list_length(caml, ISC_FALSE); + + result = dns_acl_create(mctx, nelem, &dacl); if (result != ISC_R_SUCCESS) return (result); } @@ -209,8 +258,7 @@ cfg_acl_fromconfig(const cfg_obj_t *caml, de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; - elt = cfg_list_next(elt)) - { + elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); isc_boolean_t neg;