passenger 5.0.27 → 5.0.28

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +14 -1
  3. data/CONTRIBUTORS +2 -0
  4. data/Rakefile +6 -5
  5. data/build/agent.rb +1 -1
  6. data/build/basics.rb +6 -71
  7. data/build/misc.rb +2 -2
  8. data/build/nginx.rb +18 -1
  9. data/build/packaging.rb +3 -1
  10. data/build/{cplusplus_support.rb → support/cplusplus.rb} +0 -0
  11. data/build/{cxx_dependency_map.rb → support/cxx_dependency_map.rb} +72 -1
  12. data/build/support/general.rb +106 -0
  13. data/dev/ci/run_travis.sh +9 -0
  14. data/dev/vagrant/nginx_rakefile +1 -1
  15. data/src/agent/Core/ApplicationPool/Options.h +4 -0
  16. data/src/agent/Core/Controller/CheckoutSession.cpp +1 -2
  17. data/src/agent/Core/Controller/InitRequest.cpp +1 -0
  18. data/src/agent/Core/SpawningKit/DirectSpawner.h +12 -0
  19. data/src/agent/Core/SpawningKit/SmartSpawner.h +13 -2
  20. data/src/agent/Core/SpawningKit/Spawner.h +35 -0
  21. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +12 -6
  22. data/src/apache2_module/ConfigurationCommands.cpp +7 -0
  23. data/src/apache2_module/ConfigurationFields.hpp +2 -0
  24. data/src/apache2_module/ConfigurationSetters.cpp +34 -0
  25. data/src/apache2_module/CreateDirConfig.cpp +1 -0
  26. data/src/apache2_module/MergeDirConfig.cpp +7 -0
  27. data/src/apache2_module/SetHeaders.cpp +5 -0
  28. data/src/cxx_supportlib/Constants.h +3 -1
  29. data/src/cxx_supportlib/Logging.h +11 -8
  30. data/src/cxx_supportlib/LveLoggingDecorator.h +92 -0
  31. data/src/cxx_supportlib/MemoryKit/mbuf.cpp +51 -16
  32. data/src/cxx_supportlib/MemoryKit/mbuf.h +27 -24
  33. data/src/cxx_supportlib/ServerKit/HttpServer.h +4 -0
  34. data/src/cxx_supportlib/vendor-copy/adhoc_lve.h +304 -0
  35. data/src/nginx_module/Configuration.c +8 -0
  36. data/src/nginx_module/config +26 -12
  37. data/src/ruby_supportlib/phusion_passenger.rb +8 -8
  38. data/src/ruby_supportlib/phusion_passenger/admin_tools/memory_stats.rb +1 -1
  39. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +8 -0
  40. data/src/ruby_supportlib/phusion_passenger/common_library.rb +2 -2
  41. data/src/ruby_supportlib/phusion_passenger/config/about_command.rb +26 -1
  42. data/src/ruby_supportlib/phusion_passenger/config/main.rb +2 -0
  43. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -0
  44. data/src/ruby_supportlib/phusion_passenger/packaging.rb +1 -1
  45. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +1 -0
  46. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +1 -1
  47. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +2 -1
  48. metadata +7 -4
@@ -0,0 +1,106 @@
1
+ # Phusion Passenger - https://www.phusionpassenger.com/
2
+ # Copyright (c) 2010-2016 Phusion Holding B.V.
3
+ #
4
+ # "Passenger", "Phusion Passenger" and "Union Station" are registered
5
+ # trademarks of Phusion Holding B.V.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ class TemplateRenderer
26
+ def initialize(filename)
27
+ require 'erb' if !defined?(ERB)
28
+ @erb = ERB.new(File.read(filename), nil, "-")
29
+ @erb.filename = filename
30
+ end
31
+
32
+ def render
33
+ return @erb.result(binding)
34
+ end
35
+
36
+ def render_to(filename)
37
+ puts "Creating #{filename}"
38
+ text = render
39
+ # When packaging, some timestamps may be modified. The user may not
40
+ # have write access to the source root (for example, when Passenger
41
+ # Standalone is compiling its runtime), so we only write to the file
42
+ # when necessary.
43
+ if !File.exist?(filename) || File.writable?(filename) || File.read(filename) != text
44
+ File.open(filename, 'w') do |f|
45
+ f.write(text)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ class Pathname
52
+ if !method_defined?(:/)
53
+ def /(other)
54
+ self + other.to_s
55
+ end
56
+ end
57
+ end
58
+
59
+ def string_option(name, default_value = nil)
60
+ value = ENV[name]
61
+ if value.nil? || value.empty?
62
+ if default_value.respond_to?(:call)
63
+ default_value.call
64
+ else
65
+ default_value
66
+ end
67
+ else
68
+ value
69
+ end
70
+ end
71
+
72
+ def pathname_option(name, default_value)
73
+ Pathname.new(string_option(name, default_value))
74
+ end
75
+
76
+ def compiler_flag_option(name, default_value = '')
77
+ string_option(name, default_value).gsub("\n", " ")
78
+ end
79
+
80
+ def boolean_option(name, default_value = false)
81
+ value = ENV[name]
82
+ if value.nil? || value.empty?
83
+ default_value
84
+ else
85
+ value == "yes" || value == "on" || value == "true" || value == "1"
86
+ end
87
+ end
88
+
89
+ def maybe_wrap_in_ccache(command)
90
+ if boolean_option('USE_CCACHE', false) && command !~ /^ccache /
91
+ "ccache #{command}"
92
+ else
93
+ command
94
+ end
95
+ end
96
+
97
+ def ensure_target_directory_exists(target)
98
+ dir = File.dirname(target)
99
+ if !File.exist?(dir)
100
+ sh "mkdir -p #{dir}"
101
+ end
102
+ end
103
+
104
+ def shesc(path)
105
+ Shellwords.escape(path)
106
+ end
@@ -16,6 +16,8 @@ fi
16
16
 
17
17
  COMPILE_CONCURRENCY=${COMPILE_CONCURRENCY:-2}
18
18
 
19
+ TEST_DYNAMIC_WITH_NGINX_VERSION=1.9.15
20
+
19
21
  export VERBOSE=1
20
22
  export TRACE=1
21
23
  export DEVDEPS_DEFAULT=no
@@ -213,6 +215,13 @@ if [[ "$TEST_NGINX" = 1 ]]; then
213
215
  install_node_and_modules
214
216
  run ./bin/passenger-install-nginx-module --auto --prefix=/tmp/nginx --auto-download
215
217
  run bundle exec drake -j$COMPILE_CONCURRENCY test:integration:nginx
218
+
219
+ run curl -sSLO http://www.nginx.org/download/nginx-$TEST_DYNAMIC_WITH_NGINX_VERSION.tar.gz
220
+ run tar zxf nginx-$TEST_DYNAMIC_WITH_NGINX_VERSION.tar.gz
221
+ run cd nginx-$TEST_DYNAMIC_WITH_NGINX_VERSION
222
+ run ./configure --add-dynamic-module=$(../bin/passenger-config --nginx-addon-dir)
223
+ run make
224
+ run cd ..
216
225
  fi
217
226
 
218
227
  if [[ "$TEST_APACHE2" = 1 ]]; then
@@ -27,7 +27,7 @@ task :configure do
27
27
  " --with-http_ssl_module" +
28
28
  " --with-http_gzip_static_module" +
29
29
  " --with-http_stub_status_module" +
30
- " --with-http_spdy_module" +
30
+ " --with-http_v2_module" +
31
31
  " --with-ipv6" +
32
32
  " --with-debug"
33
33
  sh "sed", "-E", "-i", 's/ -O[0-9]? / -ggdb /g', "objs/Makefile"
@@ -237,6 +237,9 @@ public:
237
237
  /** See class overview. Defaults to the defaultUser's primary group. */
238
238
  StaticString defaultGroup;
239
239
 
240
+ /** Minimum user id starting from which entering LVE and CageFS is allowed. */
241
+ unsigned int lveMinUid;
242
+
240
243
  /**
241
244
  * The directory which contains restart.txt and always_restart.txt.
242
245
  * An empty string means that the default directory should be used.
@@ -474,6 +477,7 @@ public:
474
477
  baseURI("/", 1),
475
478
  spawnMethod(DEFAULT_SPAWN_METHOD, sizeof(DEFAULT_SPAWN_METHOD) - 1),
476
479
  defaultUser(PASSENGER_DEFAULT_USER, sizeof(PASSENGER_DEFAULT_USER) - 1),
480
+ lveMinUid(DEFAULT_LVE_MIN_UID),
477
481
  integrationMode(DEFAULT_INTEGRATION_MODE, sizeof(DEFAULT_INTEGRATION_MODE) - 1),
478
482
  ruby(DEFAULT_RUBY, sizeof(DEFAULT_RUBY) - 1),
479
483
  python(DEFAULT_PYTHON, sizeof(DEFAULT_PYTHON) - 1),
@@ -378,8 +378,7 @@ Controller::friendlyErrorPagesEnabled(Request *req) {
378
378
  bool defaultValue;
379
379
  string defaultStr = agentsOptions->get("friendly_error_pages");
380
380
  if (defaultStr == "auto") {
381
- defaultValue = req->options.environment != "staging"
382
- && req->options.environment != "production";
381
+ defaultValue = (req->options.environment == "development");
383
382
  } else {
384
383
  defaultValue = defaultStr == "true";
385
384
  }
@@ -383,6 +383,7 @@ Controller::createNewPoolOptions(Client *client, Request *req,
383
383
  fillPoolOption(req, options.loadShellEnvvars, "!~PASSENGER_LOAD_SHELL_ENVVARS");
384
384
  fillPoolOption(req, options.fileDescriptorUlimit, "!~PASSENGER_APP_FILE_DESCRIPTOR_ULIMIT");
385
385
  fillPoolOption(req, options.raiseInternalError, "!~PASSENGER_RAISE_INTERNAL_ERROR");
386
+ fillPoolOption(req, options.lveMinUid, "!~PASSENGER_LVE_MIN_UID");
386
387
  /******************/
387
388
 
388
389
  boost::shared_ptr<Options> optionsCopy = boost::make_shared<Options>(options);
@@ -28,9 +28,11 @@
28
28
 
29
29
  #include <Core/SpawningKit/Spawner.h>
30
30
  #include <Constants.h>
31
+ #include <LveLoggingDecorator.h>
31
32
  #include <limits.h> // for PTHREAD_STACK_MIN
32
33
  #include <pthread.h>
33
34
 
35
+ #include <adhoc_lve.h>
34
36
 
35
37
  namespace Passenger {
36
38
  namespace SpawningKit {
@@ -167,6 +169,14 @@ public:
167
169
  preparation.userSwitching.gid);
168
170
  pid_t pid;
169
171
 
172
+ adhoc_lve::LveEnter scopedLveEnter(LveLoggingDecorator::lveInitOnce(),
173
+ preparation.userSwitching.uid,
174
+ options.lveMinUid,
175
+ LveLoggingDecorator::lveExitCallback);
176
+ LveLoggingDecorator::logLveEnter(scopedLveEnter,
177
+ preparation.userSwitching.uid,
178
+ options.lveMinUid);
179
+
170
180
  pid = syscalls::fork();
171
181
  if (pid == 0) {
172
182
  setenv("PASSENGER_DEBUG_DIR", debugDir->getPath().c_str(), 1);
@@ -203,6 +213,8 @@ public:
203
213
 
204
214
  } else {
205
215
  UPDATE_TRACE_POINT();
216
+ scopedLveEnter.exit();
217
+
206
218
  P_LOG_FILE_DESCRIPTOR_PURPOSE(adminSocket.first,
207
219
  "App " << pid << " (" << options.appRoot << ") adminSocket[0]");
208
220
  P_LOG_FILE_DESCRIPTOR_PURPOSE(adminSocket.second,
@@ -29,6 +29,9 @@
29
29
  #include <Core/SpawningKit/Spawner.h>
30
30
  #include <Core/SpawningKit/PipeWatcher.h>
31
31
  #include <Constants.h>
32
+ #include <LveLoggingDecorator.h>
33
+
34
+ #include <adhoc_lve.h>
32
35
 
33
36
  namespace Passenger {
34
37
  namespace SpawningKit {
@@ -212,9 +215,15 @@ private:
212
215
  Pipe errorPipe = createPipe(__FILE__, __LINE__);
213
216
  DebugDirPtr debugDir = boost::make_shared<DebugDir>(preparation.userSwitching.uid,
214
217
  preparation.userSwitching.gid);
215
- pid_t pid;
216
218
 
217
- pid = syscalls::fork();
219
+ adhoc_lve::LveEnter scopedLveEnter(LveLoggingDecorator::lveInitOnce(),
220
+ preparation.userSwitching.uid,
221
+ options.lveMinUid,
222
+ LveLoggingDecorator::lveExitCallback);
223
+ LveLoggingDecorator::logLveEnter(scopedLveEnter,
224
+ preparation.userSwitching.uid,
225
+ options.lveMinUid);
226
+ pid_t pid = syscalls::fork();
218
227
  if (pid == 0) {
219
228
  setenv("PASSENGER_DEBUG_DIR", debugDir->getPath().c_str(), 1);
220
229
  purgeStdio(stdout);
@@ -249,6 +258,8 @@ private:
249
258
  throw SystemException("Cannot fork a new process", e);
250
259
 
251
260
  } else {
261
+ scopedLveEnter.exit();
262
+
252
263
  UPDATE_TRACE_POINT();
253
264
  P_LOG_FILE_DESCRIPTOR_PURPOSE(adminSocket.first,
254
265
  "Preloader " << pid << " (" << options.appRoot << ") adminSocket[0]");
@@ -78,6 +78,7 @@
78
78
  #include <pwd.h>
79
79
  #include <grp.h>
80
80
  #include <dirent.h>
81
+ #include <adhoc_lve.h>
81
82
  #include <modp_b64.h>
82
83
  #include <FileDescriptor.h>
83
84
  #include <Exceptions.h>
@@ -871,8 +872,42 @@ protected:
871
872
  }
872
873
  }
873
874
 
875
+ void enterLveJail(const struct passwd * pw) {
876
+ if (!pw)
877
+ return;
878
+
879
+ string lve_init_err;
880
+ adhoc_lve::LibLve& liblve = adhoc_lve::LveInitSignleton::getInstance(&lve_init_err);
881
+ if (liblve.is_error())
882
+ {
883
+ printf("!> Error\n");
884
+ printf("!> \n");
885
+ printf("!> Failed to init LVE library%s%s\n",
886
+ lve_init_err.empty()? "" : ": ",
887
+ lve_init_err.c_str());
888
+ fflush(stdout);
889
+ _exit(1);
890
+ }
891
+
892
+ if (!liblve.is_lve_available())
893
+ return;
894
+
895
+ string jail_err;
896
+ int rc = liblve.jail(pw, jail_err);
897
+ if (rc < 0)
898
+ {
899
+ printf("!> Error\n");
900
+ printf("!> \n");
901
+ printf("enterLve() failed: %s\n", jail_err.c_str());
902
+ fflush(stdout);
903
+ _exit(1);
904
+ }
905
+ }
906
+
874
907
  void switchUser(const SpawnPreparationInfo &info) {
875
908
  if (info.userSwitching.enabled) {
909
+ enterLveJail(&info.userSwitching.lveUserPwd);
910
+
876
911
  bool setgroupsCalled = false;
877
912
  #ifdef HAVE_GETGROUPLIST
878
913
  if (info.userSwitching.ngroups <= NGROUPS_MAX) {
@@ -55,7 +55,10 @@ struct UserSwitchingInfo {
55
55
  uid_t uid;
56
56
  gid_t gid;
57
57
  int ngroups;
58
- shared_array<gid_t> gidset;
58
+ boost::shared_array<gid_t> gidset;
59
+
60
+ struct passwd lveUserPwd, *lveUserPwdComplete;
61
+ boost::shared_array<char> lveUserPwdStrBuf;
59
62
  };
60
63
 
61
64
  inline UserSwitchingInfo
@@ -64,9 +67,10 @@ prepareUserSwitching(const Options &options) {
64
67
  UserSwitchingInfo info;
65
68
 
66
69
  if (geteuid() != 0) {
67
- struct passwd pwd, *userInfo;
70
+ struct passwd &pwd = info.lveUserPwd;
71
+ boost::shared_array<char> &strings = info.lveUserPwdStrBuf;
72
+ struct passwd *userInfo;
68
73
  long bufSize;
69
- shared_array<char> strings;
70
74
 
71
75
  // _SC_GETPW_R_SIZE_MAX is not a maximum:
72
76
  // http://tomlee.co/2012/10/problems-with-large-linux-unix-groups-and-getgrgid_r-getgrnam_r/
@@ -97,11 +101,13 @@ prepareUserSwitching(const Options &options) {
97
101
  string defaultGroup;
98
102
  string startupFile = absolutizePath(options.getStartupFile(),
99
103
  absolutizePath(options.appRoot));
100
- struct passwd pwd, *userInfo;
104
+ struct passwd &pwd = info.lveUserPwd;
105
+ boost::shared_array<char> &pwdBuf = info.lveUserPwdStrBuf;
106
+ struct passwd *userInfo;
101
107
  struct group grp;
102
108
  gid_t groupId = (gid_t) -1;
103
109
  long pwdBufSize, grpBufSize;
104
- shared_array<char> pwdBuf, grpBuf;
110
+ boost::shared_array<char> grpBuf;
105
111
  int ret;
106
112
 
107
113
  // _SC_GETPW_R_SIZE_MAX/_SC_GETGR_R_SIZE_MAX are not maximums:
@@ -250,7 +256,7 @@ prepareUserSwitching(const Options &options) {
250
256
  int e = errno;
251
257
  throw SystemException("getgrouplist() failed", e);
252
258
  }
253
- info.gidset = shared_array<gid_t>(new gid_t[info.ngroups]);
259
+ info.gidset = boost::shared_array<gid_t>(new gid_t[info.ngroups]);
254
260
  for (int i = 0; i < info.ngroups; i++) {
255
261
  info.gidset[i] = groups[i];
256
262
  }
@@ -237,6 +237,13 @@
237
237
  "Force Passenger to believe that an application process can handle the given number of concurrent requests per process"),
238
238
 
239
239
 
240
+ AP_INIT_TAKE1("PassengerLveMinUid",
241
+ (Take1Func) cmd_passenger_lve_min_uid,
242
+ NULL,
243
+ RSRC_CONF,
244
+ "Minimum user id starting from which entering LVE and CageFS is allowed."),
245
+
246
+
240
247
  AP_INIT_TAKE1("RailsEnv",
241
248
  (Take1Func) cmd_passenger_app_env,
242
249
  NULL,
@@ -61,6 +61,8 @@ struct GeneratedDirConfigPart {
61
61
  Threeway stickySessionsCookieName;
62
62
  /** Force Passenger to believe that an application process can handle the given number of concurrent requests per process */
63
63
  int forceMaxConcurrentRequestsPerProcess;
64
+ /** Minimum user id starting from which entering LVE and CageFS is allowed. */
65
+ int lveMinUid;
64
66
  /** The maximum number of simultaneously alive application instances a single application may occupy. */
65
67
  int maxInstancesPerApp;
66
68
  /** The maximum number of seconds that a preloader process may be idle before it is shutdown. */
@@ -444,4 +444,38 @@
444
444
  }
445
445
  }
446
446
 
447
+
448
+ static const char *
449
+ cmd_passenger_lve_min_uid(cmd_parms *cmd, void *pcfg, const char *arg) {
450
+ DirConfig *config = (DirConfig *) pcfg;
451
+ char *end;
452
+ long result;
453
+
454
+ result = strtol(arg, &end, 10);
455
+ if (*end != '\0') {
456
+ string message = "Invalid number specified for ";
457
+ message.append(cmd->directive->directive);
458
+ message.append(".");
459
+
460
+ char *messageStr = (char *) apr_palloc(cmd->temp_pool,
461
+ message.size() + 1);
462
+ memcpy(messageStr, message.c_str(), message.size() + 1);
463
+ return messageStr;
464
+
465
+ } else if (result < 0) {
466
+ string message = "Value for ";
467
+ message.append(cmd->directive->directive);
468
+ message.append(" must be greater than or equal to 0.");
469
+
470
+ char *messageStr = (char *) apr_palloc(cmd->temp_pool,
471
+ message.size() + 1);
472
+ memcpy(messageStr, message.c_str(), message.size() + 1);
473
+ return messageStr;
474
+
475
+ } else {
476
+ config->lveMinUid = (int) result;
477
+ return NULL;
478
+ }
479
+ }
480
+
447
481
 
@@ -67,4 +67,5 @@
67
67
  config->restartDir = NULL;
68
68
  config->appGroupName = NULL;
69
69
  config->forceMaxConcurrentRequestsPerProcess = UNSET_INT_VALUE;
70
+ config->lveMinUid = UNSET_INT_VALUE;
70
71
 
@@ -236,3 +236,10 @@
236
236
  add->forceMaxConcurrentRequestsPerProcess;
237
237
 
238
238
 
239
+
240
+ config->lveMinUid =
241
+ (add->lveMinUid == UNSET_INT_VALUE) ?
242
+ base->lveMinUid :
243
+ add->lveMinUid;
244
+
245
+
@@ -155,3 +155,8 @@
155
155
  sizeof("!~PASSENGER_FORCE_MAX_CONCURRENT_REQUESTS_PER_PROCESS") - 1), config->forceMaxConcurrentRequestsPerProcess);
156
156
 
157
157
 
158
+
159
+ addHeader(r, result, StaticString("!~PASSENGER_LVE_MIN_UID",
160
+ sizeof("!~PASSENGER_LVE_MIN_UID") - 1), config->lveMinUid);
161
+
162
+
@@ -65,6 +65,8 @@
65
65
 
66
66
  #define DEFAULT_LOG_LEVEL 3
67
67
 
68
+ #define DEFAULT_LVE_MIN_UID 500
69
+
68
70
  #define DEFAULT_MAX_POOL_SIZE 6
69
71
 
70
72
  #define DEFAULT_MAX_PRELOADER_IDLE_TIME 300
@@ -121,7 +123,7 @@
121
123
 
122
124
  #define PASSENGER_DEFAULT_USER "nobody"
123
125
 
124
- #define PASSENGER_VERSION "5.0.27"
126
+ #define PASSENGER_VERSION "5.0.28"
125
127
 
126
128
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
127
129