View | Details | Raw Unified | Return to bug 225917
Collapse All | Expand All

(-)net-p2p/transmission-cli/Makefile (-2 / +2 lines)
Lines 1-8 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
PORTNAME=	transmission
3
PORTNAME=	transmission
4
PORTVERSION=	2.92
4
PORTVERSION=	2.93
5
PORTREVISION?=	3
5
PORTREVISION?=	0
6
CATEGORIES?=	net-p2p
6
CATEGORIES?=	net-p2p
7
MASTER_SITES=	https://github.com/transmission/transmission-releases/raw/master/ \
7
MASTER_SITES=	https://github.com/transmission/transmission-releases/raw/master/ \
8
		http://transmission.cachefly.net/
8
		http://transmission.cachefly.net/
(-)net-p2p/transmission-cli/distinfo (-2 / +3 lines)
Lines 1-2 Link Here
1
SHA256 (transmission-2.92.tar.xz) = 3a8d045c306ad9acb7bf81126939b9594553a388482efa0ec1bfb67b22acd35f
1
TIMESTAMP = 1518561250
2
SIZE (transmission-2.92.tar.xz) = 3378116
2
SHA256 (transmission-2.93.tar.xz) = 8815920e0a4499bcdadbbe89a4115092dab42ce5199f71ff9a926cfd12b9b90b
3
SIZE (transmission-2.93.tar.xz) = 3363868
(-)net-p2p/transmission-cli/files/patch-fix_dns_rebinding_vuln (-302 lines)
Lines 1-302 Link Here
1
Fix a weakness that allows remote code execution via the Transmission
2
RPC server using DNS rebinding:
3
4
https://bugs.chromium.org/p/project-zero/issues/detail?id=1447
5
6
Patch adapted from Tavis Ormandy's patch on the Transmission master
7
branch to the Transmission 2.92 release by Leo Famulari
8
<leo@famulari.name>:
9
10
https://github.com/transmission/transmission/pull/468/commits
11
12
From fe2d3c6e75088f3d9b6040ce06da3d530358bc2f Mon Sep 17 00:00:00 2001
13
From: Tavis Ormandy <taviso@google.com>
14
Date: Thu, 11 Jan 2018 10:00:41 -0800
15
Subject: [PATCH] mitigate dns rebinding attacks against daemon
16
17
---
18
 libtransmission/quark.c        |   2 + 
19
 libtransmission/quark.h        |   2 + 
20
 libtransmission/rpc-server.c   | 116 +++++++++++++++++++++++++++++++++++++----
21
 libtransmission/rpc-server.h   |   4 ++
22
 libtransmission/session.c      |   2 + 
23
 libtransmission/transmission.h |   1 + 
24
 libtransmission/web.c          |   3 ++
25
 7 files changed, 121 insertions(+), 9 deletions(-)
26
27
diff --git a/libtransmission/quark.c b/libtransmission/quark.c
28
index 30cc2bca4..b4fd7aabd 100644
29
--- libtransmission/quark.c.orig
30
+++ libtransmission/quark.c
31
@@ -289,6 +289,8 @@ static const struct tr_key_struct my_static[] =
32
   { "rpc-authentication-required", 27 },
33
   { "rpc-bind-address", 16 },
34
   { "rpc-enabled", 11 },
35
+  { "rpc-host-whitelist", 18 },
36
+  { "rpc-host-whitelist-enabled", 26 },
37
   { "rpc-password", 12 },
38
   { "rpc-port", 8 },
39
   { "rpc-url", 7 },
40
diff --git a/libtransmission/quark.h b/libtransmission/quark.h
41
index 7f5212733..17464be8f 100644
42
--- libtransmission/quark.h.orig
43
+++ libtransmission/quark.h
44
@@ -291,6 +291,8 @@ enum
45
   TR_KEY_rpc_authentication_required,
46
   TR_KEY_rpc_bind_address,
47
   TR_KEY_rpc_enabled,
48
+  TR_KEY_rpc_host_whitelist,
49
+  TR_KEY_rpc_host_whitelist_enabled,
50
   TR_KEY_rpc_password,
51
   TR_KEY_rpc_port,
52
   TR_KEY_rpc_url,
53
diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c
54
index a3485f3fa..292cd5fce 100644
55
--- libtransmission/rpc-server.c.orig
56
+++ libtransmission/rpc-server.c
57
@@ -52,6 +52,7 @@ struct tr_rpc_server
58
     bool               isEnabled;
59
     bool               isPasswordEnabled;
60
     bool               isWhitelistEnabled;
61
+    bool               isHostWhitelistEnabled;
62
     tr_port            port;
63
     char             * url;
64
     struct in_addr     bindAddress;
65
@@ -63,6 +64,7 @@ struct tr_rpc_server
66
     char             * password;
67
     char             * whitelistStr;
68
     tr_list          * whitelist;
69
+    tr_list          * hostWhitelist;
70
 
71
     char             * sessionId;
72
     time_t             sessionIdExpiresAt;
73
@@ -588,6 +590,49 @@ isAddressAllowed (const tr_rpc_server * server, const char * address)
74
   return false;
75
 }
76
 
77
+static bool isHostnameAllowed(tr_rpc_server const* server, struct evhttp_request* req)
78
+{
79
+    /* If password auth is enabled, any hostname is permitted. */
80
+    if (server->isPasswordEnabled)
81
+    {
82
+        return true;
83
+    }
84
+
85
+    char const* const host = evhttp_find_header(req->input_headers, "Host");
86
+
87
+    // If whitelist is disabled, no restrictions.
88
+    if (!server->isHostWhitelistEnabled)
89
+        return true;
90
+
91
+    /* No host header, invalid request. */
92
+    if (host == NULL)
93
+    {
94
+        return false;
95
+    }
96
+
97
+    /* Host header might include the port. */
98
+    char* const hostname = tr_strndup(host, strcspn(host, ":"));
99
+
100
+    /* localhost or ipaddress is always acceptable. */
101
+    if (strcmp(hostname, "localhost") == 0 || strcmp(hostname, "localhost.") == 0 || tr_addressIsIP(hostname))
102
+    {
103
+        tr_free(hostname);
104
+        return true;
105
+    }
106
+
107
+    /* Otherwise, hostname must be whitelisted. */
108
+    for (tr_list* l = server->hostWhitelist; l != NULL; l = l->next) {
109
+        if (tr_wildmat(hostname, l->data))
110
+        {
111
+            tr_free(hostname);
112
+            return true;
113
+        }
114
+    }
115
+
116
+    tr_free(hostname);
117
+    return false;
118
+}
119
+
120
 static bool
121
 test_session_id (struct tr_rpc_server * server, struct evhttp_request * req)
122
 {
123
@@ -663,6 +708,23 @@ handle_request (struct evhttp_request * req, void * arg)
124
           handle_upload (req, server);
125
         }
126
 #ifdef REQUIRE_SESSION_ID
127
+        else if (!isHostnameAllowed(server, req))
128
+        {
129
+            char* tmp = tr_strdup_printf(
130
+                "<p>Transmission received your request, but the hostname was unrecognized.</p>"
131
+                "<p>To fix this, choose one of the following options:"
132
+                "<ul>"
133
+                "<li>Enable password authentication, then any hostname is allowed.</li>"
134
+                "<li>Add the hostname you want to use to the whitelist in settings.</li>"
135
+                "</ul></p>"
136
+                "<p>If you're editing settings.json, see the 'rpc-host-whitelist' and 'rpc-host-whitelist-enabled' entries.</p>"
137
+                "<p>This requirement has been added to help prevent "
138
+                "<a href=\"https://en.wikipedia.org/wiki/DNS_rebinding\">DNS Rebinding</a> "
139
+                "attacks.</p>");
140
+            send_simple_response(req, 421, tmp);
141
+            tr_free(tmp);
142
+        }
143
+
144
       else if (!test_session_id (server, req))
145
         {
146
           const char * sessionId = get_current_session_id (server);
147
@@ -674,7 +736,7 @@ handle_request (struct evhttp_request * req, void * arg)
148
             "<li> When you get this 409 error message, resend your request with the updated header"
149
             "</ol></p>"
150
             "<p>This requirement has been added to help prevent "
151
-            "<a href=\"http://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
152
+            "<a href=\"https://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
153
             "attacks.</p>"
154
             "<p><code>%s: %s</code></p>",
155
             TR_RPC_SESSION_ID_HEADER, sessionId);
156
@@ -875,19 +937,14 @@ tr_rpcGetUrl (const tr_rpc_server * server)
157
   return server->url ? server->url : "";
158
 }
159
 
160
-void
161
-tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
162
+static void
163
+tr_rpcSetList (char const* whitelistStr, tr_list** list)
164
 {
165
   void * tmp;
166
   const char * walk;
167
 
168
-  /* keep the string */
169
-  tmp = server->whitelistStr;
170
-  server->whitelistStr = tr_strdup (whitelistStr);
171
-  tr_free (tmp);
172
-
173
   /* clear out the old whitelist entries */
174
-  while ((tmp = tr_list_pop_front (&server->whitelist)))
175
+  while ((tmp = tr_list_pop_front (list)) != NULL)
176
     tr_free (tmp);
177
 
178
   /* build the new whitelist entries */
179
@@ -896,7 +953,7 @@ tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
180
       const char * delimiters = " ,;";
181
       const size_t len = strcspn (walk, delimiters);
182
       char * token = tr_strndup (walk, len);
183
-      tr_list_append (&server->whitelist, token);
184
+      tr_list_append (list, token);
185
       if (strcspn (token, "+-") < len)
186
         tr_logAddNamedInfo (MY_NAME, "Adding address to whitelist: %s (And it has a '+' or '-'!  Are you using an old ACL by mistake?)", token);
187
       else
188
@@ -909,6 +966,21 @@ tr_rpcSetWhitelist (tr_rpc_server * server, const char * whitelistStr)
189
     }
190
 }
191
 
192
+void tr_rpcSetHostWhitelist(tr_rpc_server* server, char const* whitelistStr)
193
+{
194
+    tr_rpcSetList(whitelistStr, &server->hostWhitelist);
195
+}
196
+
197
+void tr_rpcSetWhitelist(tr_rpc_server* server, char const* whitelistStr)
198
+{
199
+    /* keep the string */
200
+    char* const tmp = server->whitelistStr;
201
+    server->whitelistStr = tr_strdup(whitelistStr);
202
+    tr_free(tmp);
203
+
204
+    tr_rpcSetList(whitelistStr, &server->whitelist);
205
+}
206
+
207
 const char*
208
 tr_rpcGetWhitelist (const tr_rpc_server * server)
209
 {
210
@@ -930,6 +1002,11 @@ tr_rpcGetWhitelistEnabled (const tr_rpc_server * server)
211
   return server->isWhitelistEnabled;
212
 }
213
 
214
+void tr_rpcSetHostWhitelistEnabled(tr_rpc_server* server, bool isEnabled)
215
+{
216
+    server->isHostWhitelistEnabled = isEnabled;
217
+}
218
+
219
 /****
220
 *****  PASSWORD
221
 ****/
222
@@ -1063,6 +1140,28 @@ tr_rpcInit (tr_session  * session, tr_variant * settings)
223
   else
224
     tr_rpcSetWhitelistEnabled (s, boolVal);
225
 
226
+  key = TR_KEY_rpc_host_whitelist_enabled;
227
+
228
+  if (!tr_variantDictFindBool(settings, key, &boolVal))
229
+  {
230
+      missing_settings_key(key);
231
+  }
232
+  else
233
+  {
234
+      tr_rpcSetHostWhitelistEnabled(s, boolVal);
235
+  }
236
+
237
+  key = TR_KEY_rpc_host_whitelist;
238
+
239
+  if (!tr_variantDictFindStr(settings, key, &str, NULL) && str != NULL)
240
+  {
241
+      missing_settings_key(key);
242
+  }
243
+  else
244
+  {
245
+      tr_rpcSetHostWhitelist(s, str);
246
+  }
247
+
248
   key = TR_KEY_rpc_authentication_required;
249
   if (!tr_variantDictFindBool (settings, key, &boolVal))
250
     missing_settings_key (key);
251
diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h
252
index e0302c5ea..8c9e6b24e 100644
253
--- libtransmission/rpc-server.h.orig
254
+++ libtransmission/rpc-server.h
255
@@ -49,6 +49,10 @@ void            tr_rpcSetWhitelist (tr_rpc_server * server,
256
 
257
 const char*     tr_rpcGetWhitelist (const tr_rpc_server * server);
258
 
259
+void tr_rpcSetHostWhitelistEnabled(tr_rpc_server* server, bool isEnabled);
260
+
261
+void tr_rpcSetHostWhitelist(tr_rpc_server* server, char const* whitelist);
262
+
263
 void            tr_rpcSetPassword (tr_rpc_server * server,
264
                                    const char *    password);
265
 
266
diff --git a/libtransmission/session.c b/libtransmission/session.c
267
index 844cadba8..58b717913 100644
268
--- libtransmission/session.c.orig
269
+++ libtransmission/session.c
270
@@ -359,6 +359,8 @@ tr_sessionGetDefaultSettings (tr_variant * d)
271
   tr_variantDictAddStr  (d, TR_KEY_rpc_username,                    "");
272
   tr_variantDictAddStr  (d, TR_KEY_rpc_whitelist,                   TR_DEFAULT_RPC_WHITELIST);
273
   tr_variantDictAddBool (d, TR_KEY_rpc_whitelist_enabled,           true);
274
+  tr_variantDictAddStr(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST);
275
+  tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true);
276
   tr_variantDictAddInt  (d, TR_KEY_rpc_port,                        atoi (TR_DEFAULT_RPC_PORT_STR));
277
   tr_variantDictAddStr  (d, TR_KEY_rpc_url,                         TR_DEFAULT_RPC_URL_STR);
278
   tr_variantDictAddBool (d, TR_KEY_scrape_paused_torrents_enabled,  true);
279
diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h
280
index 4f76adfd6..e213a8f4e 100644
281
--- libtransmission/transmission.h.orig
282
+++ libtransmission/transmission.h
283
@@ -123,6 +123,7 @@ const char* tr_getDefaultDownloadDir (void);
284
 #define TR_DEFAULT_BIND_ADDRESS_IPV4        "0.0.0.0"
285
 #define TR_DEFAULT_BIND_ADDRESS_IPV6             "::"
286
 #define TR_DEFAULT_RPC_WHITELIST          "127.0.0.1"
287
+#define TR_DEFAULT_RPC_HOST_WHITELIST              ""
288
 #define TR_DEFAULT_RPC_PORT_STR                "9091"
289
 #define TR_DEFAULT_RPC_URL_STR       "/transmission/"
290
 #define TR_DEFAULT_PEER_PORT_STR              "51413"
291
diff --git a/libtransmission/web.c b/libtransmission/web.c
292
index ee495e9fc..c7f062730 100644
293
--- libtransmission/web.c.orig
294
+++ libtransmission/web.c
295
@@ -594,6 +594,7 @@ tr_webGetResponseStr (long code)
296
       case 415: return "Unsupported Media Type";
297
       case 416: return "Requested Range Not Satisfiable";
298
       case 417: return "Expectation Failed";
299
+      case 421: return "Misdirected Request";
300
       case 500: return "Internal Server Error";
301
       case 501: return "Not Implemented";
302
       case 502: return "Bad Gateway";
(-)net-p2p/transmission-daemon/Makefile (-1 lines)
Lines 1-6 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
PORTREVISION=	4
4
PKGNAMESUFFIX=	-daemon
3
PKGNAMESUFFIX=	-daemon
5
4
6
MAINTAINER=	crees@FreeBSD.org
5
MAINTAINER=	crees@FreeBSD.org
(-)net-p2p/transmission-gtk/Makefile (-1 lines)
Lines 1-6 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
PORTREVISION=	4
4
PKGNAMESUFFIX=	-gtk
3
PKGNAMESUFFIX=	-gtk
5
4
6
MAINTAINER=	crees@FreeBSD.org
5
MAINTAINER=	crees@FreeBSD.org
(-)net-p2p/transmission-qt4/Makefile (-1 lines)
Lines 1-6 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
PORTREVISION=	6
4
PKGNAMESUFFIX=	-qt4
3
PKGNAMESUFFIX=	-qt4
5
4
6
MAINTAINER=	crees@FreeBSD.org
5
MAINTAINER=	crees@FreeBSD.org
(-)net-p2p/transmission-qt5/Makefile (-1 lines)
Lines 1-6 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
PORTREVISION=	1
4
PKGNAMESUFFIX=	-qt5
3
PKGNAMESUFFIX=	-qt5
5
4
6
MAINTAINER=	crees@FreeBSD.org
5
MAINTAINER=	crees@FreeBSD.org

Return to bug 225917