krb5 commit [krb5-1.12]: Fix several memory leaks in LDAP KDB modules
Tom Yu
tlyu at MIT.EDU
Mon Jul 21 18:33:42 EDT 2014
https://github.com/krb5/krb5/commit/37447050b6c9b92ac8c77da26984624ac43fdbc6
commit 37447050b6c9b92ac8c77da26984624ac43fdbc6
Author: Greg Hudson <ghudson at mit.edu>
Date: Tue Jun 10 23:53:31 2014 -0400
Fix several memory leaks in LDAP KDB modules
Fix memory leaks discovered by running valgrind over kdbtest, and some
related leaks. Many of them result from not calling ldap_msgfree
after an unsuccessful search (as the OpenLDAP documentation requires)
or after an exception following a search, so many of the fixes move or
add ldap_msgfree calls to cleanup labels.
ldap_osa_free_princ_ent was not used, and could not be used because it
frees the container while krb5_lookup_tl_kadm_data uses a
caller-allocated container. Change it to leave the container alone,
but to correctly destroy xdrs. Use it in krb5_ldap_put_principal
where princ_ent was leaked.
In krb5_ldap_put_principal, subtreelist is declared twice in interior
scopes and not properly freed; move it to function scope and free it
up in the cleanup label. Also in krb5_ldap_put_principal, avoiding
decoding multiple KBR5_TL_KADM_DATA values (which we don't expect to
see) as later decodes would cause earlier decodes to leak.
In krb5_encode_krbsecretkey, fix a leak of the krb5_data container and
also add an error check when calling asn1_encode_sequence_of_keys;
otherwise we would dereference a null pointer if we run out of memory
encoding keys (very unlikely).
(cherry picked from commit bfd2a69193ddc1b324d48a7da6455cfbda54fc09)
ticket: 7941
version_fixed: 1.12.2
status: resolved
src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c | 2 +-
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c | 3 +
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c | 57 ++++++++++---------
src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c | 9 ++-
src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c | 11 +++-
src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c | 4 +-
src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c | 3 +-
7 files changed, 51 insertions(+), 38 deletions(-)
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
index 8776ab5..abefcf5 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
@@ -1020,7 +1020,7 @@ checkattributevalue(LDAP *ld, char *dn, char *attribute, char **attrvalues,
LDAP_NO_LIMIT,
&result)) != LDAP_SUCCESS) {
st = set_ldap_error(0, st, OP_SEARCH);
- return st;
+ goto cleanup;
}
/*
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
index 47ba5f0..4c1ab40 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
@@ -206,6 +206,7 @@ krb5_ldap_iterate(krb5_context context, char *match_expr,
}
} /* end of for (ent= ... */
ldap_msgfree(result);
+ result = NULL;
} /* end of for (tree= ... */
cleanup:
@@ -215,7 +216,9 @@ cleanup:
for (;ntree; --ntree)
if (subtree[ntree-1])
free (subtree[ntree-1]);
+ free(subtree);
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
index ac612d3..515eba7 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
@@ -448,18 +448,18 @@ krb5_encode_krbsecretkey(krb5_key_data *key_data_in, int n_key_data,
for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
krb5_data *code;
if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
- asn1_encode_sequence_of_keys (key_data+last,
- (krb5_int16) i - last + 1,
- mkvno,
- &code);
- ret[j] = malloc (sizeof (struct berval));
- if (ret[j] == NULL) {
- err = ENOMEM;
+ ret[j] = k5alloc(sizeof(struct berval), &err);
+ if (ret[j] == NULL)
+ goto cleanup;
+ err = asn1_encode_sequence_of_keys(key_data + last,
+ (krb5_int16)i - last + 1,
+ mkvno, &code);
+ if (err)
goto cleanup;
- }
/*CHECK_NULL(ret[j]); */
ret[j]->bv_len = code->length;
ret[j]->bv_val = code->data;
+ free(code);
j++;
last = i + 1;
@@ -509,9 +509,11 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
char **db_args)
{
int l=0, kerberos_principal_object_type=0;
+ unsigned int ntrees=0, tre=0;
krb5_error_code st=0, tempst=0;
LDAP *ld=NULL;
LDAPMessage *result=NULL, *ent=NULL;
+ char **subtreelist = NULL;
char *user=NULL, *subtree=NULL, *principal_dn=NULL;
char **values=NULL, *strval[10]={NULL}, errbuf[1024];
char *filtuser=NULL;
@@ -525,7 +527,7 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
kdb5_dal_handle *dal_handle=NULL;
krb5_ldap_context *ldap_context=NULL;
krb5_ldap_server_handle *ldap_server_handle=NULL;
- osa_princ_ent_rec princ_ent;
+ osa_princ_ent_rec princ_ent = {0};
xargs_t xargs = {0};
char *polname = NULL;
OPERATION optype;
@@ -576,9 +578,9 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
goto cleanup;
if (entry->mask & KADM5_LOAD) {
- unsigned int tree = 0, ntrees = 0;
+ unsigned int tree = 0;
int numlentries = 0;
- char **subtreelist = NULL, *filter = NULL;
+ char *filter = NULL;
/* A load operation is special, will do a mix-in (add krbprinc
* attrs to a non-krb object entry) if an object exists with a
@@ -600,7 +602,6 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
found_entry = FALSE;
/* search for entry with matching krbprincipalname attribute */
for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
- result = NULL;
if (principal_dn == NULL) {
LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
} else {
@@ -610,7 +611,6 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
if (st == LDAP_SUCCESS) {
numlentries = ldap_count_entries(ld, result);
if (numlentries > 1) {
- ldap_msgfree(result);
free(filter);
st = EINVAL;
krb5_set_error_message(context, st,
@@ -628,21 +628,20 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
st = set_ldap_error (context, st, 0);
- ldap_msgfree(result);
free(filter);
goto cleanup;
}
}
}
}
- if (result)
- ldap_msgfree(result);
} else if (st != LDAP_NO_SUCH_OBJECT) {
/* could not perform search, return with failure */
st = set_ldap_error (context, st, 0);
free(filter);
goto cleanup;
}
+ ldap_msgfree(result);
+ result = NULL;
/*
* If it isn't found then assume a standalone princ entry is to
* be created.
@@ -717,9 +716,7 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
*/
if (xargs.dn_from_kbd == TRUE) {
/* make sure the DN falls in the subtree */
- unsigned int tre=0, ntrees=0;
int dnlen=0, subtreelen=0;
- char **subtreelist=NULL;
char *dn=NULL;
krb5_boolean outofsubtree=TRUE;
@@ -736,9 +733,12 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
dn = standalone_principal_dn;
}
- /* get the current subtree list */
- if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
- goto cleanup;
+ /* Get the current subtree list if we haven't already done so. */
+ if (subtreelist == NULL) {
+ st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees);
+ if (st)
+ goto cleanup;
+ }
for (tre=0; tre<ntrees; ++tre) {
if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
@@ -754,10 +754,6 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
}
}
- for (tre=0; tre < ntrees; ++tre) {
- free(subtreelist[tre]);
- }
-
if (outofsubtree == TRUE) {
st = EINVAL;
krb5_set_error_message(context, st,
@@ -785,6 +781,8 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
*/
char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
+ ldap_msgfree(result);
+ result = NULL;
LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
if (st == LDAP_SUCCESS) {
ent = ldap_first_entry(ld, result);
@@ -798,7 +796,6 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
ldap_value_free(values);
}
}
- ldap_msgfree(result);
} else {
st = set_ldap_error(context, st, OP_SEARCH);
goto cleanup;
@@ -1006,10 +1003,10 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
memset(&princ_ent, 0, sizeof(princ_ent));
for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
- /* FIX ME: I guess the princ_ent should be freed after this call */
if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
goto cleanup;
}
+ break;
}
}
@@ -1291,6 +1288,10 @@ cleanup:
if (polname != NULL)
free(polname);
+ for (tre = 0; tre < ntrees; tre++)
+ free(subtreelist[tre]);
+ free(subtreelist);
+
if (subtree)
free (subtree);
@@ -1307,6 +1308,8 @@ cleanup:
free (keys);
ldap_mods_free(mods, 1);
+ ldap_osa_free_princ_ent(&princ_ent);
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return(st);
}
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c
index 4d7d673..522773e 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_pwd_policy.c
@@ -452,15 +452,17 @@ krb5_ldap_iterate_password_policy(krb5_context context, char *match_expr,
goto cleanup;
(*func)(func_arg, entry);
- /* XXX this will free policy so don't free it */
krb5_ldap_free_password_policy(context, entry);
entry = NULL;
+
+ free(policy);
+ policy = NULL;
}
- ldap_msgfree(result);
cleanup:
free(entry);
-
+ free(policy);
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
@@ -472,6 +474,7 @@ krb5_ldap_free_password_policy (context, entry)
{
if (entry) {
free(entry->name);
+ free(entry->allowed_keysalts);
free(entry);
}
return;
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
index 032be6f..c0e1478 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
@@ -170,7 +170,6 @@ krb5_ldap_list_realm(krb5_context context, char ***realms)
ldap_value_free(values);
}
} /* for (ent= ... */
- ldap_msgfree(result);
cleanup:
@@ -187,6 +186,7 @@ cleanup:
/* If there are no elements, still return a NULL terminated array */
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
@@ -284,7 +284,6 @@ krb5_ldap_delete_realm (krb5_context context, char *lrealm)
ldap_value_free(values);
}
}
- ldap_msgfree(result);
}
/* Delete all password policies */
@@ -319,6 +318,12 @@ cleanup:
free (subtrees);
}
+ if (result_arr != NULL) {
+ for (l = 0; l < ntree; l++)
+ ldap_msgfree(result_arr[l]);
+ free(result_arr);
+ }
+
if (policy != NULL) {
for (i = 0; policy[i] != NULL; i++)
free (policy[i]);
@@ -844,7 +849,6 @@ krb5_ldap_read_realm_params(krb5_context context, char *lrealm,
}
}
- ldap_msgfree(result);
rlparams->mask = *mask;
*rlparamp = rlparams;
@@ -857,6 +861,7 @@ cleanup:
krb5_ldap_free_realm_params(rlparams);
*rlparamp=NULL;
}
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c
index 99b5401..02d8e7c 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.c
@@ -250,7 +250,6 @@ krb5_ldap_read_policy(krb5_context context, char *policyname,
if (krb5_ldap_get_value(ld, ent, "krbticketflags", (int *) &(lpolicy->tktflags)) == 0)
*omask |= LDAP_POLICY_TKTFLAGS;
}
- ldap_msgfree(result);
lpolicy->mask = *omask;
store_tl_data(lpolicy->tl_data, KDB_TL_MASK, omask);
@@ -261,6 +260,7 @@ cleanup:
krb5_ldap_free_policy(context, lpolicy);
*policy = NULL;
}
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
@@ -468,7 +468,6 @@ krb5_ldap_list(krb5_context context, char ***list, char *objectclass,
}
ldap_memfree(dn);
}
- ldap_msgfree(result);
cleanup:
if (filter)
@@ -483,6 +482,7 @@ cleanup:
*list = NULL;
}
}
+ ldap_msgfree(result);
krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
return st;
}
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c
index 5ae8672..5eca41e 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_xdr.c
@@ -176,9 +176,8 @@ ldap_osa_free_princ_ent(osa_princ_ent_t val)
XDR xdrs;
xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
-
ldap_xdr_osa_princ_ent_rec(&xdrs, val);
- free(val);
+ xdr_destroy(&xdrs);
}
krb5_error_code
More information about the cvs-krb5
mailing list