use Bugzilla::Install::Util qw(bin_loc install_string);
use Bugzilla::Util qw(generate_random_password wrap_hard);
+use Mojo::JSON qw(encode_json);
use Data::Dumper;
use File::Basename qw(dirname);
use English qw($EGID);
},
},
{
- name => 'apache_size_limit',
- default => 600000,
+ name => 'setrlimit',
+ default => encode_json({ RLIMIT_AS => 2e9 }),
+ },
+ {
+ name => 'size_limit',
+ default => 750000,
},
{
name => 'memcached_servers',
$self->plugin('Bugzilla::Quantum::Plugin::Glue');
$self->plugin('Bugzilla::Quantum::Plugin::Hostage')
unless $ENV{BUGZILLA_DISABLE_HOSTAGE};
+ $self->plugin('Bugzilla::Quantum::Plugin::SizeLimit')
+ unless $ENV{BUGZILLA_DISABLE_SIZELIMIT};
$self->plugin('Bugzilla::Quantum::Plugin::BlockIP');
$self->plugin('Bugzilla::Quantum::Plugin::Helpers');
--- /dev/null
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Quantum::Plugin::SizeLimit;
+use 5.10.1;
+use Mojo::Base 'Mojolicious::Plugin';
+use Mojo::JSON qw(decode_json);
+use Bugzilla::Logging;
+
+use constant MIN_SIZE_LIMIT => 750_000;
+use constant HAVE_LINUX_SMAPS_TINY => eval { require Linux::Smaps::Tiny };
+use constant HAVE_BSD_RESOURCE => eval { require BSD::Resource };
+
+BEGIN {
+ if (HAVE_LINUX_SMAPS_TINY) {
+ Linux::Smaps::Tiny->import('get_smaps_summary');
+ }
+ if (HAVE_BSD_RESOURCE) {
+ BSD::Resource->import;
+ }
+}
+
+my @RESOURCES = qw(
+ RLIMIT_CPU RLIMIT_FSIZE RLIMIT_DATA RLIMIT_STACK RLIMIT_CORE RLIMIT_RSS RLIMIT_MEMLOCK RLIMIT_NPROC RLIMIT_NOFILE
+ RLIMIT_OFILE RLIMIT_OPEN_MAX RLIMIT_LOCKS RLIMIT_AS RLIMIT_VMEM RLIMIT_PTHREAD RLIMIT_TCACHE RLIMIT_AIO_MEM
+ RLIMIT_AIO_OPS RLIMIT_FREEMEM RLIMIT_NTHR RLIMIT_NPTS RLIMIT_RSESTACK RLIMIT_SBSIZE RLIMIT_SWAP RLIMIT_MSGQUEUE
+ RLIMIT_RTPRIO RLIMIT_RTTIME RLIMIT_SIGPENDING
+);
+
+my %RESOURCE;
+if (HAVE_BSD_RESOURCE) {
+ $RESOURCE{$_} = eval $_ for @RESOURCES;
+}
+
+sub register {
+ my ($self, $app, $conf) = @_;
+
+ if (HAVE_BSD_RESOURCE) {
+ my $setrlimit = decode_json(Bugzilla->localconfig->{setrlimit});
+
+ # This trick means the master process will not a size limit.
+ Mojo::IOLoop->next_tick(sub {
+ foreach my $resource (keys %$setrlimit) {
+ setrlimit($RESOURCE{$resource}, $setrlimit->{$resource}, $setrlimit->{$resource});
+ }
+ });
+ }
+
+ if (HAVE_LINUX_SMAPS_TINY) {
+ my $size_limit = Bugzilla->localconfig->{size_limit};
+ return unless $size_limit;
+
+ if ($size_limit < MIN_SIZE_LIMIT) {
+ WARN(sprintf "size_limit cannot be smaller than %d", MIN_SIZE_LIMIT);
+ $size_limit = MIN_SIZE_LIMIT;
+ }
+
+ $app->hook(
+ after_dispatch => sub {
+ my $c = shift;
+ my $summary = get_smaps_summary();
+ if ($summary->{Size} >= $size_limit) {
+ my $diff = $summary->{Size} - $size_limit;
+ INFO("memory size exceeded $size_limit by $diff ($summary->{Size})");
+ $c->res->headers->connection('close');
+ Mojo::IOLoop->singleton->stop_gracefully;
+ }
+ }
+ );
+ }
+}
+
+1;
},
linux_smaps => {
description => 'Linux::Smaps::Tiny for limiting memory usage',
- prereqs => {runtime => {requires => {'Linux::Smaps::Tiny' => '0'}}},
+ prereqs => {runtime => {requires => {'Linux::Smaps::Tiny' => '0', 'BSD::Resource' => 0}}},
},
linux_pdeath => {
description => 'Linux::Pdeathsig for a good parent/child relationships',
BMO_shadowdbport
The port of the read-only database.
-BMO_apache_size_limit
- This is the max amount of unshared memory (in kb) that the apache process is
- allowed to use before Apache::SizeLimit kills it.
+BMO_setrlimit
+ This is a json object and can set any limit described in https://metacpan.org/pod/BSD::Resource.
+ Typically it used for setting RLIMIT_AS, and the default value is ``{ "RLIMIT_AS": 2000000000 }``.
+
+BMO_size_limit
+ This is the max amount of unshared memory the worker processes are allowed to
+ use before they will exit. Minimum 750000 (750MiB)
BMO_mail_delivery_method
Usually configured on the MTA section of admin interface, but may be set here for testing purposes.
$answer{'passwdqc_min'} = '8, 8, 8, 8, 8';
$answer{'ADMIN_REALNAME'} = 'Vagrant User';
$answer{'NO_PAUSE'} = 1;
-$answer{'apache_size_limit'} = 700000;
+$answer{'size_limit'} = 750000;
$answer{'bugzilla_version'} = '1';
$answer{'create_htaccess'} = '1';
$answer{'db_check'} = 1;
$answer{'ADMIN_PASSWORD'} = 'bmo4c9rocks';
$answer{'ADMIN_REALNAME'} = 'BMO Admin';
$answer{'NO_PAUSE'} = 1;
-$answer{'apache_size_limit'} = 700000;
+$answer{'size_limit'} = 750000;
$answer{'bugzilla_version'} = '1';
$answer{'create_htaccess'} = '';
$answer{'diffpath'} = '/usr/bin';
If you set this to anything other than "", you will need to run checksetup.pl
as ##root## or as a user who is a member of the specified group.
END
- localconfig_apache_size_limit => <<EOT,
-This is the max amount of unshared memory the apache process is allowed to use
-before Apache::SizeLimit kills it. This is only applicable when run under mod_perl.
+ localconfig_setrlimit => <<EOT,
+This a json object whose keys are the named constants for the setrlimit(1) C library
+function. The default sets RLIMIT_AS to 2GiB.
+EOT
+ localconfig_size_limit => <<EOT,
+This is the max amount of unshared memory the worker processes are allowed to use before they will exit.
EOT
localconfig_shadowdb_user => <<EOT,
The username used to authenticate to the shadow db.
$answer{'passwdqc_min'} = '8, 8, 8, 8, 8';
$answer{'ADMIN_REALNAME'} = 'Vagrant User';
$answer{'NO_PAUSE'} = 1;
-$answer{'apache_size_limit'} = 700000;
+$answer{'size_limit'} = 750000;
$answer{'bugzilla_version'} = '1';
$answer{'create_htaccess'} = '1';
$answer{'db_check'} = 1;