On 11/30/2015 06:02 PM, Jakub Hrozek wrote:

Wouldn't it then be better to see if another same object is already in
the hashtable and free it before replacing?

I agree it would be best. I tried that before and failed because I could not 
decipher out the relation of talloc contexts.

I tried that again. Seems that leaks are gone. Segfaults were not happening 
during my testing.

Code got even messier :-(

I think the code would look nice if it was placed in the else branch of
create_negcache_netgr() :-)

Done, thanks for hint.


I also don't think we need the tmp_ctx change..

I dare to disagree here. With prev. versions of patch I was experiencing segfaults. IIRC step_context is being allocated on context of the netgroup that is freed. I also think that it's not a good idea to allocate local data on context that does not hold any reference to that data. But it might be matter of personal taste.

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

>From 8f2d4cdac0f5bee1847d7b13e904e84e7d706841 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <prei...@redhat.com>
Date: Fri, 27 Nov 2015 07:53:00 -0500
Subject: [PATCH] NSS: Fix memory leak netgroup

If netgroup cannot be found in setnetgrent_retry() function
set_netgroup_entry() is called which steals getent_ctx directly to
nss_ctx->netgroups.
Subsequently function lookup_netgr_step() is called that (in case of
nenexisting group) will call create_negcache_netgr() which creates
a new dummy object to serve as negative cache. While doing so it calls
again set_netgroup_entry() for the same netgroup and it calls
hash_enter.

hash_enter will remove previously hashed entry for netgroup (created in
setnetgrent_retry()) from hash table but it won't be freed and thus it
leaks. This patch marks such netgroup and freed it after the call of
create_negcache_netgr().

Resolves:
https://fedorahosted.org/sssd/ticket/2865
---
 src/responder/nss/nsssrv_netgroup.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
index 9a78c1119c2f4e06e43ebec29ace775adc997e08..27ae1474a70858efb8040b864dd0e21a8bb674de 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -434,6 +434,7 @@ static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
 {
     errno_t ret;
     struct getent_ctx *netgr;
+    struct getent_ctx *netgr_to_be_freed = NULL;
 
     netgr = talloc_zero(step_ctx->nctx, struct getent_ctx);
     if (netgr == NULL) {
@@ -441,6 +442,11 @@ static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
         ret = ENOMEM;
         goto done;
     } else {
+        /* Is there already netgroup with such name? */
+        ret = get_netgroup_entry(step_ctx->nctx, step_ctx->name,
+                             &netgr_to_be_freed);
+        if (ret != EOK) netgr_to_be_freed = NULL;
+
         netgr->ready = true;
         netgr->found = false;
         netgr->entries = NULL;
@@ -461,6 +467,9 @@ static errno_t create_negcache_netgr(struct setent_step_ctx *step_ctx)
     }
 
 done:
+    /* Free netgroup after step_ctx is not needed. */
+    if (netgr_to_be_freed) talloc_zfree(netgr_to_be_freed);
+
     if (ret != EOK) {
         talloc_free(netgr);
     }
@@ -474,6 +483,12 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
     struct getent_ctx *netgr;
     char *name = NULL;
     uint32_t lifetime;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
 
     /* Check each domain for this netgroup name */
     while (dom) {
@@ -494,8 +509,7 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
         /* make sure to update the dctx if we changed domain */
         step_ctx->dctx->domain = dom;
 
-        talloc_free(name);
-        name = sss_get_cased_name(step_ctx, step_ctx->name,
+        name = sss_get_cased_name(tmp_ctx, step_ctx->name,
                                   dom->case_sensitive);
         if (!name) {
             DEBUG(SSSDBG_CRIT_FAILURE, "sss_get_cased_name failed\n");
@@ -623,10 +637,11 @@ static errno_t lookup_netgr_step(struct setent_step_ctx *step_ctx)
               "create_negcache_netgr failed with: %d:[%s], ignored.\n",
               ret, sss_strerror(ret));
     }
+
     ret = ENOENT;
 
 done:
-    talloc_free(name);
+    talloc_free(tmp_ctx);
     return ret;
 }
 
-- 
2.4.3

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

Reply via email to