Skip to content

Commit 816ae4b

Browse files
committed
Transform ProcessLauncherLinux to ProcessLauncherPosixFork
Summary: Use ProcessLauncherPosixFork in Linux and NetBSD. Changes to ProcessLauncherLinux: - Limit personality.h and ASLR code to Linux. - Reuse portable ptrace(2) PT_TRACE_ME operation available on Linux and BSDs. - Limit ETXTBSY error path from execve(2) to Linux. - In LaunchProcess declaration change virtual to override. This code should be readily available for FreeBSD. Sponsored by <The NetBSD Foundation> Reviewers: joerg, clayborg, labath, emaste Reviewed By: labath Subscribers: danalbert, srhines, mgorny, #lldb Tags: #lldb Differential Revision: https://reviews.llvm.org/D29347 llvm-svn: 293768
1 parent 79d58a3 commit 816ae4b

File tree

7 files changed

+263
-257
lines changed

7 files changed

+263
-257
lines changed
Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +0,0 @@
1-
//===-- ProcessLauncherAndroid.h --------------------------------*- C++ -*-===//
2-
//
3-
// The LLVM Compiler Infrastructure
4-
//
5-
// This file is distributed under the University of Illinois Open Source
6-
// License. See LICENSE.TXT for details.
7-
//
8-
//===----------------------------------------------------------------------===//
9-
10-
#ifndef lldb_Host_android_ProcessLauncherAndroid_h_
11-
#define lldb_Host_android_ProcessLauncherAndroid_h_
12-
13-
#include "lldb/Host/ProcessLauncher.h"
14-
15-
namespace lldb_private {
16-
17-
class ProcessLauncherLinux : public ProcessLauncher {
18-
public:
19-
virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
20-
Error &error);
21-
};
22-
23-
} // end of namespace lldb_private
24-
25-
#endif
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===-- ProcessLauncherPosixFork.h ------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef lldb_Host_posix_ProcessLauncherPosixFork_h_
11+
#define lldb_Host_posix_ProcessLauncherPosixFork_h_
12+
13+
#include "lldb/Host/ProcessLauncher.h"
14+
15+
namespace lldb_private {
16+
17+
class ProcessLauncherPosixFork : public ProcessLauncher {
18+
public:
19+
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
20+
Error &error) override;
21+
};
22+
23+
} // end of namespace lldb_private
24+
25+
#endif

lldb/source/Host/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ else()
9090
posix/LockFilePosix.cpp
9191
posix/MainLoopPosix.cpp
9292
posix/PipePosix.cpp
93+
posix/ProcessLauncherPosixFork.cpp
9394
)
9495

9596
if (NOT (CMAKE_SYSTEM_NAME MATCHES "Android"))
@@ -122,7 +123,6 @@ else()
122123
linux/HostInfoLinux.cpp
123124
linux/HostThreadLinux.cpp
124125
linux/LibcGlue.cpp
125-
linux/ProcessLauncherLinux.cpp
126126
linux/ThisThread.cpp
127127
)
128128
list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)

lldb/source/Host/common/Host.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@
7171

7272
#if defined(_WIN32)
7373
#include "lldb/Host/windows/ProcessLauncherWindows.h"
74-
#elif defined(__linux__)
75-
#include "lldb/Host/linux/ProcessLauncherLinux.h"
74+
#elif defined(__linux__) || defined(__NetBSD__)
75+
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
7676
#else
7777
#include "lldb/Host/posix/ProcessLauncherPosix.h"
7878
#endif
@@ -975,8 +975,8 @@ Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
975975
std::unique_ptr<ProcessLauncher> delegate_launcher;
976976
#if defined(_WIN32)
977977
delegate_launcher.reset(new ProcessLauncherWindows());
978-
#elif defined(__linux__)
979-
delegate_launcher.reset(new ProcessLauncherLinux());
978+
#elif defined(__linux__) || defined(__NetBSD__)
979+
delegate_launcher.reset(new ProcessLauncherPosixFork());
980980
#else
981981
delegate_launcher.reset(new ProcessLauncherPosix());
982982
#endif
Lines changed: 0 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -1,225 +0,0 @@
1-
//===-- ProcessLauncherLinux.cpp --------------------------------*- C++ -*-===//
2-
//
3-
// The LLVM Compiler Infrastructure
4-
//
5-
// This file is distributed under the University of Illinois Open Source
6-
// License. See LICENSE.TXT for details.
7-
//
8-
//===----------------------------------------------------------------------===//
9-
10-
#include "lldb/Host/linux/ProcessLauncherLinux.h"
11-
#include "lldb/Core/Log.h"
12-
#include "lldb/Host/FileSpec.h"
13-
#include "lldb/Host/Host.h"
14-
#include "lldb/Host/HostProcess.h"
15-
#include "lldb/Host/Pipe.h"
16-
#include "lldb/Target/ProcessLaunchInfo.h"
17-
18-
#include <limits.h>
19-
#include <sys/ptrace.h>
20-
#include <sys/wait.h>
21-
22-
#include <sstream>
23-
24-
#ifdef __ANDROID__
25-
#include <android/api-level.h>
26-
#endif
27-
28-
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
29-
#include <linux/personality.h>
30-
#else
31-
#include <sys/personality.h>
32-
#endif
33-
34-
using namespace lldb;
35-
using namespace lldb_private;
36-
37-
static void FixupEnvironment(Args &env) {
38-
#ifdef __ANDROID__
39-
// If there is no PATH variable specified inside the environment then set the
40-
// path to /system/bin. It is required because the default path used by
41-
// execve() is wrong on android.
42-
static const char *path = "PATH=";
43-
for (auto &entry : env.entries()) {
44-
if (entry.ref.startswith(path))
45-
return;
46-
}
47-
env.AppendArgument(llvm::StringRef("PATH=/system/bin"));
48-
#endif
49-
}
50-
51-
static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
52-
const char *operation) {
53-
std::ostringstream os;
54-
os << operation << " failed: " << strerror(errno);
55-
write(error_fd, os.str().data(), os.str().size());
56-
close(error_fd);
57-
_exit(1);
58-
}
59-
60-
static void DupDescriptor(int error_fd, const FileSpec &file_spec, int fd,
61-
int flags) {
62-
int target_fd = ::open(file_spec.GetCString(), flags, 0666);
63-
64-
if (target_fd == -1)
65-
ExitWithError(error_fd, "DupDescriptor-open");
66-
67-
if (target_fd == fd)
68-
return;
69-
70-
if (::dup2(target_fd, fd) == -1)
71-
ExitWithError(error_fd, "DupDescriptor-dup2");
72-
73-
::close(target_fd);
74-
return;
75-
}
76-
77-
static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
78-
const ProcessLaunchInfo &info) {
79-
// First, make sure we disable all logging. If we are logging to stdout, our
80-
// logs can be
81-
// mistaken for inferior output.
82-
Log::DisableAllLogChannels(nullptr);
83-
84-
// Do not inherit setgid powers.
85-
if (setgid(getgid()) != 0)
86-
ExitWithError(error_fd, "setgid");
87-
88-
if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
89-
if (setpgid(0, 0) != 0)
90-
ExitWithError(error_fd, "setpgid");
91-
}
92-
93-
for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
94-
const FileAction &action = *info.GetFileActionAtIndex(i);
95-
switch (action.GetAction()) {
96-
case FileAction::eFileActionClose:
97-
if (close(action.GetFD()) != 0)
98-
ExitWithError(error_fd, "close");
99-
break;
100-
case FileAction::eFileActionDuplicate:
101-
if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
102-
ExitWithError(error_fd, "dup2");
103-
break;
104-
case FileAction::eFileActionOpen:
105-
DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
106-
action.GetActionArgument());
107-
break;
108-
case FileAction::eFileActionNone:
109-
break;
110-
}
111-
}
112-
113-
const char **argv = info.GetArguments().GetConstArgumentVector();
114-
115-
// Change working directory
116-
if (info.GetWorkingDirectory() &&
117-
0 != ::chdir(info.GetWorkingDirectory().GetCString()))
118-
ExitWithError(error_fd, "chdir");
119-
120-
// Disable ASLR if requested.
121-
if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
122-
const unsigned long personality_get_current = 0xffffffff;
123-
int value = personality(personality_get_current);
124-
if (value == -1)
125-
ExitWithError(error_fd, "personality get");
126-
127-
value = personality(ADDR_NO_RANDOMIZE | value);
128-
if (value == -1)
129-
ExitWithError(error_fd, "personality set");
130-
}
131-
132-
Args env = info.GetEnvironmentEntries();
133-
FixupEnvironment(env);
134-
const char **envp = env.GetConstArgumentVector();
135-
136-
// Clear the signal mask to prevent the child from being affected by
137-
// any masking done by the parent.
138-
sigset_t set;
139-
if (sigemptyset(&set) != 0 ||
140-
pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
141-
ExitWithError(error_fd, "pthread_sigmask");
142-
143-
if (info.GetFlags().Test(eLaunchFlagDebug)) {
144-
// HACK:
145-
// Close everything besides stdin, stdout, and stderr that has no file
146-
// action to avoid leaking. Only do this when debugging, as elsewhere we
147-
// actually rely on
148-
// passing open descriptors to child processes.
149-
for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
150-
if (!info.GetFileActionForFD(fd) && fd != error_fd)
151-
close(fd);
152-
153-
// Start tracing this child that is about to exec.
154-
if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
155-
ExitWithError(error_fd, "ptrace");
156-
}
157-
158-
// Execute. We should never return...
159-
execve(argv[0], const_cast<char *const *>(argv),
160-
const_cast<char *const *>(envp));
161-
162-
if (errno == ETXTBSY) {
163-
// On android M and earlier we can get this error because the adb deamon can
164-
// hold a write
165-
// handle on the executable even after it has finished uploading it. This
166-
// state lasts
167-
// only a short time and happens only when there are many concurrent adb
168-
// commands being
169-
// issued, such as when running the test suite. (The file remains open when
170-
// someone does
171-
// an "adb shell" command in the fork() child before it has had a chance to
172-
// exec.) Since
173-
// this state should clear up quickly, wait a while and then give it one
174-
// more go.
175-
usleep(50000);
176-
execve(argv[0], const_cast<char *const *>(argv),
177-
const_cast<char *const *>(envp));
178-
}
179-
180-
// ...unless exec fails. In which case we definitely need to end the child
181-
// here.
182-
ExitWithError(error_fd, "execve");
183-
}
184-
185-
HostProcess
186-
ProcessLauncherLinux::LaunchProcess(const ProcessLaunchInfo &launch_info,
187-
Error &error) {
188-
char exe_path[PATH_MAX];
189-
launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
190-
191-
// A pipe used by the child process to report errors.
192-
PipePosix pipe;
193-
const bool child_processes_inherit = false;
194-
error = pipe.CreateNew(child_processes_inherit);
195-
if (error.Fail())
196-
return HostProcess();
197-
198-
::pid_t pid = ::fork();
199-
if (pid == -1) {
200-
// Fork failed
201-
error.SetErrorStringWithFormat("Fork failed with error message: %s",
202-
strerror(errno));
203-
return HostProcess(LLDB_INVALID_PROCESS_ID);
204-
}
205-
if (pid == 0) {
206-
// child process
207-
pipe.CloseReadFileDescriptor();
208-
ChildFunc(pipe.ReleaseWriteFileDescriptor(), launch_info);
209-
}
210-
211-
// parent process
212-
213-
pipe.CloseWriteFileDescriptor();
214-
char buf[1000];
215-
int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);
216-
217-
if (r == 0)
218-
return HostProcess(pid); // No error. We're done.
219-
220-
error.SetErrorString(buf);
221-
222-
waitpid(pid, nullptr, 0);
223-
224-
return HostProcess();
225-
}

0 commit comments

Comments
 (0)