drepl: memory leak fix
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Mon, 26 Nov 2018 22:07:44 +0000 (11:07 +1300)
committerGarming Sam <garming@samba.org>
Wed, 17 Jul 2019 06:17:10 +0000 (06:17 +0000)
Fixes a memory leak where schema reference attached to ldb
instance is lost before it can be freed.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14042

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Autobuild-User(master): Garming Sam <garming@samba.org>
Autobuild-Date(master): Wed Jul 17 06:17:10 UTC 2019 on sn-devel-184

source4/dsdb/schema/schema_set.c

index b316686fd032f3af75c26406917163a48460f6c6..943d0ef49f59f9763ea11b74a67efb160a22649b 100644 (file)
@@ -695,6 +695,7 @@ int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
                          enum schema_set_enum write_indices_and_attributes)
 {
        int ret;
+       void *ptr;
        struct dsdb_schema *old_schema;
        old_schema = ldb_get_opaque(ldb, "dsdb_schema");
        ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
@@ -706,8 +707,13 @@ int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema,
         * none, NULL is harmless here */
        talloc_unlink(ldb, old_schema);
 
-       if (talloc_reference(ldb, schema) == NULL) {
-               return ldb_oom(ldb);
+       /* Reference schema on ldb if it wasn't done already */
+       ret = talloc_is_parent(ldb, schema);
+       if (ret == 0) {
+               ptr = talloc_reference(ldb, schema);
+               if (ptr == NULL) {
+                       return ldb_oom(ldb);
+               }
        }
 
        /* Make this ldb use local schema preferably */
@@ -741,6 +747,7 @@ int dsdb_set_global_schema(struct ldb_context *ldb)
 {
        int ret;
        void *use_global_schema = (void *)1;
+       void *ptr;
        struct dsdb_schema *old_schema = ldb_get_opaque(ldb, "dsdb_schema");
 
        ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema);
@@ -766,9 +773,15 @@ int dsdb_set_global_schema(struct ldb_context *ldb)
        /* Don't write indices and attributes, it's expensive */
        ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, SCHEMA_MEMORY_ONLY);
        if (ret == LDB_SUCCESS) {
-               /* Keep a reference to this schema, just in case the original copy is replaced */
-               if (talloc_reference(ldb, global_schema) == NULL) {
-                       return ldb_oom(ldb);
+               /* If ldb doesn't have a reference to the schema, make one,
+                * just in case the original copy is replaced */
+               ret = talloc_is_parent(ldb, global_schema);
+               if (ret == 0) {
+                       ptr = talloc_reference(ldb, global_schema);
+                       if (ptr == NULL) {
+                               return ldb_oom(ldb);
+                       }
+                       ret = ldb_set_opaque(ldb, "dsdb_schema", global_schema);
                }
        }
 
@@ -794,6 +807,7 @@ struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *referen
        dsdb_schema_refresh_fn refresh_fn;
        struct ldb_module *loaded_from_module;
        bool use_global_schema;
+       int ret;
        TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
        if (tmp_ctx == NULL) {
                return NULL;
@@ -843,7 +857,11 @@ struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *referen
 
        /* This removes the extra reference above */
        talloc_free(tmp_ctx);
-       if (!reference_ctx) {
+
+       /* If ref ctx exists and doesn't already reference schema, then add
+        * a reference.  Otherwise, just return schema.*/
+       ret = talloc_is_parent(reference_ctx, schema_out);
+       if ((ret == 1) || (!reference_ctx)) {
                return schema_out;
        } else {
                return talloc_reference(reference_ctx, schema_out);