Download raw body.
Fix memory leaks in ldapd caused by missing ober_free_elements calls
Hi tech@,
This patch fixes several memory leaks in ldapd caused by missing calls
to ober_free_elements after using namespace_get. The namespace_get
function eventually calls ober_read_element, which allocates memory
for parsed BER elements.
The most significant leak happens during processing of bind requests
from non-root users in auth.c. The returned ber_element was not freed
after being processed.
Similar issues were found and fixed in ldape.c and modify.c. In these
cases, ber_element returned by namespace_get was also left unfreed.
Additionally, minor cosmetic cleanups were made to simplify some
NULL checks. Since ober_free_elements safely handles NULL arguments,
explicit pointer checks before calling it are unnecessary and were
removed.
Tested with multiple bind and modify operations to confirm no
regressions or new leaks.
The diff is in the attachment.
Best regards,
Anton Kasimov
Index: auth.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/auth.c,v
diff -u -p -u -p -r1.15 auth.c
--- auth.c 29 Jun 2022 09:10:13 -0000 1.15
+++ auth.c 10 May 2025 08:46:30 -0000
@@ -301,7 +301,7 @@ ldap_auth_simple(struct request *req, ch
char *password;
char *user_password;
struct namespace *ns;
- struct ber_element *elm = NULL, *pw = NULL;
+ struct ber_element *entry = NULL, *elm = NULL, *pw = NULL;
if (*binddn == '\0') {
free(req->conn->binddn); /* anonymous bind */
@@ -337,15 +337,15 @@ ldap_auth_simple(struct request *req, ch
NULL, LDAP_SCOPE_BASE))
return LDAP_INSUFFICIENT_ACCESS;
- elm = namespace_get(ns, binddn);
- if (elm == NULL && errno == ESTALE) {
+ entry = namespace_get(ns, binddn);
+ if (entry == NULL && errno == ESTALE) {
if (namespace_queue_request(ns, req) != 0)
return LDAP_BUSY;
return -1; /* Database is being reopened. */
}
- if (elm != NULL)
- pw = ldap_get_attribute(elm, "userPassword");
+ if (entry != NULL)
+ pw = ldap_get_attribute(entry, "userPassword");
if (pw != NULL) {
for (elm = pw->be_next->be_sub; elm;
elm = elm->be_next) {
@@ -356,6 +356,7 @@ ldap_auth_simple(struct request *req, ch
break;
}
}
+ ober_free_elements(entry);
}
free(req->conn->binddn);
Index: ldape.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/ldape.c,v
diff -u -p -u -p -r1.38 ldape.c
--- ldape.c 17 Jan 2024 08:28:15 -0000 1.38
+++ ldape.c 10 May 2025 08:46:30 -0000
@@ -105,8 +105,7 @@ send_ldap_extended_response(struct conn
return;
fail:
- if (root)
- ober_free_elements(root);
+ ober_free_elements(root);
}
int
@@ -180,10 +179,8 @@ ldap_refer(struct request *req, const ch
return LDAP_REFERRAL;
fail:
- if (root != NULL)
- ober_free_elements(root);
- if (ref_root != NULL)
- ober_free_elements(ref_root);
+ ober_free_elements(root);
+ ober_free_elements(ref_root);
request_free(req);
return LDAP_REFERRAL;
}
@@ -205,6 +202,14 @@ ldap_respond(struct request *req, int co
}
int
+ldap_free_elements_and_respond(struct ber_element *elm, struct request *req,
+ int code)
+{
+ ober_free_elements(elm);
+ return ldap_respond(req, code);
+}
+
+int
ldap_abandon(struct request *req)
{
long long msgid;
@@ -266,19 +271,22 @@ ldap_compare(struct request *req)
return ldap_respond(req, LDAP_NO_SUCH_OBJECT);
if ((attr = ldap_find_attribute(entry, at)) == NULL)
- return ldap_respond(req, LDAP_NO_SUCH_ATTRIBUTE);
+ return ldap_free_elements_and_respond(entry, req,
+ LDAP_NO_SUCH_ATTRIBUTE);
if ((attr = attr->be_next) == NULL) /* skip attribute name */
- return ldap_respond(req, LDAP_OTHER);
+ return ldap_free_elements_and_respond(entry, req, LDAP_OTHER);
for (elm = attr->be_sub; elm != NULL; elm = elm->be_next) {
if (ober_get_string(elm, &s) != 0)
- return ldap_respond(req, LDAP_OTHER);
+ return ldap_free_elements_and_respond(entry, req,
+ LDAP_OTHER);
if (strcasecmp(value, s) == 0)
- return ldap_respond(req, LDAP_COMPARE_TRUE);
+ return ldap_free_elements_and_respond(entry, req,
+ LDAP_COMPARE_TRUE);
}
- return ldap_respond(req, LDAP_COMPARE_FALSE);
+ return ldap_free_elements_and_respond(entry, req, LDAP_COMPARE_FALSE);
}
int
Index: modify.c
===================================================================
RCS file: /cvs/src/usr.sbin/ldapd/modify.c,v
diff -u -p -u -p -r1.24 modify.c
--- modify.c 20 Dec 2021 13:26:11 -0000 1.24
+++ modify.c 10 May 2025 08:46:30 -0000
@@ -36,7 +36,7 @@ ldap_delete(struct request *req)
struct namespace *ns;
struct referrals *refs;
struct cursor *cursor;
- struct ber_element *entry, *elm, *a;
+ struct ber_element *entry = NULL, *elm, *a;
int rc = LDAP_OTHER;
++stats.req_mod;
@@ -114,6 +114,7 @@ ldap_delete(struct request *req)
rc = LDAP_SUCCESS;
done:
+ ober_free_elements(entry);
btree_cursor_close(cursor);
btval_reset(&key);
namespace_abort(ns);
@@ -226,8 +227,7 @@ ldap_add(struct request *req)
return ldap_respond(req, rc);
fail:
- if (set != NULL)
- ober_free_elements(set);
+ ober_free_elements(set);
namespace_abort(ns);
return ldap_respond(req, LDAP_OTHER);
}
@@ -384,8 +384,8 @@ ldap_modify(struct request *req)
rc = LDAP_OTHER;
done:
- if (vals != NULL)
- ober_free_elements(vals);
+ ober_free_elements(vals);
+ ober_free_elements(entry);
namespace_abort(ns);
return ldap_respond(req, rc);
}
Fix memory leaks in ldapd caused by missing ober_free_elements calls