diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-04 06:43:15 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-04 06:43:15 +0000 |
commit | 75f1032d17f5660afeec30943c0c7c0ab37d16a9 (patch) | |
tree | 4285bed7997029a49d08ee9b363d8c8a0d02cd5f /src/arm | |
parent | aa4361ff05e8cecfa11ca0d1fdc94be0503db07b (diff) | |
download | gnunet-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.c | 85 |
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); |