Witold Filipczyk <[EMAIL PROTECTED]> writes:

> +     uri = get_uri(uri_string.source, URI_BASE);
> +     done_string(&uri_string);
> +     if (!uri) {
> +             done_bittorrent_peer_connection(peer);
> +             return BITTORRENT_STATE_OUT_OF_MEM;
> +     }
> +     uri->protocol = PROTOCOL_BITTORRENT;

Changing uri->protocol like that is not safe, I think.  get_uri()
may have returned a cached URI to which there are other references.
Because a malicious BitTorrent tracker can return arbitrary
hostnames in the peer list, and this code will then change the
protocol of the corresponding HTTP URIs to BitTorrent and affect
future accesses to those hosts, I think this needs to be fixed.
A pretty clear solution is to add a "bittorrent-peer" URI scheme
for use in these connections, but other fixes are fine too.

The following patch is also available from a Git repository:
git://repo.or.cz/elinks/kon.git 0.12/bittorrent-peer-uri

Fix blacklist crash in BitTorrent

make_bittorrent_peer_connection() used to construct a struct uri on
the stack. This was hacky but worked nicely because the struct uri
was not really accessed after make_connection() returned.  However,
since commit a83ff1f565a4a7bc25a4b8353ee26bc1b97410e3, the struct uri
is also needed when the connection is being closed.  Valgrind shows:

Invalid read of size 2
   at 0x8100764: get_blacklist_entry (blacklist.c:33)
   by 0x8100985: del_blacklist_entry (blacklist.c:64)
   by 0x80DA579: complete_connect_socket (socket.c:448)
   by 0x80DA84A: connected (socket.c:513)
   by 0x80D0DDF: select_loop (select.c:297)
   by 0x80D00C6: main (main.c:353)
 Address 0xBEC3BFAE is just below the stack ptr.  To suppress, use: 
--workaround-gcc296-bugs=yes

To fix this, allocate the struct uri on the heap instead, by
constructing a string and giving that to get_uri().  This string
cannot use the "bittorrent" URI scheme because parse_uri() does not
recognize the host and port fields in that.  (The "bittorrent" scheme
has protocol_backend.free_syntax = 1 in order to support strings like
"bittorrent:http://beta.legaltorrents.com/get/159-noisome-beasts";.)
Instead, define a new "bittorrent-peer" URI scheme for this purpose.
If the user attempts to use this URI scheme, its handler aborts the
connection with an error; but when make_bittorrent_peer_connection()
uses a bittorrent-peer URI, the handler is not called.

This change also lets get_uri() set the ipv6 flag if peer_info->ip is
an IPv6 address literal.

Reported by Witold Filipczyk.

---
commit d93bceb9bd6ab32c614ac20dc5c87e3af2a7f85f
tree a32c808927944db6717398c8595626c958008579
parent 7de8b9940c96f51c55c2706ed9aa6ad11257d7ee
author Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sun, 07 Sep 2008 06:10:52 +0300
committer Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sun, 07 Sep 2008 06:31:36 
+0300

 src/network/state.c                   |    1 +
 src/network/state.h                   |    1 +
 src/protocol/bittorrent/connection.c  |    6 ++++
 src/protocol/bittorrent/connection.h  |    2 +
 src/protocol/bittorrent/peerconnect.c |   45 ++++++++++++++++++++-------------
 src/protocol/protocol.c               |    1 +
 src/protocol/protocol.h               |    1 +
 7 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/src/network/state.c b/src/network/state.c
index 3a94982..9ecd6f3 100644
--- a/src/network/state.c
+++ b/src/network/state.c
@@ -124,6 +124,7 @@ static const struct s_msg_dsc msg_dsc[] = {
        {S_BITTORRENT_METAINFO, N_("The BitTorrent metainfo file contained 
errors")},
        {S_BITTORRENT_TRACKER,  N_("The tracker requesting failed")},
        {S_BITTORRENT_BAD_URL,  N_("The BitTorrent URL does not point to a 
valid URL")},
+       {S_BITTORRENT_PEER_URL, N_("The bittorrent-peer URL scheme is for 
internal use only")},
 #endif
 
        /* fsp_open_session() failed but did not set errno.
diff --git a/src/network/state.h b/src/network/state.h
index 16faf41..f8358b2 100644
--- a/src/network/state.h
+++ b/src/network/state.h
@@ -103,6 +103,7 @@ enum connection_basic_state {
        S_BITTORRENT_METAINFO   = -100801,
        S_BITTORRENT_TRACKER    = -100802,
        S_BITTORRENT_BAD_URL    = -100803,
+       S_BITTORRENT_PEER_URL   = -100804,
 
        S_FSP_OPEN_SESSION_UNKN = -100900,
 };
diff --git a/src/protocol/bittorrent/connection.c 
b/src/protocol/bittorrent/connection.c
index f15bfe8..132283b 100644
--- a/src/protocol/bittorrent/connection.c
+++ b/src/protocol/bittorrent/connection.c
@@ -414,3 +414,9 @@ bittorrent_protocol_handler(struct connection *conn)
                              bittorrent_metainfo_callback, conn, 0);
        done_uri(uri);
 }
+
+void
+bittorrent_peer_protocol_handler(struct connection *conn)
+{
+       abort_connection(conn, connection_state(S_BITTORRENT_PEER_URL));
+}
diff --git a/src/protocol/bittorrent/connection.h 
b/src/protocol/bittorrent/connection.h
index af6c89d..13aeca0 100644
--- a/src/protocol/bittorrent/connection.h
+++ b/src/protocol/bittorrent/connection.h
@@ -9,8 +9,10 @@ struct connection;
 
 #ifdef CONFIG_BITTORRENT
 extern protocol_handler_T bittorrent_protocol_handler;
+extern protocol_handler_T bittorrent_peer_protocol_handler;
 #else
 #define bittorrent_protocol_handler NULL
+#define bittorrent_peer_protocol_handler NULL
 #endif
 
 void update_bittorrent_connection_state(struct connection *conn);
diff --git a/src/protocol/bittorrent/peerconnect.c 
b/src/protocol/bittorrent/peerconnect.c
index 8db7211..7f4158c 100644
--- a/src/protocol/bittorrent/peerconnect.c
+++ b/src/protocol/bittorrent/peerconnect.c
@@ -271,12 +271,13 @@ enum bittorrent_state
 make_bittorrent_peer_connection(struct bittorrent_connection *bittorrent,
                                struct bittorrent_peer *peer_info)
 {
-       struct uri uri;
+       enum bittorrent_state result = BITTORRENT_STATE_OUT_OF_MEM;
+       struct uri *uri = NULL;
+       struct string uri_string = NULL_STRING;
        struct bittorrent_peer_connection *peer;
-       unsigned char port[5];
 
        peer = init_bittorrent_peer_connection(-1);
-       if (!peer) return BITTORRENT_STATE_OUT_OF_MEM;
+       if (!peer) goto out;
 
        peer->local.initiater = 1;
 
@@ -284,10 +285,7 @@ make_bittorrent_peer_connection(struct 
bittorrent_connection *bittorrent,
        peer->bittorrent = bittorrent;
 
        peer->bitfield = init_bitfield(bittorrent->meta.pieces);
-       if (!peer->bitfield) {
-               done_bittorrent_peer_connection(peer);
-               return BITTORRENT_STATE_OUT_OF_MEM;
-       }
+       if (!peer->bitfield) goto out;
 
        memcpy(peer->id, peer_info->id, sizeof(peer->id));
 
@@ -295,17 +293,28 @@ make_bittorrent_peer_connection(struct 
bittorrent_connection *bittorrent,
         * can extract the IP address and port number. */
        /* FIXME: Rather change the make_connection() interface. This is an ugly
         * hack. */
-       /* FIXME: Set the ipv6 flag iff ... */
-       memset(&uri, 0, sizeof(uri));
-       uri.protocol = PROTOCOL_BITTORRENT;
-       uri.host     = peer_info->ip;
-       uri.hostlen  = strlen(peer_info->ip);
-       uri.port     = port;
-       uri.portlen  = snprintf(port, sizeof(port), "%u", peer_info->port);
-
-       make_connection(peer->socket, &uri, send_bittorrent_peer_handshake, 1);
-
-       return BITTORRENT_STATE_OK;
+       if (!init_string(&uri_string)) goto out;
+       if (!add_format_to_string(&uri_string,
+#ifdef CONFIG_IPV6
+                                 strchr(peer_info->ip, ':') ?
+                                 "bittorrent-peer://[%s]:%u/" :
+#endif
+                                 "bittorrent-peer://%s:%u/",
+                                 peer_info->ip, (unsigned) peer_info->port))
+               goto out;
+       uri = get_uri(uri_string.source, 0);
+       if (!uri) goto out;
+
+       make_connection(peer->socket, uri, send_bittorrent_peer_handshake, 1);
+       result = BITTORRENT_STATE_OK;
+
+out:
+       if (uri)
+               done_uri(uri);
+       done_string(&uri_string);
+       if (peer && result != BITTORRENT_STATE_OK)
+               done_bittorrent_peer_connection(peer);
+       return result;
 }
 
 
diff --git a/src/protocol/protocol.c b/src/protocol/protocol.c
index 3330365..e43adc2 100644
--- a/src/protocol/protocol.c
+++ b/src/protocol/protocol.c
@@ -58,6 +58,7 @@ struct protocol_backend {
 static const struct protocol_backend protocol_backends[] = {
        { "about",         0, about_protocol_handler,           0, 0, 1, 0, 1 },
        { "bittorrent",    0, bittorrent_protocol_handler,      0, 0, 1, 0, 1 },
+       { "bittorrent-peer",0,bittorrent_peer_protocol_handler, 1, 1, 0, 0, 1 },
        { "data",          0, data_protocol_handler,            0, 0, 1, 0, 1 },
        { "file",          0, file_protocol_handler,            1, 0, 0, 0, 0 },
        { "finger",       79, finger_protocol_handler,          1, 1, 0, 0, 1 },
diff --git a/src/protocol/protocol.h b/src/protocol/protocol.h
index c02e671..d009bc0 100644
--- a/src/protocol/protocol.h
+++ b/src/protocol/protocol.h
@@ -11,6 +11,7 @@ struct uri;
 enum protocol {
        PROTOCOL_ABOUT,
        PROTOCOL_BITTORRENT,
+       PROTOCOL_BITTORRENT_PEER,
        PROTOCOL_DATA,
        PROTOCOL_FILE,
        PROTOCOL_FINGER,

Attachment: pgpk6hZot3CLz.pgp
Description: PGP signature

_______________________________________________
elinks-dev mailing list
elinks-dev@linuxfromscratch.org
http://linuxfromscratch.org/mailman/listinfo/elinks-dev

Reply via email to