aboutsummaryrefslogtreecommitdiff
path: root/src/arm
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-04 06:43:15 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-04 06:43:15 +0000
commit75f1032d17f5660afeec30943c0c7c0ab37d16a9 (patch)
tree4285bed7997029a49d08ee9b363d8c8a0d02cd5f /src/arm
parentaa4361ff05e8cecfa11ca0d1fdc94be0503db07b (diff)
downloadgnunet-75f1032d17f5660afeec30943c0c7c0ab37d16a9.tar.gz
gnunet-75f1032d17f5660afeec30943c0c7c0ab37d16a9.zip
LRN: Fix a rare arm-interceptor double-free bug
Diffstat (limited to 'src/arm')
-rw-r--r--src/arm/gnunet-service-arm_interceptor.c85
1 files changed, 56 insertions, 29 deletions
diff --git a/src/arm/gnunet-service-arm_interceptor.c b/src/arm/gnunet-service-arm_interceptor.c
index 237b9bf95..8f4a4731c 100644
--- a/src/arm/gnunet-service-arm_interceptor.c
+++ b/src/arm/gnunet-service-arm_interceptor.c
@@ -194,6 +194,10 @@ struct ForwardedConnection
194 */ 194 */
195 int first_write_done; 195 int first_write_done;
196 196
197 /**
198 * Reference count (the structure is freed when it reaches zero)
199 */
200 int reference_count;
197}; 201};
198 202
199/** 203/**
@@ -289,14 +293,8 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
289 { 293 {
290#if DEBUG_SERVICE_MANAGER 294#if DEBUG_SERVICE_MANAGER
291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292 "Stopping forwarding from service to client\n", 296 "Stopping forwarding from service to client\n");
293 fc->listen_info->serviceName);
294#endif 297#endif
295 if (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK)
296 {
297 GNUNET_SCHEDULER_cancel (fc->service_to_client_task);
298 fc->service_to_client_task = GNUNET_SCHEDULER_NO_TASK;
299 }
300 if (fc->armClientSocket != NULL) 298 if (fc->armClientSocket != NULL)
301 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, 299 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
302 SHUT_WR); 300 SHUT_WR);
@@ -308,14 +306,8 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
308 { 306 {
309#if DEBUG_SERVICE_MANAGER 307#if DEBUG_SERVICE_MANAGER
310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311 "Stopping forwarding from client to service\n", 309 "Stopping forwarding from client to service\n");
312 fc->listen_info->serviceName);
313#endif 310#endif
314 if (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK)
315 {
316 GNUNET_SCHEDULER_cancel (fc->client_to_service_task);
317 fc->client_to_service_task = GNUNET_SCHEDULER_NO_TASK;
318 }
319 if (fc->armClientSocket != NULL) 311 if (fc->armClientSocket != NULL)
320 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket, 312 GNUNET_NETWORK_socket_shutdown (fc->armClientSocket,
321 SHUT_RD); 313 SHUT_RD);
@@ -323,27 +315,44 @@ closeClientAndServiceSockets (struct ForwardedConnection *fc,
323 GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket, 315 GNUNET_NETWORK_socket_shutdown (fc->armServiceSocket,
324 SHUT_WR); 316 SHUT_WR);
325 } 317 }
326 if ( (fc->client_to_service_task != GNUNET_SCHEDULER_NO_TASK) ||
327 (fc->service_to_client_task != GNUNET_SCHEDULER_NO_TASK) )
328 return;
329#if DEBUG_SERVICE_MANAGER 318#if DEBUG_SERVICE_MANAGER
330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
331 "Closing forwarding connection (done with both directions)\n"); 320 "Closing forwarding connection (done with both directions)\n");
332#endif 321#endif
333 if (fc->start_task != GNUNET_SCHEDULER_NO_TASK) 322 fc->reference_count -= 1;
334 GNUNET_SCHEDULER_cancel (fc->start_task); 323 if (fc->reference_count <= 0)
335 if ( (NULL != fc->armClientSocket) && 324 {
336 (GNUNET_SYSERR == 325 if ( (NULL != fc->armClientSocket) &&
326 (GNUNET_SYSERR ==
337 GNUNET_NETWORK_socket_close (fc->armClientSocket)) ) 327 GNUNET_NETWORK_socket_close (fc->armClientSocket)) )
338 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); 328 {
339 if ( (NULL != fc->armServiceSocket) && 329 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
340 (GNUNET_SYSERR == 330 fc->armClientSocket = NULL;
331 }
332 if ( (NULL != fc->armServiceSocket) &&
333 (GNUNET_SYSERR ==
341 GNUNET_NETWORK_socket_close (fc->armServiceSocket)) ) 334 GNUNET_NETWORK_socket_close (fc->armServiceSocket)) )
342 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); 335 {
343 GNUNET_free (fc->listen_info->serviceName); 336 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close");
344 GNUNET_free (fc->listen_info->service_addr); 337 fc->armServiceSocket = NULL;
345 GNUNET_free (fc->listen_info); 338 }
346 GNUNET_free (fc); 339 if (fc->listen_info != NULL)
340 {
341 if (fc->listen_info->serviceName != NULL)
342 {
343 GNUNET_free (fc->listen_info->serviceName);
344 fc->listen_info->serviceName = NULL;
345 }
346 if (fc->listen_info->service_addr != NULL)
347 {
348 GNUNET_free (fc->listen_info->service_addr);
349 fc->listen_info->service_addr = NULL;
350 }
351 GNUNET_free (fc->listen_info);
352 fc->listen_info = NULL;
353 }
354 GNUNET_free (fc);
355 }
347} 356}
348 357
349 358
@@ -703,6 +712,11 @@ receiveFromClient (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
703 GNUNET_TIME_UNIT_FOREVER_REL, 712 GNUNET_TIME_UNIT_FOREVER_REL,
704 fc->armServiceSocket, 713 fc->armServiceSocket,
705 &forwardToService, fc); 714 &forwardToService, fc);
715 else
716 /* We have not added any task with fc as a closure, so we're
717 * dropping our reference to fc
718 */
719 fc->reference_count -= 1;
706} 720}
707 721
708 722
@@ -728,6 +742,12 @@ fc_acceptConnection (void *cls,
728 GNUNET_free (fc->listen_info->service_addr); 742 GNUNET_free (fc->listen_info->service_addr);
729 fc->listen_info->service_addr = sli->service_addr; 743 fc->listen_info->service_addr = sli->service_addr;
730 fc->listen_info->service_addr_len = sli->service_addr_len; 744 fc->listen_info->service_addr_len = sli->service_addr_len;
745 /* Drop fc reference count prematurely, it'll be incremented
746 * once or twice in the following conditional branches.
747 * This is, apparently, the place where reference count increases
748 * past 1.
749 */
750 fc->reference_count -= 1;
731 if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK) 751 if (fc->client_to_service_task == GNUNET_SCHEDULER_NO_TASK)
732 { 752 {
733 if (fc->client_to_service_bufferDataLength == 0) 753 if (fc->client_to_service_bufferDataLength == 0)
@@ -740,6 +760,7 @@ fc_acceptConnection (void *cls,
740 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, 760 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
741 fc->armServiceSocket, 761 fc->armServiceSocket,
742 &forwardToService, fc); 762 &forwardToService, fc);
763 fc->reference_count += 1;
743 } 764 }
744 if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK) 765 if (fc->service_to_client_task == GNUNET_SCHEDULER_NO_TASK)
745 { 766 {
@@ -753,6 +774,7 @@ fc_acceptConnection (void *cls,
753 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, 774 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
754 fc->armClientSocket, 775 fc->armClientSocket,
755 &forwardToClient, fc); 776 &forwardToClient, fc);
777 fc->reference_count += 1;
756 } 778 }
757 GNUNET_free (sli); 779 GNUNET_free (sli);
758} 780}
@@ -951,6 +973,7 @@ accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo)
951 struct ForwardedConnection *fc; 973 struct ForwardedConnection *fc;
952 974
953 fc = GNUNET_malloc (sizeof (struct ForwardedConnection)); 975 fc = GNUNET_malloc (sizeof (struct ForwardedConnection));
976 fc->reference_count = 1;
954 fc->listen_info = serviceListeningInfo; 977 fc->listen_info = serviceListeningInfo;
955 fc->service_to_client_bufferPos = fc->service_to_client_buffer; 978 fc->service_to_client_bufferPos = fc->service_to_client_buffer;
956 fc->client_to_service_bufferPos = fc->client_to_service_buffer; 979 fc->client_to_service_bufferPos = fc->client_to_service_buffer;
@@ -988,6 +1011,10 @@ accept_and_forward (struct ServiceListeningInfo *serviceListeningInfo)
988 fc->armClientSocket, 1011 fc->armClientSocket,
989 &receiveFromClient, fc); 1012 &receiveFromClient, fc);
990 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task); 1013 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == fc->start_task);
1014 /* We're creating another chain of tasks for this fc that
1015 * will have its own reference to it.
1016 */
1017 fc->reference_count += 1;
991 fc->start_task 1018 fc->start_task
992 = GNUNET_SCHEDULER_add_now (&start_forwarding, 1019 = GNUNET_SCHEDULER_add_now (&start_forwarding,
993 fc); 1020 fc);