passenger 5.3.1 → 5.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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();
|