diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-07-14 16:44:45 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-07-14 16:44:45 +0000 |
commit | b247968ea031953cc33f88372962b9bb69052b8a (patch) | |
tree | f5b15d286d95a8f0d5c7b662352092452016d367 | |
parent | 8766ccd1af741881379c16f1c2947edd32819e62 (diff) | |
download | gnunet-b247968ea031953cc33f88372962b9bb69052b8a.tar.gz gnunet-b247968ea031953cc33f88372962b9bb69052b8a.zip |
fixing use-after free and/or possible bad recursion on disconnect
-rw-r--r-- | src/transport/gnunet-service-transport.c | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index dd367d38a..1141bdb64 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c | |||
@@ -566,6 +566,11 @@ struct NeighbourList | |||
566 | int public_key_valid; | 566 | int public_key_valid; |
567 | 567 | ||
568 | /** | 568 | /** |
569 | * Are we already in the process of disconnecting this neighbour? | ||
570 | */ | ||
571 | int in_disconnect; | ||
572 | |||
573 | /** | ||
569 | * Performance data for the peer. | 574 | * Performance data for the peer. |
570 | */ | 575 | */ |
571 | struct GNUNET_TRANSPORT_ATS_Information *ats; | 576 | struct GNUNET_TRANSPORT_ATS_Information *ats; |
@@ -1614,21 +1619,16 @@ transmit_send_continuation (void *cls, | |||
1614 | n = find_neighbour (&mq->neighbour_id); | 1619 | n = find_neighbour (&mq->neighbour_id); |
1615 | if (mq->client != NULL) | 1620 | if (mq->client != NULL) |
1616 | transmit_send_ok (mq->client, n, target, result); | 1621 | transmit_send_ok (mq->client, n, target, result); |
1617 | if (n != NULL) | 1622 | GNUNET_assert (n != NULL); |
1618 | { | 1623 | GNUNET_CONTAINER_DLL_remove (n->cont_head, |
1619 | GNUNET_CONTAINER_DLL_remove (n->cont_head, | 1624 | n->cont_tail, |
1620 | n->cont_tail, | 1625 | mq); |
1621 | mq); | ||
1622 | } | ||
1623 | GNUNET_free (mq); | 1626 | GNUNET_free (mq); |
1624 | if (n != NULL) | 1627 | if (result == GNUNET_OK) |
1625 | { | 1628 | try_transmission_to_peer (n); |
1626 | if (result == GNUNET_OK) | 1629 | else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task) |
1627 | try_transmission_to_peer (n); | 1630 | n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, |
1628 | else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task) | 1631 | n); |
1629 | n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, | ||
1630 | n); | ||
1631 | } | ||
1632 | } | 1632 | } |
1633 | 1633 | ||
1634 | 1634 | ||
@@ -4853,6 +4853,8 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
4853 | struct ForeignAddressList *peer_addresses; | 4853 | struct ForeignAddressList *peer_addresses; |
4854 | struct ForeignAddressList *peer_pos; | 4854 | struct ForeignAddressList *peer_pos; |
4855 | 4855 | ||
4856 | if (GNUNET_YES == n->in_disconnect) | ||
4857 | return; | ||
4856 | if (GNUNET_YES == check) | 4858 | if (GNUNET_YES == check) |
4857 | { | 4859 | { |
4858 | rpos = n->plugins; | 4860 | rpos = n->plugins; |
@@ -4861,7 +4863,7 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
4861 | peer_addresses = rpos->addresses; | 4863 | peer_addresses = rpos->addresses; |
4862 | while (peer_addresses != NULL) | 4864 | while (peer_addresses != NULL) |
4863 | { | 4865 | { |
4864 | // Do not disconnect if: an address is connected or an inbound address exists | 4866 | /* Do not disconnect if: an address is connected or an inbound address exists */ |
4865 | if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0)) | 4867 | if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0)) |
4866 | { | 4868 | { |
4867 | #if DEBUG_TRANSPORT | 4869 | #if DEBUG_TRANSPORT |
@@ -4884,20 +4886,7 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
4884 | "Disconnecting from `%4s'\n", | 4886 | "Disconnecting from `%4s'\n", |
4885 | GNUNET_i2s (&n->id)); | 4887 | GNUNET_i2s (&n->id)); |
4886 | #endif | 4888 | #endif |
4887 | 4889 | n->in_disconnect = GNUNET_YES; /* prevent recursive entry */ | |
4888 | /* remove n from neighbours list */ | ||
4889 | nprev = NULL; | ||
4890 | npos = neighbours; | ||
4891 | while ((npos != NULL) && (npos != n)) | ||
4892 | { | ||
4893 | nprev = npos; | ||
4894 | npos = npos->next; | ||
4895 | } | ||
4896 | GNUNET_assert (npos != NULL); | ||
4897 | if (nprev == NULL) | ||
4898 | neighbours = n->next; | ||
4899 | else | ||
4900 | nprev->next = n->next; | ||
4901 | 4890 | ||
4902 | /* notify all clients about disconnect */ | 4891 | /* notify all clients about disconnect */ |
4903 | if (GNUNET_YES == n->received_pong) | 4892 | if (GNUNET_YES == n->received_pong) |
@@ -4989,6 +4978,21 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
4989 | GNUNET_NO); | 4978 | GNUNET_NO); |
4990 | n->piter = NULL; | 4979 | n->piter = NULL; |
4991 | } | 4980 | } |
4981 | |||
4982 | /* remove n from neighbours list */ | ||
4983 | nprev = NULL; | ||
4984 | npos = neighbours; | ||
4985 | while ((npos != NULL) && (npos != n)) | ||
4986 | { | ||
4987 | nprev = npos; | ||
4988 | npos = npos->next; | ||
4989 | } | ||
4990 | GNUNET_assert (npos != NULL); | ||
4991 | if (nprev == NULL) | ||
4992 | neighbours = n->next; | ||
4993 | else | ||
4994 | nprev->next = n->next; | ||
4995 | |||
4992 | /* finally, free n itself */ | 4996 | /* finally, free n itself */ |
4993 | GNUNET_STATISTICS_update (stats, | 4997 | GNUNET_STATISTICS_update (stats, |
4994 | gettext_noop ("# active neighbours"), | 4998 | gettext_noop ("# active neighbours"), |