Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 06 Oct 2014 14:20:42 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        freebsd-current@freebsd.org
Cc:        David Shane Holden <dpejesh@yahoo.com>
Subject:   Re: [PATCH] nscd
Message-ID:  <5187301.oT50I74Vz0@ralph.baldwin.cx>
In-Reply-To: <m0d8o4$qa3$1@ger.gmane.org>
References:  <m0d8o4$qa3$1@ger.gmane.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Monday, September 29, 2014 11:40:52 PM David Shane Holden wrote:
> So, I've noticed nscd hasn't worked right for awhile now.  Since I
> upgraded to 10.0 it never seemed to cache properly but I never bothered
> to really dig into it until recently and here's what I've found.  In my
> environment I have nsswitch set to use caching and LDAP as such:
> 
> group: files cache ldap
> passwd: files cache ldap
> 
> The LDAP part works fine, but caching didn't on 10.0 for some reason.
> On my 9.2 machines it works as expected though.  What I've found is in
> usr.sbin/nscd/query.c
> 
> struct query_state *
> init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t
> egid)
> {
>    ...
> 	memcpy(&retval->timeout, &s_configuration->query_timeout,
> 		sizeof(struct timeval));
>    ...
> }
> 
> s_configuration->query_timeout is an 'int' which is being memcpy'd into
> a 'struct timeval' causing it to grab other parts of the s_configuration
> struct along with the query_timeout value and polluting retval->timeout.
> In this case it appears to be grabbing s_configuration->threads_num and
> shoving that into timeout.tv_sec along with the query_timeout. This ends
> up confusing nscd later on (instead of being 8 it ends up being set to
> 34359738376) and breaks it's ability to cache.  I've attached a patch to
> set the retval->timeout properly and gets nscd working again.  I'm
> guessing gcc was handling this differently from clang which is why it
> wasn't a problem before 10.0.

Cute.  This codebase likes to use memcpy() way too much for simple assignments
Which can lead to bugs like this.  It also likes to do this:

	size = strlen(name) + 1;
	foo = calloc(size, 1);
	assert(foo != NULL);
	strlcpy(foo, name, size); // or memcpy()

instead of the simpler:

	foo = strdup(name);
	assert(foo != NULL);

I have a patch to remove various memcpy's trying to copy structures as well as 
un-expand several of the strdup() calls if you'd care to test it.  These 
changes didn't cover any other memcpy() misuse.

Index: cachelib.c
===================================================================
--- cachelib.c	(revision 272657)
+++ cachelib.c	(working copy)
@@ -485,7 +485,7 @@
 	assert(retval != NULL);
 
 	assert(params != NULL);
-	memcpy(&retval->params, params, sizeof(struct cache_params));
+	retval->params = *params;
 
 	retval->entries = calloc(1,
 		sizeof(*retval->entries) * INITIAL_ENTRIES_CAPACITY);
@@ -522,7 +522,6 @@
 	struct cache_entry_params const *params)
 {
 	int policies_size;
-	size_t entry_name_size;
 	struct cache_common_entry_	*new_common_entry;
 	struct cache_mp_entry_		*new_mp_entry;
 
@@ -552,7 +551,6 @@
 		the_cache->entries = new_entries;
 	}
 
-	entry_name_size = strlen(params->entry_name) + 1;
 	switch (params->entry_type)
 	{
 	case CET_COMMON:
@@ -560,16 +558,12 @@
 			sizeof(*new_common_entry));
 		assert(new_common_entry != NULL);
 
-		memcpy(&new_common_entry->common_params, params,
-			sizeof(struct common_cache_entry_params));
-		new_common_entry->params =
-		  (struct cache_entry_params *)&new_common_entry->common_params;
+		new_common_entry->common_params.cep = *params;
+		new_common_entry->params = &new_common_entry->common_params.cep;
 
-		new_common_entry->common_params.cep.entry_name = calloc(1,
-			entry_name_size);
+		new_common_entry->common_params.cep.entry_name =
+		    strdup(params->entry_name);
 		assert(new_common_entry->common_params.cep.entry_name != NULL);
-		strlcpy(new_common_entry->common_params.cep.entry_name,
-			params->entry_name, entry_name_size);
 		new_common_entry->name =
 			new_common_entry->common_params.cep.entry_name;
 
@@ -614,16 +608,12 @@
 			sizeof(*new_mp_entry));
 		assert(new_mp_entry != NULL);
 
-		memcpy(&new_mp_entry->mp_params, params,
-			sizeof(struct mp_cache_entry_params));
-		new_mp_entry->params =
-			(struct cache_entry_params *)&new_mp_entry->mp_params;
+		new_mp_entry->mp_params.cep = *params;
+		new_mp_entry->params = &new_mp_entry->mp_params.cep;
 
-		new_mp_entry->mp_params.cep.entry_name = calloc(1,
-			entry_name_size);
+		new_mp_entry->mp_params.cep.entry_name =
+		    strdup(params->entry_name);
 		assert(new_mp_entry->mp_params.cep.entry_name != NULL);
-		strlcpy(new_mp_entry->mp_params.cep.entry_name, params->entry_name,
-			entry_name_size);
 		new_mp_entry->name = new_mp_entry->mp_params.cep.entry_name;
 
 		TAILQ_INIT(&new_mp_entry->ws_head);
@@ -781,9 +771,8 @@
 
 	if (find_res->fifo_policy_item->connected_item != NULL) {
 		connected_item = find_res->fifo_policy_item->connected_item;
-		memcpy(&connected_item->last_request_time,
-			&find_res->fifo_policy_item->last_request_time,
-			sizeof(struct timeval));
+		connected_item->last_request_time = 
+			find_res->fifo_policy_item->last_request_time;
 		connected_item->request_count =
 			find_res->fifo_policy_item->request_count;
 
@@ -873,9 +862,8 @@
 	if (common_entry->policies_size > 1) {
 		connected_policy_item =
 			common_entry->policies[1]->create_item_func();
-		memcpy(&connected_policy_item->creation_time,
-			&policy_item->creation_time,
-			sizeof(struct timeval));
+		connected_policy_item->creation_time =
+			policy_item->creation_time;
 		connected_policy_item->key = policy_item->key;
 		connected_policy_item->key_size = policy_item->key_size;
 
Index: config.c
===================================================================
--- config.c	(revision 272657)
+++ config.c	(working copy)
@@ -116,7 +116,6 @@
 	struct mp_cache_entry_params const *mp_params)
 {
 	struct configuration_entry *retval;
-	size_t	size;
 	int res;
 
 	TRACE_IN(create_configuration_entry);
@@ -159,22 +158,15 @@
 		return (NULL);
 	}
 
-	memcpy(&retval->positive_cache_params, positive_params,
-		sizeof(struct common_cache_entry_params));
-	memcpy(&retval->negative_cache_params, negative_params,
-		sizeof(struct common_cache_entry_params));
-	memcpy(&retval->mp_cache_params, mp_params,
-		sizeof(struct mp_cache_entry_params));
+	retval->positive_cache_params = *positive_params;
+	retval->negative_cache_params = *negative_params;
+	retval->mp_cache_params = *mp_params;
 
-	size = strlen(name);
-	retval->name = calloc(1, size + 1);
+	retval->name = strdup(name);
 	assert(retval->name != NULL);
-	memcpy(retval->name, name, size);
 
-	memcpy(&retval->common_query_timeout, common_timeout,
-		sizeof(struct timeval));
-	memcpy(&retval->mp_query_timeout, mp_timeout,
-		sizeof(struct timeval));
+	retval->common_query_timeout = *common_timeout;
+	retval->mp_query_timeout = *mp_timeout;
 
 	asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name);
 	assert(retval->positive_cache_params.cep.entry_name != NULL);
@@ -212,8 +204,7 @@
 	positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH;
 	positive_params.policy = CPT_LRU;
 
-	memcpy(&negative_params, &positive_params,
-		sizeof(struct common_cache_entry_params));
+	negative_params = positive_params;
 	negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE;
 	negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2;
 	negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME;
@@ -544,15 +535,12 @@
 	if (config->socket_path != NULL)
 		free(config->socket_path);
 
-	len = strlen(DEFAULT_SOCKET_PATH);
-	config->socket_path = calloc(1, len + 1);
+	config->socket_path = strdup(DEFAULT_SOCKET_PATH);
 	assert(config->socket_path != NULL);
-	memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
 
-	len = strlen(DEFAULT_PIDFILE_PATH);
+	config->pidfile_path = strdup(DEFAULT_PIDFILE_PATH);
 	config->pidfile_path = calloc(1, len + 1);
 	assert(config->pidfile_path != NULL);
-	memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
 
 	config->socket_mode =  S_IFSOCK | S_IRUSR | S_IWUSR |
 		S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
Index: mp_rs_query.c
===================================================================
--- mp_rs_query.c	(revision 272657)
+++ mp_rs_query.c	(working copy)
@@ -307,9 +307,7 @@
 			CELT_MULTIPART);
 		    if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
 		    (qstate->config_entry->mp_query_timeout.tv_usec != 0))
-			memcpy(&qstate->timeout,
-			    &qstate->config_entry->mp_query_timeout,
-			    sizeof(struct timeval));
+			qstate->timeout = qstate->config_entry->mp_query_timeout;
 		    configuration_unlock_entry(qstate->config_entry,
 			CELT_MULTIPART);
 		}
Index: mp_ws_query.c
===================================================================
--- mp_ws_query.c	(revision 272657)
+++ mp_ws_query.c	(working copy)
@@ -241,9 +241,7 @@
 
 		if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
 		    (qstate->config_entry->mp_query_timeout.tv_usec != 0))
-			memcpy(&qstate->timeout,
-				&qstate->config_entry->mp_query_timeout,
-				sizeof(struct timeval));
+			qstate->timeout = qstate->config_entry->mp_query_timeout;
 	}
 	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
 
Index: parser.c
===================================================================
--- parser.c	(revision 272657)
+++ parser.c	(working copy)
@@ -138,10 +138,8 @@
 	lifetime.tv_sec = ttl;
 
 	entry = find_create_entry(config, entry_name);
-	memcpy(&entry->positive_cache_params.max_lifetime,
-		&lifetime, sizeof(struct timeval));
-	memcpy(&entry->mp_cache_params.max_lifetime,
-		&lifetime, sizeof(struct timeval));
+	entry->positive_cache_params.max_lifetime = lifetime;
+	entry->mp_cache_params.max_lifetime = lifetime;
 
 	TRACE_OUT(set_positive_time_to_live);
 }
@@ -161,8 +159,7 @@
 
 	entry = find_create_entry(config, entry_name);
 	assert(entry != NULL);
-	memcpy(&entry->negative_cache_params.max_lifetime,
-		&lifetime, sizeof(struct timeval));
+	entry->negative_cache_params.max_lifetime = lifetime;
 
 	TRACE_OUT(set_negative_time_to_live);
 }
Index: query.c
===================================================================
--- query.c	(revision 272657)
+++ query.c	(working copy)
@@ -451,9 +451,8 @@
 
 		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
 		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
-			memcpy(&qstate->timeout,
-				&qstate->config_entry->common_query_timeout,
-				sizeof(struct timeval));
+			qstate->timeout =
+			    qstate->config_entry->common_query_timeout;
 
 	} else
 		write_response->error_code = -1;
@@ -532,9 +531,8 @@
 
 		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
 		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
-			memcpy(&qstate->timeout,
-				&qstate->config_entry->common_query_timeout,
-				sizeof(struct timeval));
+			qstate->timeout =
+			    qstate->config_entry->common_query_timeout;
 	} else
 		write_response->error_code = -1;
 
@@ -806,9 +804,8 @@
 
 		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
 		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
-			memcpy(&qstate->timeout,
-				&qstate->config_entry->common_query_timeout,
-				sizeof(struct timeval));
+			qstate->timeout =
+			    qstate->config_entry->common_query_timeout;
 	} else
 		read_response->error_code = -1;
 

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5187301.oT50I74Vz0>