Browse Source

Merge branch 'bug9288_rebased'

Conflicts:
	src/test/test_pt.c
Nick Mathewson 10 years ago
parent
commit
904a58d10f
8 changed files with 131 additions and 29 deletions
  1. 4 0
      changes/bug9288
  2. 5 5
      src/common/util.c
  3. 12 9
      src/common/util.h
  4. 2 2
      src/or/statefile.c
  5. 1 1
      src/or/statefile.h
  6. 16 12
      src/or/transports.c
  7. 2 0
      src/or/transports.h
  8. 89 0
      src/test/test_pt.c

+ 4 - 0
changes/bug9288

@@ -0,0 +1,4 @@
+  o Minor bugfixes:
+    - Fix an invalid memory read that occured when a pluggable
+      transport proxy failed its configuration protocol.
+      Fixes bug 9288.

+ 5 - 5
src/common/util.c

@@ -3966,9 +3966,9 @@ tor_spawn_background(const char *const filename, const char **argv,
  *  <b>process_handle</b>.
  *  If <b>also_terminate_process</b> is true, also terminate the
  *  process of the process handle. */
-void
-tor_process_handle_destroy(process_handle_t *process_handle,
-                           int also_terminate_process)
+MOCK_IMPL(void,
+tor_process_handle_destroy,(process_handle_t *process_handle,
+                            int also_terminate_process))
 {
   if (!process_handle)
     return;
@@ -4567,8 +4567,8 @@ log_from_handle(HANDLE *pipe, int severity)
 /** Return a smartlist containing lines outputted from
  *  <b>handle</b>. Return NULL on error, and set
  *  <b>stream_status_out</b> appropriately. */
-smartlist_t *
-tor_get_lines_from_handle(FILE *handle, enum stream_status *stream_status_out)
+MOCK_IMPL(smartlist_t *,
+tor_get_lines_from_handle,(FILE *handle, enum stream_status *stream_status_out))
 {
   enum stream_status stream_status;
   char stdout_buf[400];

+ 12 - 9
src/common/util.h

@@ -492,18 +492,21 @@ FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
 #endif
 
 #ifdef _WIN32
-struct smartlist_t *
-tor_get_lines_from_handle(HANDLE *handle,
-                          enum stream_status *stream_status);
+MOCK_DECL(struct smartlist_t *,
+tor_get_lines_from_handle,(HANDLE *handle,
+                           enum stream_status *stream_status));
 #else
-struct smartlist_t *
-tor_get_lines_from_handle(FILE *handle,
-                          enum stream_status *stream_status);
+MOCK_DECL(struct smartlist_t *,
+tor_get_lines_from_handle,(FILE *handle,
+                           enum stream_status *stream_status));
 #endif
 
-int tor_terminate_process(process_handle_t *process_handle);
-void tor_process_handle_destroy(process_handle_t *process_handle,
-                                int also_terminate_process);
+int
+tor_terminate_process(process_handle_t *process_handle);
+
+MOCK_DECL(void,
+tor_process_handle_destroy,(process_handle_t *process_handle,
+                            int also_terminate_process));
 
 /* ===== Insecure rng */
 typedef struct tor_weak_rng_t {

+ 2 - 2
src/or/statefile.c

@@ -117,8 +117,8 @@ static const config_format_t state_format = {
 static or_state_t *global_state = NULL;
 
 /** Return the persistent state struct for this Tor. */
-or_state_t *
-get_or_state(void)
+MOCK_IMPL(or_state_t *,
+get_or_state, (void))
 {
   tor_assert(global_state);
   return global_state;

+ 1 - 1
src/or/statefile.h

@@ -7,7 +7,7 @@
 #ifndef TOR_STATEFILE_H
 #define TOR_STATEFILE_H
 
-or_state_t *get_or_state(void);
+MOCK_DECL(or_state_t *,get_or_state,(void));
 int did_last_state_file_write_fail(void);
 int or_state_save(time_t now);
 

+ 16 - 12
src/or/transports.c

@@ -103,8 +103,6 @@ create_managed_proxy_environment(const managed_proxy_t *mp);
 static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
 
 static void handle_finished_proxy(managed_proxy_t *mp);
-static void configure_proxy(managed_proxy_t *mp);
-
 static void parse_method_error(const char *line, int is_server_method);
 #define parse_server_method_error(l) parse_method_error(l, 1)
 #define parse_client_method_error(l) parse_method_error(l, 0)
@@ -574,10 +572,8 @@ pt_configure_remaining_proxies(void)
     /* If the proxy is not fully configured, try to configure it
        futher. */
     if (!proxy_configuration_finished(mp))
-      configure_proxy(mp);
-
-    if (proxy_configuration_finished(mp))
-      at_least_a_proxy_config_finished = 1;
+      if (configure_proxy(mp) == 1)
+        at_least_a_proxy_config_finished = 1;
 
   } SMARTLIST_FOREACH_END(mp);
 
@@ -589,10 +585,14 @@ pt_configure_remaining_proxies(void)
     mark_my_descriptor_dirty("configured managed proxies");
 }
 
-/** Attempt to continue configuring managed proxy <b>mp</b>. */
-static void
+/** Attempt to continue configuring managed proxy <b>mp</b>.
+ *  Return 1 if the transport configuration finished, and return 0
+ *  otherwise (if we still have more configuring to do for this
+ *  proxy). */
+STATIC int
 configure_proxy(managed_proxy_t *mp)
 {
+  int configuration_finished = 0;
   smartlist_t *proxy_output = NULL;
   enum stream_status stream_status = 0;
 
@@ -602,7 +602,7 @@ configure_proxy(managed_proxy_t *mp)
       mp->conf_state = PT_PROTO_FAILED_LAUNCH;
       handle_finished_proxy(mp);
     }
-    return;
+    return 0;
   }
 
   tor_assert(mp->conf_state != PT_PROTO_INFANT);
@@ -634,13 +634,17 @@ configure_proxy(managed_proxy_t *mp)
 
  done:
   /* if the proxy finished configuring, exit the loop. */
-  if (proxy_configuration_finished(mp))
+  if (proxy_configuration_finished(mp)) {
     handle_finished_proxy(mp);
+    configuration_finished = 1;
+  }
 
   if (proxy_output) {
     SMARTLIST_FOREACH(proxy_output, char *, cp, tor_free(cp));
     smartlist_free(proxy_output);
   }
+
+  return configuration_finished;
 }
 
 /** Register server managed proxy <b>mp</b> transports to state */
@@ -709,7 +713,8 @@ managed_proxy_destroy(managed_proxy_t *mp,
   smartlist_free(mp->transports_to_launch);
 
   /* remove it from the list of managed proxies */
-  smartlist_remove(managed_proxy_list, mp);
+  if (managed_proxy_list)
+    smartlist_remove(managed_proxy_list, mp);
 
   /* free the argv */
   free_execve_args(mp->argv);
@@ -746,7 +751,6 @@ handle_finished_proxy(managed_proxy_t *mp)
   }
 
   unconfigured_proxies_n--;
-  tor_assert(unconfigured_proxies_n >= 0);
 }
 
 /** Return true if the configuration of the managed proxy <b>mp</b> is

+ 2 - 0
src/or/transports.h

@@ -121,6 +121,8 @@ STATIC void managed_proxy_destroy(managed_proxy_t *mp,
 STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list,
                                              char **proxy_argv, int is_server);
 
+STATIC int configure_proxy(managed_proxy_t *mp);
+
 #endif
 
 #endif

+ 89 - 0
src/test/test_pt.c

@@ -5,11 +5,14 @@
 
 #include "orconfig.h"
 #define PT_PRIVATE
+#define UTIL_PRIVATE
 #include "or.h"
 #include "config.h"
 #include "confparse.h"
 #include "transports.h"
 #include "circuitbuild.h"
+#include "util.h"
+#include "statefile.h"
 #include "test.h"
 
 static void
@@ -269,6 +272,90 @@ test_pt_get_extrainfo_string(void *arg)
   tor_free(s);
 }
 
+#ifdef _WIN32
+#define STDIN_HANDLE HANDLE
+#else
+#define STDIN_HANDLE FILE
+#endif
+
+static smartlist_t *
+tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle,
+                                      enum stream_status *stream_status_out)
+{
+  static int times_called = 0;
+  smartlist_t *retval_sl = smartlist_new();
+
+  (void) handle;
+  (void) stream_status_out;
+
+  /* Generate some dummy CMETHOD lines the first 5 times. The 6th
+     time, send 'CMETHODS DONE' to finish configuring the proxy. */
+  if (times_called++ != 5) {
+    smartlist_add_asprintf(retval_sl, "CMETHOD mock%d socks5 127.0.0.1:555%d",
+                           times_called, times_called);
+  } else {
+    smartlist_add(retval_sl, tor_strdup("CMETHODS DONE"));
+  }
+
+  return retval_sl;
+}
+
+/* NOP mock */
+static void
+tor_process_handle_destroy_replacement(process_handle_t *process_handle,
+                                       int also_terminate_process)
+{
+  (void) process_handle;
+  (void) also_terminate_process;
+}
+
+static or_state_t *dummy_state = NULL;
+
+static or_state_t *
+get_or_state_replacement(void)
+{
+  return dummy_state;
+}
+
+/* Test the configure_proxy() function. */
+static void
+test_pt_configure_proxy(void *arg)
+{
+  int i;
+  managed_proxy_t *mp = NULL;
+  (void) arg;
+
+  dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+  MOCK(tor_get_lines_from_handle,
+       tor_get_lines_from_handle_replacement);
+  MOCK(tor_process_handle_destroy,
+       tor_process_handle_destroy_replacement);
+  MOCK(get_or_state,
+       get_or_state_replacement);
+
+  mp = tor_malloc(sizeof(managed_proxy_t));
+  mp->conf_state = PT_PROTO_ACCEPTING_METHODS;
+  mp->transports = smartlist_new();
+  mp->transports_to_launch = smartlist_new();
+  mp->process_handle = tor_malloc_zero(sizeof(process_handle_t));
+  mp->argv = tor_malloc_zero(sizeof(char*)*2);
+  mp->argv[0] = tor_strdup("<testcase>");
+
+  /* Test the return value of configure_proxy() by calling it some
+     times while it is uninitialized and then finally finalizing its
+     configuration. */
+  for (i = 0 ; i < 5 ; i++) {
+    test_assert(configure_proxy(mp) == 0);
+  }
+  test_assert(configure_proxy(mp) == 1);
+
+ done:
+  tor_free(dummy_state);
+  UNMOCK(tor_get_lines_from_handle);
+  UNMOCK(tor_process_handle_destroy);
+}
+
 #define PT_LEGACY(name)                                               \
   { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name }
 
@@ -279,6 +366,8 @@ struct testcase_t pt_tests[] = {
     NULL, NULL },
   { "get_extrainfo_string", test_pt_get_extrainfo_string, TT_FORK,
     NULL, NULL },
+  { "configure_proxy",test_pt_configure_proxy, TT_FORK,
+    NULL, NULL },
   END_OF_TESTCASES
 };