[Freeipa-devel] [PATCH 0055] Fix race condition in addrdataset() during SOA serial update

Adam Tkac atkac at redhat.com
Fri Sep 14 13:07:57 UTC 2012


On Fri, Sep 07, 2012 at 01:05:37PM +0200, Petr Spacek wrote:
> Hello,
> 
>     Fix race condition in addrdataset() during SOA serial update.
> 
>     https://fedorahosted.org/bind-dyndb-ldap/ticket/89

Good catch, thanks. Ack

A

> From 5e8bc8f943345d8d92900474905288939958dcd8 Mon Sep 17 00:00:00 2001
> From: Petr Spacek <pspacek at redhat.com>
> Date: Fri, 7 Sep 2012 13:01:57 +0200
> Subject: [PATCH] Fix race condition in addrdataset() during SOA serial
>  update.
> 
> https://fedorahosted.org/bind-dyndb-ldap/ticket/89
> 
> Signed-off-by: Petr Spacek <pspacek at redhat.com>
> ---
>  src/ldap_driver.c | 44 ++++++++++++++++++++++++++++++++++----------
>  src/ldap_helper.c |  4 ++--
>  2 files changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/src/ldap_driver.c b/src/ldap_driver.c
> index 2cdde30cdad9544d530475f5cf4a0b8275a56f03..3a802238028145d35390f6a8d00f156bfdf8e7a1 100644
> --- a/src/ldap_driver.c
> +++ b/src/ldap_driver.c
> @@ -936,6 +936,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
>  	dns_rdatalist_t diff;
>  	isc_result_t result;
>  	isc_boolean_t rdatalist_exists = ISC_FALSE;
> +	isc_boolean_t soa_simulated_write = ISC_FALSE;
>  
>  	UNUSED(now);
>  	UNUSED(db);
> @@ -975,42 +976,65 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
>  			rdatalist_removedups(found_rdlist, new_rdlist,
>  					     ISC_FALSE, &diff);
>  
> -			if ((options & DNS_DBADD_MERGE) != 0)
> +			if ((options & DNS_DBADD_MERGE) == 0 &&
> +			    (rdatalist_length(&diff) != 0)) {
> +				CLEANUP_WITH(DNS_R_NOTEXACT);
> +			} else {
>  				free_rdatalist(ldapdb->common.mctx, &diff);
> -			else if (rdatalist_length(&diff) != 0) {
> -				free_rdatalist(ldapdb->common.mctx, &diff);
> -				result = DNS_R_NOTEXACT;
> -				goto cleanup;
>  			}
>  		} else {
>  			/* Replace existing rdataset */
>  			free_rdatalist(ldapdb->common.mctx, found_rdlist);
>  		}
>  	}
>  
> -	CHECK(write_to_ldap(&ldapdbnode->owner, ldapdb->ldap_inst, new_rdlist));
> +	/* HACK: SOA addition will never fail with DNS_R_UNCHANGED.
> +	 * This prevents warning from BIND's diff_apply(), it has too strict
> +	 * checks for us.
> +	 *
> +	 * Reason: There is a race condition between SOA serial update
> +	 * from BIND's update_action() and our persistent search watcher, because
> +	 * they don't know about each other.
> +	 * BIND's update_action() changes data with first addrdataset() call and
> +	 * then changes serial with second addrdataset() call.
> +	 * It can lead to empty diff if persistent search watcher
> +	 * incremented serial in meanwhile.
> +	 */
> +	if (HEAD(new_rdlist->rdata) == NULL) {
> +		if (rdlist->type == dns_rdatatype_soa)
> +			soa_simulated_write = ISC_TRUE;
> +		else
> +			CLEANUP_WITH(DNS_R_UNCHANGED);
> +	} else {
> +		CHECK(write_to_ldap(&ldapdbnode->owner, ldapdb->ldap_inst, new_rdlist));
> +	}
> +
>  
>  	if (addedrdataset != NULL) {
> -		result = dns_rdatalist_tordataset(new_rdlist, addedrdataset);
> -		/* Use strong condition here, returns only SUCCESS */
> -		INSIST(result == ISC_R_SUCCESS);
> +		if (soa_simulated_write) {
> +			dns_rdataset_clone(rdataset, addedrdataset);
> +		} else {
> +			result = dns_rdatalist_tordataset(new_rdlist, addedrdataset);
> +			/* Use strong condition here, returns only SUCCESS */
> +			INSIST(result == ISC_R_SUCCESS);
> +		}
>  	}
>  
>  	if (rdatalist_exists) {
>  		ISC_LIST_APPENDLIST(found_rdlist->rdata, new_rdlist->rdata,
>  				    link);
>  		SAFE_MEM_PUT_PTR(ldapdb->common.mctx, new_rdlist);
>  	} else
>  		APPEND(ldapdbnode->rdatalist, new_rdlist, link);
>  
> -
>  	return ISC_R_SUCCESS;
>  
>  cleanup:
>  	if (new_rdlist != NULL) {
>  		free_rdatalist(ldapdb->common.mctx, new_rdlist);
>  		SAFE_MEM_PUT_PTR(ldapdb->common.mctx, new_rdlist);
>  	}
> +	free_rdatalist(ldapdb->common.mctx, &diff);
>  
>  	return result;
>  }
> diff --git a/src/ldap_helper.c b/src/ldap_helper.c
> index 3241ffe486205fa03a6fd1a0a14edf1245c5c4aa..e636a84b35d0bcdc8573c6e7146f38ee21a42076 100644
> --- a/src/ldap_helper.c
> +++ b/src/ldap_helper.c
> @@ -2973,10 +2973,10 @@ soa_serial_increment(isc_mem_t *mctx, ldap_instance_t *inst,
>  
>  	/* put the new SOA to inst->cache and compare old and new serials */
>  	CHECK(ldap_get_zone_serial(inst, zone_name, &new_serial));
> -	INSIST(isc_serial_gt(new_serial, old_serial) == ISC_TRUE);
>  
>  cleanup:
> -	if (result != ISC_R_SUCCESS)
> +	if (result != ISC_R_SUCCESS ||
> +	    isc_serial_gt(new_serial, old_serial) != ISC_TRUE)
>  		log_error("SOA serial number incrementation failed in zone '%s'",
>  					str_buf(zone_dn));
>  
> -- 
> 1.7.11.4
> 


-- 
Adam Tkac, Red Hat, Inc.




More information about the Freeipa-devel mailing list