forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ptrace_check.cc
148 lines (120 loc) · 5.14 KB
/
ptrace_check.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// It is __imperative__ that the functions in this file are __not__ included in
// release or profile builds.
//
// They call into the "private" ptrace() API to ensure that the current process
// is being ptrace()-d. Only debug builds rely on ptrace(), and the ptrace() API
// is not allowed for use in the App Store, so we must exclude it from profile-
// and release-builds.
//
// When an app is launched from a host workstation (e.g. via Xcode or
// "ios-deploy"), the process is already ptrace()-d by debugserver. However,
// when an app is launched from the home screen, it is not, so for debug builds
// we initialize the ptrace() relationship via PT_TRACE_ME if necessary.
//
// Please see the following documents for more details:
// - go/decommissioning-dbc
// - go/decommissioning-dbc-engine
// - go/decommissioning-dbc-tools
#include "flutter/runtime/ptrace_check.h"
#if TRACING_CHECKS_NECESSARY
#include <sys/sysctl.h>
#include <sys/types.h>
#include <mutex>
#include "flutter/fml/build_config.h"
// Being extra careful and adding additional landmines that will prevent
// compilation of this TU in an incorrect runtime mode.
static_assert(FML_OS_IOS, "This translation unit is iOS specific.");
static_assert(FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG,
"This translation unit must only be compiled in the debug "
"runtime mode as it "
"contains private API usage.");
#define PT_TRACE_ME 0
#define PT_SIGEXC 12
extern "C" int ptrace(int request, pid_t pid, caddr_t addr, int data);
namespace flutter {
static bool IsLaunchedByFlutterCLI(const Settings& vm_settings) {
// Only the Flutter CLI passes "--enable-checked-mode". Therefore, if the flag
// is present, we have been launched by "ios-deploy" via "debugserver".
//
// We choose this flag because it is always passed to launch debug builds.
return vm_settings.enable_checked_mode;
}
static bool IsLaunchedByXcode() {
// Use "sysctl()" to check if we're currently being debugged (e.g. by Xcode).
// We could also check "getppid() != 1" (launchd), but this is more direct.
const pid_t self = getpid();
int mib[5] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, self, 0};
auto proc = std::make_unique<struct kinfo_proc>();
size_t proc_size = sizeof(struct kinfo_proc);
if (::sysctl(mib, 4, proc.get(), &proc_size, nullptr, 0) < 0) {
FML_LOG(ERROR) << "Could not execute sysctl() to get current process info: "
<< strerror(errno);
return false;
}
return proc->kp_proc.p_flag & P_TRACED;
}
static bool EnableTracingManually(const Settings& vm_settings) {
if (::ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1) {
FML_LOG(ERROR) << "Could not call ptrace(PT_TRACE_ME): " << strerror(errno);
// No use trying PT_SIGEXC -- it's only needed if PT_TRACE_ME succeeds.
return false;
}
if (::ptrace(PT_SIGEXC, 0, nullptr, 0) == -1) {
FML_LOG(ERROR) << "Could not call ptrace(PT_SIGEXC): " << strerror(errno);
return false;
}
// The previous operation causes this process to not be reaped after it
// terminates (even if PT_SIGEXC fails). Issue a warning to the console every
// (approximiately) maxproc/10 leaks. See the links above for an explanation
// of this issue.
size_t maxproc = 0;
size_t maxproc_size = sizeof(size_t);
const int sysctl_result =
::sysctlbyname("kern.maxproc", &maxproc, &maxproc_size, nullptr, 0);
if (sysctl_result < 0) {
FML_LOG(ERROR)
<< "Could not execute sysctl() to determine process count limit: "
<< strerror(errno);
return false;
}
const char* warning =
"Launching a debug-mode app from the home screen may cause problems.\n"
"Please compile a profile-/release-build, launch your app via \"flutter "
"run\", or see https://github.com/flutter/flutter/wiki/"
"PID-leak-in-iOS-debug-builds-launched-from-home-screen for details.";
if (vm_settings.verbose_logging // used for testing and also informative
|| sysctl_result < 0 // could not determine maximum process count
|| maxproc / 10 == 0 // avoid division (%) by 0
|| getpid() % (maxproc / 10) == 0) // warning every ~maxproc/10 leaks
{
FML_LOG(ERROR) << warning;
}
return true;
}
static bool EnableTracingIfNecessaryOnce(const Settings& vm_settings) {
if (IsLaunchedByFlutterCLI(vm_settings)) {
return true;
}
if (IsLaunchedByXcode()) {
return true;
}
return EnableTracingManually(vm_settings);
}
static TracingResult sTracingResult = TracingResult::kNotAttempted;
bool EnableTracingIfNecessaryImpl(const Settings& vm_settings) {
static std::once_flag tracing_flag;
std::call_once(tracing_flag, [&vm_settings]() {
sTracingResult = EnableTracingIfNecessaryOnce(vm_settings)
? TracingResult::kEnabled
: TracingResult::kDisabled;
});
return sTracingResult != TracingResult::kDisabled;
}
TracingResult GetTracingResultImpl() {
return sTracingResult;
}
} // namespace flutter
#endif // TRACING_CHECKS_NECESSARY