From 7215e481030ceee395e517e4e195aeba3d467fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Sun, 29 Jan 2023 15:24:15 +0100 Subject: fix use after free in torrent structs remove_torrent was doing wrong things when first torrent in LL was to be removed --- README.md | 8 +++--- src/dht.c | 85 ++++++++++++++++---------------------------------------------- src/main.c | 12 ++++++--- 3 files changed, 34 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 514f7b9..abfdc94 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ # todo * use ppoll * implement BEP-0042 DHT security extension, requires crc32c library -* metadata receiving from uTorrent does not work for some unknown reason +* metadata receiving from uTorrent does not work for some unknown reason (fixed) * uses A LOT of bandwidth, implement packet deduplication (fixed?) +* analysis: geoip for queries, get their localtime and update counter for current 15 minute period in countries time(queries) chart # anti sybil measures: -* analysis: geoip for queries, get their localtime and update counter for current 15 minute period in countries time(queries) chart -* only get_peers when aren't any peers to test -* periodic counter for packets that resets on periodic call, breaks into debugger if any of the following is larger than 2**14: +* only get_peers when aren't any peers to test (done) +* periodic counter for packets that resets on periodic call, assert none of the following is larger than 2**14: (done) - received queries - sent queries - received responses diff --git a/src/dht.c b/src/dht.c index c5fd98b..dc3ff77 100644 --- a/src/dht.c +++ b/src/dht.c @@ -343,6 +343,7 @@ struct torrent { int recvd; /**< length of received data for current packet */ char * software; /**< can be read from disconnection() - software string client sent, may be NULL */ time_t ttl; /**< if nonzero, torrent will get his ->type cleared after this seconds() timestamp. set to seconds()+512 for example */ + unsigned canary; /**< for debugging purposes. assert that it's zero. set in free. */ }; /** @@ -404,6 +405,7 @@ void torrent_free (struct torrent * t) { } free(t->software); free(t->metadata); + t->canary = UINT_MAX; free(t); } @@ -447,6 +449,17 @@ void torrent_print (FILE * s, const struct torrent * t) { } } +/** + * assert that torrent linked list is correct and contains no freed structures + * + * @param t [in] first element of torrent linked list + */ + +void torrent_ll_assert (const struct torrent * t) { + for (; t != NULL; t = t->next) + assert(!t->canary); +} + /** * what to log to FILE * from L() */ @@ -532,6 +545,7 @@ struct dht { unsigned txqp; unsigned rxrp; unsigned txrp; + unsigned removed_torrents; }; /** @@ -1172,7 +1186,7 @@ int bucket_grade (const struct dht * d, const struct bucket * b) { if (node_count(b->nodes) < K) return 0; struct node * n = b->nodes; - if (n) { + while (n) { if (node_grade(n) == bad) return 0; n = n->next; @@ -1321,6 +1335,8 @@ void remove_torrent (struct dht * d, struct torrent * t) { t->prev->next = t->next; if (t->next) t->next->prev = t->prev; + if (t == d->torrents) + d->torrents = t->next; struct peer * p = t->peers; while (p) { d->peers_num--; @@ -1328,6 +1344,8 @@ void remove_torrent (struct dht * d, struct torrent * t) { } d->torrents_num--; torrent_free(t); + torrent_ll_assert(d->torrents); + d->removed_torrents++; } /** @@ -1962,7 +1980,7 @@ void handle (struct dht * d, char * pkt, int len, struct sockaddr_in6 addr) { memcpy(&peer->addr, &addr, sizeof addr); if (bpath(b, "a/port") && (!bpath(b, "a/implied_port") || !bpath(b, "a/implied_port")->intvalue)) peer->addr.sin6_port = htons(bpath(b, "a/port")->intvalue); - peer = add_peer(d, torrent, peer); + add_peer(d, torrent, peer); break; default: // see NOTE01 ; @@ -2299,70 +2317,12 @@ void periodic (struct dht * d) { res_nclose(&state); // receiving and resolving SRV->{A,AAAA} in handle() } t: - ; + torrent_ll_assert(d->torrents); struct torrent * t = d->torrents; while (t) { if (t->ttl && seconds() > t->ttl) t->type = 0; if (t->type & (peers | announce)) { - /* - struct node * n = t->nodes; - int c = node_count(n); - if (!c) { -#define RTGP(buckets) {struct bucket * b = d->buckets; \ - find(t->hash, &b, NULL); \ - struct node * n = b->nodes; \ - c = node_count(n); \ - if (c) { \ - c = rand() % c; \ - while (c--) \ - n = n->next; \ - if (!n->unanswered) \ - n->last_sent = seconds(); \ - n->unanswered++; \ - get_peers(d, &n->addr, t->hash); \ - } else { \ - struct bucket * b = d->buckets; \ - c = 0; \ - while (b) { \ - c += node_count(b->nodes); \ - b = b->next; \ - } \ - if (c) { \ - c = rand() % c; \ - b = d->buckets; \ - int i = 0; \ - while (b) { \ - struct node * n = b->nodes; \ - while (n) { \ - if (i++ == c) { \ - i = -1; \ - if (!n->unanswered) \ - n->last_sent = seconds(); \ - n->unanswered++; \ - get_peers(d, &n->addr, t->hash); \ - break; \ - } \ - n = n->nodes; \ - } \ - if (i == -1) \ - break; \ - b = b->next; \ - } \ - } \ - } - RTGP(buckets); - RTGP(buckets6); - } else { - c = rand() % c; - while (c--) - n = n->next; - if (!n->unanswered) - n->last_sent = seconds(); - n->unanswered++; - get_peers(d, &n->addr, t->hash); - } - */ struct node * n = t->nodes; int sent = 0; while (n) { @@ -2463,8 +2423,7 @@ void periodic (struct dht * d) { t = t->next; } L(debug, d, "txqp=%u rxrp=%u rxqp=%u txrp=%u", d->txqp, d->rxrp, d->rxqp, d->txrp); - if (d->txqp > 16384 || d->rxrp > 16384 || d->rxqp > 16384 || d->txrp > 16384) - raise(SIGINT); + assert(!(d->txqp > 16384 || d->rxrp > 16384 || d->rxqp > 16384 || d->txrp > 16384)); d->txqp = d->txrp = d->rxqp = d->rxrp = 0; } diff --git a/src/main.c b/src/main.c index 4368e21..b42c873 100644 --- a/src/main.c +++ b/src/main.c @@ -66,6 +66,8 @@ int main (int argc, char ** argv) { struct pollfd * pollfds = NULL; int r = 0; struct dht * dht = NULL; + char * cfr = NULL; + struct bencoding * config = NULL; struct sigaction sigact = { .sa_handler = handler, .sa_flags = SA_RESTART @@ -110,15 +112,15 @@ int main (int argc, char ** argv) { r = 12; goto r; } - char * cfr = NULL; if (statbuf.st_size && !(cfr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, cf, 0))) { error_at_line(0, errno, __FILE__, __LINE__, "mmap(NULL, %ld, PROT_READ, MAP_SHARED, cf, 0)", statbuf.st_size); r = 13; goto r; } - struct bencoding * config = bdecode(cfr, statbuf.st_size, replace); + config = bdecode(cfr, statbuf.st_size, replace); dht = dht_init(config); free_bencoding(config); + config = NULL; dht->possible_torrent = found_torrent; dht->connection = connection; pollfds = malloc(sizeof *pollfds); @@ -197,13 +199,15 @@ w: goto r; } bencode(cfr, config); - free_bencoding(config); - config = NULL; r: if (dht) { dht_free(dht); dht = NULL; } + if (config) { + free_bencoding(config); + config = NULL; + } if (cfr && munmap(cfr, statbuf.st_size) == -1) error_at_line(0, errno, __FILE__, __LINE__, "munmap(cf, %ld)", statbuf.st_size); if (close(cf) == -1) -- cgit v1.2.3