Revert to getting a random port and sending that down to debugserver for iOS. The sandboxing is not letting debugserver reverse connect back to lldb.

<rdar://problem/15789865>

llvm-svn: 198963
This commit is contained in:
Greg Clayton 2014-01-10 22:24:11 +00:00
parent 9485dcfb1a
commit fda4fab505
4 changed files with 100 additions and 37 deletions

View File

@ -598,12 +598,12 @@ GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)
} }
Error Error
GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port, GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
uint16_t in_port,
lldb_private::ProcessLaunchInfo &launch_info, lldb_private::ProcessLaunchInfo &launch_info,
uint16_t &port) uint16_t &out_port)
{ {
port = 0; out_port = in_port;
Error error; Error error;
// If we locate debugserver, keep that located version around // If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec; static FileSpec g_debugserver_file_spec;
@ -651,8 +651,17 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
debugserver_args.AppendArgument(debugserver_path); debugserver_args.AppendArgument(debugserver_path);
// If a host and port is supplied then use it // If a host and port is supplied then use it
if (host_and_port) char host_and_port[128];
if (hostname)
{
snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
debugserver_args.AppendArgument(host_and_port); debugserver_args.AppendArgument(host_and_port);
}
else
{
host_and_port[0] = '\0';
}
// use native registers, not the GDB registers // use native registers, not the GDB registers
debugserver_args.AppendArgument("--native-regs"); debugserver_args.AppendArgument("--native-regs");
// make debugserver run in its own session so signals generated by // make debugserver run in its own session so signals generated by
@ -661,34 +670,45 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
char named_pipe_path[PATH_MAX]; char named_pipe_path[PATH_MAX];
if (host_and_port) bool listen = false;
if (host_and_port[0])
{ {
// Create a temporary file to get the stdout/stderr and redirect the // Create a temporary file to get the stdout/stderr and redirect the
// output of the command into this file. We will later read this file // output of the command into this file. We will later read this file
// if all goes well and fill the data into "command_output_ptr" // if all goes well and fill the data into "command_output_ptr"
FileSpec tmpdir_file_spec;
if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
}
else
{
strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
}
if (::mktemp (named_pipe_path)) if (in_port == 0)
{ {
if (::mkfifo(named_pipe_path, 0600) == 0) // Binding to port zero, we need to figure out what port it ends up
// using using a named pipe...
FileSpec tmpdir_file_spec;
if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{ {
debugserver_args.AppendArgument("--named-pipe"); tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
debugserver_args.AppendArgument(named_pipe_path); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
}
else
{
strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
}
if (::mktemp (named_pipe_path))
{
if (::mkfifo(named_pipe_path, 0600) == 0)
{
debugserver_args.AppendArgument("--named-pipe");
debugserver_args.AppendArgument(named_pipe_path);
}
else
named_pipe_path[0] = '\0';
} }
else else
named_pipe_path[0] = '\0'; named_pipe_path[0] = '\0';
} }
else else
named_pipe_path[0] = '\0'; {
listen = true;
}
} }
else else
{ {
@ -701,10 +721,10 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
return error; return error;
ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
port = connection->GetBoundPort(3); out_port = connection->GetBoundPort(3);
assert (port != 0); assert (out_port != 0);
char port_cstr[32]; char port_cstr[32];
snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", port); snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port);
// Send the host and port down that debugserver and specify an option // Send the host and port down that debugserver and specify an option
// so that it connects back to the port we are listening to in this process // so that it connects back to the port we are listening to in this process
debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument("--reverse-connect");
@ -746,10 +766,14 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
error = name_pipe_file.Read(port_cstr, num_bytes); error = name_pipe_file.Read(port_cstr, num_bytes);
assert (error.Success()); assert (error.Success());
assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
port = Args::StringToUInt32(port_cstr, 0); out_port = Args::StringToUInt32(port_cstr, 0);
name_pipe_file.Close(); name_pipe_file.Close();
} }
Host::Unlink(named_pipe_path); Host::Unlink(named_pipe_path);
}
else if (listen)
{
} }
else else
{ {

View File

@ -121,9 +121,10 @@ public:
// supplied connection URL. // supplied connection URL.
//------------------------------------------------------------------ //------------------------------------------------------------------
lldb_private::Error lldb_private::Error
StartDebugserverProcess (const char *host_and_port, StartDebugserverProcess (const char *hostname,
uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit
lldb_private::ProcessLaunchInfo &launch_info, lldb_private::ProcessLaunchInfo &launch_info,
uint16_t &port); uint16_t &out_port);
void void
DumpHistory(lldb_private::Stream &strm); DumpHistory(lldb_private::Stream &strm);

View File

@ -841,18 +841,16 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
{ {
// Spawn a debugserver and try to get the port it listens to. // Spawn a debugserver and try to get the port it listens to.
ProcessLaunchInfo debugserver_launch_info; ProcessLaunchInfo debugserver_launch_info;
StreamString host_and_port;
if (hostname.empty()) if (hostname.empty())
hostname = "localhost"; hostname = "localhost";
host_and_port.Printf("%s:%u", hostname.c_str(), port);
const char *host_and_port_cstr = host_and_port.GetString().c_str();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
if (log) if (log)
log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
error = StartDebugserverProcess (host_and_port_cstr, error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
port,
debugserver_launch_info, debugserver_launch_info,
port); port);

View File

@ -167,6 +167,34 @@ namespace {
} // anonymous namespace end } // anonymous namespace end
static bool rand_initialized = false;
// TODO Randomly assigning a port is unsafe. We should get an unused
// ephemeral port from the kernel and make sure we reserve it before passing
// it to debugserver.
#if defined (__APPLE__)
#define LOW_PORT (IPPORT_RESERVED)
#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
#else
#define LOW_PORT (1024u)
#define HIGH_PORT (49151u)
#endif
static inline uint16_t
get_random_port ()
{
if (!rand_initialized)
{
time_t seed = time(NULL);
rand_initialized = true;
srand(seed);
}
return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
}
lldb_private::ConstString lldb_private::ConstString
ProcessGDBRemote::GetPluginNameStatic() ProcessGDBRemote::GetPluginNameStatic()
{ {
@ -2514,7 +2542,6 @@ Error
ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info)
{ {
Error error; Error error;
uint16_t port = 0;
if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
{ {
// If we locate debugserver, keep that located version around // If we locate debugserver, keep that located version around
@ -2524,7 +2551,20 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
debugserver_launch_info.SetUserID(process_info.GetUserID()); debugserver_launch_info.SetUserID(process_info.GetUserID());
error = m_gdb_comm.StartDebugserverProcess (NULL, #if defined (__APPLE__) && defined (__arm__)
// On iOS, still do a local connection using a random port
const char *hostname = "localhost";
uint16_t port = get_random_port ();
#else
// Set hostname being NULL to do the reverse connect where debugserver
// will bind to port zero and it will communicate back to us the port
// that we will connect to
const char *hostname = NULL;
uint16_t port = 0;
#endif
error = m_gdb_comm.StartDebugserverProcess (hostname,
port,
debugserver_launch_info, debugserver_launch_info,
port); port);
@ -2552,9 +2592,9 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info
} }
else else
{ {
char connect_url[128]; StreamString connect_url;
snprintf (connect_url, sizeof(connect_url), "connect://localhost:%u", port); connect_url.Printf("connect://%s:%u", hostname, port);
error = ConnectToDebugserver (connect_url); error = ConnectToDebugserver (connect_url.GetString().c_str());
} }
} }