passenger 5.3.1 → 5.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +19 -0
- data/build/cxx_tests.rb +3 -1
- data/build/support/cxx_dependency_map.rb +120 -27
- data/dev/configkit-schemas/index.json +15 -3
- data/src/agent/Core/AdminPanelConnector.h +5 -2
- data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +2 -0
- data/src/agent/Core/Config.h +2 -1
- data/src/agent/Core/Controller/Config.h +6 -1
- data/src/agent/Core/Controller/InitRequest.cpp +6 -1
- data/src/agent/Core/CoreMain.cpp +26 -60
- data/src/agent/Core/SpawningKit/DirectSpawner.h +18 -6
- data/src/agent/Core/SpawningKit/ErrorRenderer.h +8 -8
- data/src/agent/Core/SpawningKit/Handshake/Perform.h +217 -61
- data/src/agent/Core/SpawningKit/Handshake/Prepare.h +57 -8
- data/src/agent/Core/SpawningKit/Handshake/Session.h +34 -1
- data/src/agent/Core/SpawningKit/Handshake/WorkDir.h +20 -4
- data/src/agent/Core/SpawningKit/SmartSpawner.h +90 -27
- data/src/agent/ExecHelper/ExecHelperMain.cpp +3 -0
- data/src/agent/Shared/ApiAccountUtils.h +2 -2
- data/src/agent/SpawnEnvSetupper/SpawnEnvSetupperMain.cpp +14 -4
- data/src/agent/Watchdog/Config.h +2 -1
- data/src/agent/Watchdog/WatchdogMain.cpp +38 -0
- data/src/apache2_module/Hooks.cpp +1 -0
- data/src/cxx_supportlib/ConfigKit/IN_PRACTICE.md +1 -1
- data/src/cxx_supportlib/ConfigKit/README.md +1 -1
- data/src/cxx_supportlib/Constants.h +6 -1
- data/src/cxx_supportlib/FileTools/FileManip.cpp +34 -2
- data/src/cxx_supportlib/FileTools/FileManip.h +58 -1
- data/src/cxx_supportlib/FileTools/PathManip.cpp +3 -2
- data/src/cxx_supportlib/FileTools/PathSecurityCheck.cpp +99 -0
- data/src/cxx_supportlib/FileTools/PathSecurityCheck.h +69 -0
- data/src/cxx_supportlib/Utils.cpp +37 -6
- data/src/cxx_supportlib/Utils.h +6 -0
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +14 -0
- data/src/cxx_supportlib/Utils/IOUtils.cpp +10 -18
- data/src/cxx_supportlib/Utils/IOUtils.h +10 -9
- data/src/cxx_supportlib/Utils/JsonUtils.h +12 -8
- data/src/cxx_supportlib/Utils/SystemMetricsCollector.h +4 -4
- data/src/cxx_supportlib/Utils/SystemTime.h +1 -1
- data/src/cxx_supportlib/WebSocketCommandReverseServer.h +3 -3
- data/src/cxx_supportlib/oxt/system_calls.cpp +25 -1
- data/src/cxx_supportlib/oxt/system_calls.hpp +3 -1
- data/src/helper-scripts/meteor-loader.rb +115 -28
- data/src/helper-scripts/rack-preloader.rb +1 -1
- data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +4 -4
- data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +4 -4
- data/src/nginx_module/LocationConfig/AutoGeneratedCreateFunction.c +0 -10
- data/src/nginx_module/LocationConfig/AutoGeneratedHeaderSerialization.c +0 -42
- data/src/nginx_module/LocationConfig/AutoGeneratedMergeFunction.c +0 -6
- data/src/nginx_module/LocationConfig/AutoGeneratedStruct.h +0 -8
- data/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +10 -0
- data/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +22 -0
- data/src/nginx_module/MainConfig/AutoGeneratedStruct.h +8 -0
- data/src/nginx_module/ngx_http_passenger_module.c +6 -5
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +3 -0
- data/src/ruby_supportlib/phusion_passenger/config/installation_utils.rb +3 -3
- data/src/ruby_supportlib/phusion_passenger/constants.rb +5 -0
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +4 -2
- data/src/ruby_supportlib/phusion_passenger/platform_info.rb +3 -3
- data/src/ruby_supportlib/phusion_passenger/request_handler.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +1 -1
- metadata +4 -2
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2016-
|
3
|
+
* Copyright (c) 2016-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -33,6 +33,7 @@
|
|
33
33
|
#include <vector>
|
34
34
|
#include <stdexcept>
|
35
35
|
#include <algorithm>
|
36
|
+
#include <utility>
|
36
37
|
#include <cerrno>
|
37
38
|
#include <cstddef>
|
38
39
|
#include <cassert>
|
@@ -143,7 +144,7 @@ private:
|
|
143
144
|
|
144
145
|
void createWorkDir() {
|
145
146
|
TRACE_POINT();
|
146
|
-
session.workDir.reset(new HandshakeWorkDir(
|
147
|
+
session.workDir.reset(new HandshakeWorkDir());
|
147
148
|
|
148
149
|
session.envDumpDir = session.workDir->getPath() + "/envdump";
|
149
150
|
makeDirTree(session.envDumpDir,
|
@@ -216,6 +217,43 @@ private:
|
|
216
217
|
}
|
217
218
|
}
|
218
219
|
|
220
|
+
// Open various workdir subdirectories because we'll use these file descriptors later in
|
221
|
+
// safeReadFile() calls.
|
222
|
+
void openWorkDirSubdirFds() {
|
223
|
+
session.workDirFd = openDirFd(session.workDir->getPath());
|
224
|
+
session.responseDirFd = openDirFd(session.responseDir);
|
225
|
+
session.responseErrorDirFd = openDirFd(session.responseDir + "/error");
|
226
|
+
session.envDumpDirFd = openDirFd(session.envDumpDir);
|
227
|
+
session.envDumpAnnotationsDirFd = openDirFd(session.envDumpDir + "/annotations");
|
228
|
+
openJourneyStepDirFds(getFirstSubprocessJourneyStep(),
|
229
|
+
getLastSubprocessJourneyStep());
|
230
|
+
openJourneyStepDirFds(getFirstPreloaderJourneyStep(),
|
231
|
+
JourneyStep((int) getLastPreloaderJourneyStep() + 1));
|
232
|
+
}
|
233
|
+
|
234
|
+
void openJourneyStepDirFds(JourneyStep firstStep, JourneyStep lastStep) {
|
235
|
+
JourneyStep step;
|
236
|
+
|
237
|
+
for (step = firstStep; step < lastStep; step = JourneyStep((int) step + 1)) {
|
238
|
+
if (!session.journey.hasStep(step)) {
|
239
|
+
continue;
|
240
|
+
}
|
241
|
+
|
242
|
+
string stepString = journeyStepToStringLowerCase(step);
|
243
|
+
string stepDir = session.responseDir + "/steps/" + stepString;
|
244
|
+
session.stepDirFds.insert(make_pair(step, openDirFd(stepDir)));
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
int openDirFd(const string &path) {
|
249
|
+
int fd = open(path.c_str(), O_RDONLY);
|
250
|
+
if (fd == -1) {
|
251
|
+
int e = errno;
|
252
|
+
throw FileSystemException("Cannot open " + path, e, path);
|
253
|
+
}
|
254
|
+
return fd;
|
255
|
+
}
|
256
|
+
|
219
257
|
void initializeResult() {
|
220
258
|
session.result.initialize(*context, config);
|
221
259
|
}
|
@@ -266,10 +304,14 @@ private:
|
|
266
304
|
TRACE_POINT();
|
267
305
|
P_DEBUG("[App spawn arg] " << args.toStyledString());
|
268
306
|
|
307
|
+
// The workDir is a new random dir. the files that we create here
|
308
|
+
// should not exist, so if any exist then have createFile()
|
309
|
+
// throw an error because it could be a bug or an attack.
|
310
|
+
|
269
311
|
createFile(session.workDir->getPath() + "/args.json",
|
270
312
|
args.toStyledString(), 0600,
|
271
313
|
session.uid, session.gid,
|
272
|
-
|
314
|
+
false, __FILE__, __LINE__);
|
273
315
|
|
274
316
|
const string dir = session.workDir->getPath() + "/args";
|
275
317
|
makeDirTree(dir, "u=rwx,g=,o=",
|
@@ -289,14 +331,14 @@ private:
|
|
289
331
|
case Json::booleanValue:
|
290
332
|
createFile(dir + "/" + it.name(),
|
291
333
|
jsonValueToString(*it),
|
292
|
-
|
293
|
-
|
334
|
+
0600, session.uid, session.gid,
|
335
|
+
false, __FILE__, __LINE__);
|
294
336
|
break;
|
295
337
|
default:
|
296
338
|
createFile(dir + "/" + it.name() + ".json",
|
297
339
|
jsonValueToString(*it),
|
298
|
-
|
299
|
-
|
340
|
+
0600, session.uid, session.gid,
|
341
|
+
false, __FILE__, __LINE__);
|
300
342
|
break;
|
301
343
|
}
|
302
344
|
}
|
@@ -533,7 +575,7 @@ public:
|
|
533
575
|
assert(_session.config != NULL);
|
534
576
|
}
|
535
577
|
|
536
|
-
|
578
|
+
HandshakePrepare &execute() {
|
537
579
|
TRACE_POINT();
|
538
580
|
|
539
581
|
// We do not set SPAWNING_KIT_PREPARATION to the IN_PROGRESS or
|
@@ -545,6 +587,7 @@ public:
|
|
545
587
|
|
546
588
|
resolveUserAndGroup();
|
547
589
|
createWorkDir();
|
590
|
+
openWorkDirSubdirFds();
|
548
591
|
initializeResult();
|
549
592
|
|
550
593
|
UPDATE_TRACE_POINT();
|
@@ -572,6 +615,12 @@ public:
|
|
572
615
|
session.journey.setStepErrored(SPAWNING_KIT_PREPARATION);
|
573
616
|
throw SpawnException(e, session.journey, config).finalize();
|
574
617
|
}
|
618
|
+
|
619
|
+
return *this;
|
620
|
+
}
|
621
|
+
|
622
|
+
void finalize() {
|
623
|
+
session.workDir->finalize(session.uid, session.gid);
|
575
624
|
}
|
576
625
|
};
|
577
626
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2016-
|
3
|
+
* Copyright (c) 2016-2018 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -28,6 +28,7 @@
|
|
28
28
|
|
29
29
|
#include <boost/scoped_ptr.hpp>
|
30
30
|
#include <string>
|
31
|
+
#include <map>
|
31
32
|
|
32
33
|
#include <Utils.h>
|
33
34
|
#include <Core/SpawningKit/Context.h>
|
@@ -50,6 +51,12 @@ struct HandshakeSession {
|
|
50
51
|
boost::scoped_ptr<HandshakeWorkDir> workDir;
|
51
52
|
string responseDir;
|
52
53
|
string envDumpDir;
|
54
|
+
int workDirFd;
|
55
|
+
int responseDirFd;
|
56
|
+
int responseErrorDirFd;
|
57
|
+
int envDumpDirFd;
|
58
|
+
int envDumpAnnotationsDirFd;
|
59
|
+
map<JourneyStep, int> stepDirFds;
|
53
60
|
Journey journey;
|
54
61
|
Result result;
|
55
62
|
|
@@ -69,6 +76,11 @@ struct HandshakeSession {
|
|
69
76
|
HandshakeSession(Context &_context, Config &_config, JourneyType journeyType)
|
70
77
|
: context(&_context),
|
71
78
|
config(&_config),
|
79
|
+
workDirFd(-1),
|
80
|
+
responseDirFd(-1),
|
81
|
+
responseErrorDirFd(-1),
|
82
|
+
envDumpDirFd(-1),
|
83
|
+
envDumpAnnotationsDirFd(-1),
|
72
84
|
journey(journeyType, !_config.genericApp && _config.startsUsingWrapper),
|
73
85
|
uid(USER_NOT_GIVEN),
|
74
86
|
gid(GROUP_NOT_GIVEN),
|
@@ -77,6 +89,27 @@ struct HandshakeSession {
|
|
77
89
|
{ }
|
78
90
|
|
79
91
|
~HandshakeSession() {
|
92
|
+
if (workDirFd != -1) {
|
93
|
+
safelyClose(workDirFd, true);
|
94
|
+
}
|
95
|
+
if (responseDirFd != -1) {
|
96
|
+
safelyClose(responseDirFd, true);
|
97
|
+
}
|
98
|
+
if (responseErrorDirFd != -1) {
|
99
|
+
safelyClose(responseErrorDirFd, true);
|
100
|
+
}
|
101
|
+
if (envDumpDirFd != -1) {
|
102
|
+
safelyClose(envDumpDirFd, true);
|
103
|
+
}
|
104
|
+
if (envDumpAnnotationsDirFd != -1) {
|
105
|
+
safelyClose(envDumpAnnotationsDirFd, true);
|
106
|
+
}
|
107
|
+
|
108
|
+
map<JourneyStep, int>::iterator it, end = stepDirFds.end();
|
109
|
+
for (it = stepDirFds.begin(); it != end; it++) {
|
110
|
+
safelyClose(it->second);
|
111
|
+
}
|
112
|
+
|
80
113
|
if (config->debugWorkDir && workDir != NULL) {
|
81
114
|
string path = workDir->dontRemoveOnDestruction();
|
82
115
|
P_NOTICE("Work directory " << path << " preserved for debugging");
|
@@ -54,7 +54,7 @@ private:
|
|
54
54
|
string path;
|
55
55
|
|
56
56
|
public:
|
57
|
-
HandshakeWorkDir(
|
57
|
+
HandshakeWorkDir() {
|
58
58
|
char buf[PATH_MAX + 1];
|
59
59
|
char *pos = buf;
|
60
60
|
const char *end = buf + PATH_MAX;
|
@@ -70,9 +70,6 @@ public:
|
|
70
70
|
"in the format of '" + StaticString(buf) + "'", e);
|
71
71
|
} else {
|
72
72
|
path = result;
|
73
|
-
boost::this_thread::disable_interruption di;
|
74
|
-
boost::this_thread::disable_syscall_interruption dsi;
|
75
|
-
syscalls::chown(result, uid, gid);
|
76
73
|
}
|
77
74
|
}
|
78
75
|
|
@@ -86,11 +83,30 @@ public:
|
|
86
83
|
return path;
|
87
84
|
}
|
88
85
|
|
86
|
+
void finalize(uid_t uid, gid_t gid) {
|
87
|
+
finalize(path, uid, gid);
|
88
|
+
}
|
89
|
+
|
89
90
|
string dontRemoveOnDestruction() {
|
90
91
|
string result = path;
|
91
92
|
path.clear();
|
92
93
|
return result;
|
93
94
|
}
|
95
|
+
|
96
|
+
static void finalize(const string &path, uid_t uid, gid_t gid) {
|
97
|
+
// We do not chown() the work dir until:
|
98
|
+
//
|
99
|
+
// - HandshakePrepare is done populating the work dir,
|
100
|
+
// - SpawnEnvSetupperMain is done reading from and modifying the work dir
|
101
|
+
//
|
102
|
+
// This way, the application user cannot perform symlink attacks
|
103
|
+
// inside the work dir until we are done (at which point the
|
104
|
+
// follow-up code will only perform read/write operations after
|
105
|
+
// dropping root privileges).
|
106
|
+
boost::this_thread::disable_interruption di;
|
107
|
+
boost::this_thread::disable_syscall_interruption dsi;
|
108
|
+
syscalls::chown(path.c_str(), uid, gid);
|
109
|
+
}
|
94
110
|
};
|
95
111
|
|
96
112
|
|
@@ -39,7 +39,7 @@
|
|
39
39
|
#include <sys/wait.h>
|
40
40
|
#include <sys/stat.h>
|
41
41
|
#include <signal.h>
|
42
|
-
#include <
|
42
|
+
#include <unistd.h>
|
43
43
|
#include <cstring>
|
44
44
|
#include <cassert>
|
45
45
|
|
@@ -50,12 +50,13 @@
|
|
50
50
|
#include <Exceptions.h>
|
51
51
|
#include <DataStructures/StringKeyTable.h>
|
52
52
|
#include <ProcessManagement/Utils.h>
|
53
|
+
#include <FileTools/FileManip.h>
|
53
54
|
#include <Utils/SystemTime.h>
|
54
|
-
#include <Utils/IOUtils.h>
|
55
55
|
#include <Utils/BufferedIO.h>
|
56
56
|
#include <Utils/JsonUtils.h>
|
57
57
|
#include <Utils/ScopeGuard.h>
|
58
58
|
#include <Utils/ProcessMetricsCollector.h>
|
59
|
+
#include <Utils/AsyncSignalSafeUtils.h>
|
59
60
|
#include <LveLoggingDecorator.h>
|
60
61
|
#include <Core/SpawningKit/Spawner.h>
|
61
62
|
#include <Core/SpawningKit/Exceptions.h>
|
@@ -177,6 +178,8 @@ private:
|
|
177
178
|
}
|
178
179
|
|
179
180
|
struct StdChannelsAsyncOpenState {
|
181
|
+
const int workDirFd;
|
182
|
+
|
180
183
|
oxt::thread *stdinOpenThread;
|
181
184
|
FileDescriptor stdinFd;
|
182
185
|
int stdinOpenErrno;
|
@@ -187,8 +190,9 @@ private:
|
|
187
190
|
|
188
191
|
BackgroundIOCapturerPtr stdoutAndErrCapturer;
|
189
192
|
|
190
|
-
StdChannelsAsyncOpenState()
|
191
|
-
:
|
193
|
+
StdChannelsAsyncOpenState(int _workDirFd)
|
194
|
+
: workDirFd(_workDirFd),
|
195
|
+
stdinOpenThread(NULL),
|
192
196
|
stdoutAndErrOpenThread(NULL)
|
193
197
|
{ }
|
194
198
|
|
@@ -211,7 +215,8 @@ private:
|
|
211
215
|
StdChannelsAsyncOpenStatePtr openStdChannelsFifosAsynchronously(
|
212
216
|
HandshakeSession &session)
|
213
217
|
{
|
214
|
-
StdChannelsAsyncOpenStatePtr state = boost::make_shared<StdChannelsAsyncOpenState>(
|
218
|
+
StdChannelsAsyncOpenStatePtr state = boost::make_shared<StdChannelsAsyncOpenState>(
|
219
|
+
session.workDirFd);
|
215
220
|
state->stdinOpenThread = new oxt::thread(boost::bind(
|
216
221
|
openStdinChannel, state, session.workDir->getPath()),
|
217
222
|
"FIFO opener: " + session.workDir->getPath() + "/stdin", 1024 * 128);
|
@@ -282,7 +287,7 @@ private:
|
|
282
287
|
static void openStdinChannel(StdChannelsAsyncOpenStatePtr state,
|
283
288
|
const string &workDir)
|
284
289
|
{
|
285
|
-
int fd = syscalls::
|
290
|
+
int fd = syscalls::openat(state->workDirFd, "stdin", O_WRONLY | O_APPEND | O_NOFOLLOW);
|
286
291
|
int e = errno;
|
287
292
|
state->stdinFd.assign(fd, __FILE__, __LINE__);
|
288
293
|
state->stdinOpenErrno = e;
|
@@ -291,7 +296,7 @@ private:
|
|
291
296
|
static void openStdoutAndErrChannel(StdChannelsAsyncOpenStatePtr state,
|
292
297
|
const string &workDir)
|
293
298
|
{
|
294
|
-
int fd = syscalls::
|
299
|
+
int fd = syscalls::openat(state->workDirFd, "stdout_and_err", O_RDONLY | O_NOFOLLOW);
|
295
300
|
int e = errno;
|
296
301
|
state->stdoutAndErrFd.assign(fd, __FILE__, __LINE__);
|
297
302
|
state->stdoutAndErrOpenErrno = e;
|
@@ -357,8 +362,11 @@ private:
|
|
357
362
|
|
358
363
|
pid_t pid = syscalls::fork();
|
359
364
|
if (pid == 0) {
|
360
|
-
|
361
|
-
|
365
|
+
int e;
|
366
|
+
char buf[1024];
|
367
|
+
const char *end = buf + sizeof(buf);
|
368
|
+
namespace ASSU = AsyncSignalSafeUtils;
|
369
|
+
|
362
370
|
resetSignalHandlersAndMask();
|
363
371
|
disableMallocDebugging();
|
364
372
|
int stdinCopy = dup2(stdinChannel.first, 3);
|
@@ -367,6 +375,7 @@ private:
|
|
367
375
|
dup2(stdoutAndErrCopy, 1);
|
368
376
|
dup2(stdoutAndErrCopy, 2);
|
369
377
|
closeAllFileDescriptors(2, true);
|
378
|
+
|
370
379
|
execlp(agentFilename.c_str(),
|
371
380
|
agentFilename.c_str(),
|
372
381
|
"spawn-env-setupper",
|
@@ -374,10 +383,16 @@ private:
|
|
374
383
|
"--before",
|
375
384
|
NULL);
|
376
385
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
386
|
+
char *pos = buf;
|
387
|
+
e = errno;
|
388
|
+
pos = ASSU::appendData(pos, end, "Cannot execute \"");
|
389
|
+
pos = ASSU::appendData(pos, end, agentFilename.data(), agentFilename.size());
|
390
|
+
pos = ASSU::appendData(pos, end, "\": ");
|
391
|
+
pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
|
392
|
+
pos = ASSU::appendData(pos, end, " (errno=");
|
393
|
+
pos = ASSU::appendInteger<int, 10>(pos, end, e);
|
394
|
+
pos = ASSU::appendData(pos, end, ")\n");
|
395
|
+
ASSU::printError(buf, pos - buf);
|
381
396
|
_exit(1);
|
382
397
|
|
383
398
|
} else if (pid == -1) {
|
@@ -419,7 +434,7 @@ private:
|
|
419
434
|
// - bottom of stopPreloader()
|
420
435
|
// - addPreloaderEnvDumps()
|
421
436
|
HandshakePerform::loadBasicInfoFromEnvDumpDir(session.envDumpDir,
|
422
|
-
envvars, userInfo, ulimits);
|
437
|
+
session.envDumpDirFd, envvars, userInfo, ulimits);
|
423
438
|
string socketAddress = findPreloaderCommandSocketAddress(session);
|
424
439
|
|
425
440
|
{
|
@@ -431,7 +446,7 @@ private:
|
|
431
446
|
this->preloaderUserInfo = userInfo;
|
432
447
|
this->preloaderUlimits = ulimits;
|
433
448
|
this->preloaderAnnotations = loadAnnotationsFromEnvDumpDir(
|
434
|
-
session.envDumpDir);
|
449
|
+
session.envDumpDir, session.envDumpAnnotationsDirFd);
|
435
450
|
}
|
436
451
|
|
437
452
|
PipeWatcherPtr watcher = boost::make_shared<PipeWatcher>(
|
@@ -825,16 +840,56 @@ private:
|
|
825
840
|
{
|
826
841
|
TRACE_POINT();
|
827
842
|
pid_t spawnedPid = doc["pid"].asInt();
|
828
|
-
ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, spawnedPid));
|
829
|
-
|
830
|
-
UPDATE_TRACE_POINT();
|
831
|
-
waitForStdChannelFifosToBeOpenedByPeer(stdChannelsAsyncOpenState,
|
832
|
-
session, spawnedPid);
|
833
843
|
|
834
|
-
UPDATE_TRACE_POINT();
|
835
844
|
// How do we know the preloader actually forked a process
|
836
845
|
// instead of reporting the PID of a random other existing process?
|
837
|
-
// For security reasons we perform a
|
846
|
+
// For security reasons we perform a bunch of sanity checks,
|
847
|
+
// including checking the PID's UID.
|
848
|
+
|
849
|
+
if (spawnedPid < 1) {
|
850
|
+
UPDATE_TRACE_POINT();
|
851
|
+
session.journey.setStepErrored(SPAWNING_KIT_PROCESS_RESPONSE_FROM_PRELOADER);
|
852
|
+
|
853
|
+
SpawnException e(INTERNAL_ERROR, session.journey, session.config);
|
854
|
+
addPreloaderEnvDumps(e);
|
855
|
+
e.setSummary("The the preloader said it spawned a process with PID "
|
856
|
+
+ toString(spawnedPid) + ", which is not allowed.");
|
857
|
+
e.setSubprocessPid(spawnedPid);
|
858
|
+
e.setStdoutAndErrData(getBackgroundIOCapturerData(
|
859
|
+
stdChannelsAsyncOpenState->stdoutAndErrCapturer));
|
860
|
+
e.setProblemDescriptionHTML(
|
861
|
+
"<h2>Application process has unexpected PID</h2>"
|
862
|
+
"<p>The " PROGRAM_NAME " application server tried"
|
863
|
+
" to start the web application by communicating with a"
|
864
|
+
" helper process that we call a \"preloader\". However,"
|
865
|
+
" the preloader reported that it started a process with"
|
866
|
+
" a PID of " + toString(spawnedPid) + ", which is not"
|
867
|
+
" allowed.</p>");
|
868
|
+
if (!session.config->genericApp && session.config->startsUsingWrapper
|
869
|
+
&& session.config->wrapperSuppliedByThirdParty)
|
870
|
+
{
|
871
|
+
e.setSolutionDescriptionHTML(
|
872
|
+
"<h2>Please report this bug</h2>"
|
873
|
+
"<p class=\"sole-solution\">"
|
874
|
+
"This is probably a bug in the preloader process. The preloader "
|
875
|
+
"wrapper program is not written by the " PROGRAM_NAME " authors, "
|
876
|
+
"but by a third party. Please report this bug to the author of "
|
877
|
+
"the preloader wrapper program."
|
878
|
+
"</p>");
|
879
|
+
} else {
|
880
|
+
e.setSolutionDescriptionHTML(
|
881
|
+
"<h2>Please report this bug</h2>"
|
882
|
+
"<p class=\"sole-solution\">"
|
883
|
+
"This is probably a bug in the preloader process. The preloader "
|
884
|
+
"is an internal tool part of " PROGRAM_NAME ". Please "
|
885
|
+
"<a href=\"" SUPPORT_URL "\">"
|
886
|
+
"report this bug</a>."
|
887
|
+
"</p>");
|
888
|
+
}
|
889
|
+
throw e.finalize();
|
890
|
+
}
|
891
|
+
|
892
|
+
UPDATE_TRACE_POINT();
|
838
893
|
uid_t spawnedUid = getProcessUid(session, spawnedPid,
|
839
894
|
stdChannelsAsyncOpenState->stdoutAndErrCapturer);
|
840
895
|
if (spawnedUid != session.uid) {
|
@@ -882,6 +937,11 @@ private:
|
|
882
937
|
throw e.finalize();
|
883
938
|
}
|
884
939
|
|
940
|
+
UPDATE_TRACE_POINT();
|
941
|
+
ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, spawnedPid));
|
942
|
+
waitForStdChannelFifosToBeOpenedByPeer(stdChannelsAsyncOpenState,
|
943
|
+
session, spawnedPid);
|
944
|
+
|
885
945
|
UPDATE_TRACE_POINT();
|
886
946
|
string alreadyReadStdoutAndErrData;
|
887
947
|
if (stdChannelsAsyncOpenState->stdoutAndErrCapturer != NULL) {
|
@@ -1135,7 +1195,9 @@ private:
|
|
1135
1195
|
return string();
|
1136
1196
|
}
|
1137
1197
|
|
1138
|
-
static StringKeyTable<string> loadAnnotationsFromEnvDumpDir(const string &envDumpDir
|
1198
|
+
static StringKeyTable<string> loadAnnotationsFromEnvDumpDir(const string &envDumpDir,
|
1199
|
+
int envDumpAnnotationsDirFd)
|
1200
|
+
{
|
1139
1201
|
string path = envDumpDir + "/annotations";
|
1140
1202
|
DIR *dir = opendir(path.c_str());
|
1141
1203
|
if (dir == NULL) {
|
@@ -1147,9 +1209,8 @@ private:
|
|
1147
1209
|
struct dirent *ent;
|
1148
1210
|
while ((ent = readdir(dir)) != NULL) {
|
1149
1211
|
if (ent->d_name[0] != '.') {
|
1150
|
-
result.insert(ent->d_name, strip(
|
1151
|
-
|
1152
|
-
true);
|
1212
|
+
result.insert(ent->d_name, strip(safeReadFile(envDumpAnnotationsDirFd,
|
1213
|
+
ent->d_name, SPAWNINGKIT_MAX_SUBPROCESS_ENVDUMP_SIZE).first), true);
|
1153
1214
|
}
|
1154
1215
|
}
|
1155
1216
|
|
@@ -1241,8 +1302,10 @@ public:
|
|
1241
1302
|
|
1242
1303
|
try {
|
1243
1304
|
UPDATE_TRACE_POINT();
|
1244
|
-
HandshakePrepare(session, extraArgs)
|
1305
|
+
HandshakePrepare prepare(session, extraArgs);
|
1306
|
+
prepare.execute();
|
1245
1307
|
createStdChannelFifos(session);
|
1308
|
+
prepare.finalize();
|
1246
1309
|
session.journey.setStepPerformed(SPAWNING_KIT_PREPARATION, true);
|
1247
1310
|
|
1248
1311
|
UPDATE_TRACE_POINT();
|