summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2016-04-19 13:17:13 +0000
committerMatt Riedemann <mriedem@us.ibm.com>2016-06-21 15:44:39 +0000
commitd65d931da8490576f0abf30f124ca3a032b481c7 (patch)
treeaff519fa53ddb931ad7b08081b309f21db58b989
parente33f64fc7920bc4c7051f35042237403fddf1f02 (diff)
downloadoslo-concurrency-stable/liberty.tar.gz
processutils: add support for missing process limitsliberty-eol2.6.1stable/liberty
The original commit adding support for process limits only wired up address space, max files and resident set size limits. This is not sufficient to enable nova to protect qemu-img commands against malicious images. This commit adds support for the remaining limits supported by python: core file size, cpu time, data size, file size, locked memory size, max processes and stack size. Related-bug: #1449062 Change-Id: I164c4b35e1357a0f80ed7fe00a7ae8f49df92e31 (cherry picked from commit 8af826953d1ad2cab2ecf360e0c794de70a367c3) (cherry picked from commit 5f417f8e9656e097070036daced26d8b0f3728c3)
-rw-r--r--oslo_concurrency/prlimit.py21
-rw-r--r--oslo_concurrency/processutils.py38
-rw-r--r--oslo_concurrency/tests/unit/test_processutils.py37
3 files changed, 85 insertions, 11 deletions
diff --git a/oslo_concurrency/prlimit.py b/oslo_concurrency/prlimit.py
index f7718de..e0fc4e3 100644
--- a/oslo_concurrency/prlimit.py
+++ b/oslo_concurrency/prlimit.py
@@ -26,8 +26,15 @@ USAGE_PROGRAM = ('%s -m oslo_concurrency.prlimit'
RESOURCES = (
# argparse argument => resource
('as', resource.RLIMIT_AS),
+ ('core', resource.RLIMIT_CORE),
+ ('cpu', resource.RLIMIT_CPU),
+ ('data', resource.RLIMIT_DATA),
+ ('fsize', resource.RLIMIT_FSIZE),
+ ('memlock', resource.RLIMIT_MEMLOCK),
('nofile', resource.RLIMIT_NOFILE),
+ ('nproc', resource.RLIMIT_NPROC),
('rss', resource.RLIMIT_RSS),
+ ('stack', resource.RLIMIT_STACK),
)
@@ -35,10 +42,24 @@ def parse_args():
parser = argparse.ArgumentParser(description='prlimit', prog=USAGE_PROGRAM)
parser.add_argument('--as', type=int,
help='Address space limit in bytes')
+ parser.add_argument('--core', type=int,
+ help='Core file size limit in bytes')
+ parser.add_argument('--cpu', type=int,
+ help='CPU time limit in seconds')
+ parser.add_argument('--data', type=int,
+ help='Data size limit in bytes')
+ parser.add_argument('--fsize', type=int,
+ help='File size limit in bytes')
+ parser.add_argument('--memlock', type=int,
+ help='Locked memory limit in bytes')
parser.add_argument('--nofile', type=int,
help='Maximum number of open files')
+ parser.add_argument('--nproc', type=int,
+ help='Maximum number of processes')
parser.add_argument('--rss', type=int,
help='Maximum Resident Set Size (RSS) in bytes')
+ parser.add_argument('--stack', type=int,
+ help='Stack size limit in bytes')
parser.add_argument('program',
help='Program (absolute path)')
parser.add_argument('program_args', metavar="arg", nargs='...',
diff --git a/oslo_concurrency/processutils.py b/oslo_concurrency/processutils.py
index 8c6c9f9..91a98b9 100644
--- a/oslo_concurrency/processutils.py
+++ b/oslo_concurrency/processutils.py
@@ -107,16 +107,36 @@ class ProcessLimits(object):
Attributes:
* address_space: Address space limit in bytes
- * number_files: Maximum number of open files.
+ * core_file_size: Core file size limit in bytes
+ * cpu_time: CPU time limit in seconds
+ * data_size: Data size limit in bytes
+ * file_size: File size limit in bytes
+ * memory_locked: Locked memory limit in bytes
+ * number_files: Maximum number of open files
+ * number_processes: Maximum number of processes
* resident_set_size: Maximum Resident Set Size (RSS) in bytes
+ * stack_size: Stack size limit in bytes
This object can be used for the *prlimit* parameter of :func:`execute`.
"""
+ _LIMITS = {
+ "address_space": "--as",
+ "core_file_size": "--core",
+ "cpu_time": "--cpu",
+ "data_size": "--data",
+ "file_size": "--fsize",
+ "memory_locked": "--memlock",
+ "number_files": "--nofile",
+ "number_processes": "--nproc",
+ "resident_set_size": "--rss",
+ "stack_size": "--stack",
+ }
+
def __init__(self, **kw):
- self.address_space = kw.pop('address_space', None)
- self.number_files = kw.pop('number_files', None)
- self.resident_set_size = kw.pop('resident_set_size', None)
+ for limit in self._LIMITS.keys():
+ setattr(self, limit, kw.pop(limit, None))
+
if kw:
raise ValueError("invalid limits: %s"
% ', '.join(sorted(kw.keys())))
@@ -124,12 +144,10 @@ class ProcessLimits(object):
def prlimit_args(self):
"""Create a list of arguments for the prlimit command line."""
args = []
- if self.address_space:
- args.append('--as=%s' % self.address_space)
- if self.number_files:
- args.append('--nofile=%s' % self.number_files)
- if self.resident_set_size:
- args.append('--rss=%s' % self.resident_set_size)
+ for limit in self._LIMITS.keys():
+ val = getattr(self, limit)
+ if val is not None:
+ args.append("%s=%s" % (self._LIMITS[limit], val))
return args
diff --git a/oslo_concurrency/tests/unit/test_processutils.py b/oslo_concurrency/tests/unit/test_processutils.py
index 5186d9a..f326703 100644
--- a/oslo_concurrency/tests/unit/test_processutils.py
+++ b/oslo_concurrency/tests/unit/test_processutils.py
@@ -733,7 +733,7 @@ class PrlimitTestCase(test_base.BaseTestCase):
# Create a new soft limit for a resource, lower than the current
# soft limit.
soft_limit, hard_limit = resource.getrlimit(res)
- if soft_limit < 0:
+ if soft_limit <= 0:
soft_limit = default_limit
else:
soft_limit -= substract
@@ -771,6 +771,31 @@ class PrlimitTestCase(test_base.BaseTestCase):
prlimit = self.limit_address_space()
self.check_limit(prlimit, 'RLIMIT_AS', prlimit.address_space)
+ def test_core_size(self):
+ size = self.soft_limit(resource.RLIMIT_CORE, 1, 1024)
+ prlimit = processutils.ProcessLimits(core_file_size=size)
+ self.check_limit(prlimit, 'RLIMIT_CORE', prlimit.core_file_size)
+
+ def test_cpu_time(self):
+ time = self.soft_limit(resource.RLIMIT_CPU, 1, 1024)
+ prlimit = processutils.ProcessLimits(cpu_time=time)
+ self.check_limit(prlimit, 'RLIMIT_CPU', prlimit.cpu_time)
+
+ def test_data_size(self):
+ max_memory = self.memory_limit(resource.RLIMIT_DATA)
+ prlimit = processutils.ProcessLimits(data_size=max_memory)
+ self.check_limit(prlimit, 'RLIMIT_DATA', max_memory)
+
+ def test_file_size(self):
+ size = self.soft_limit(resource.RLIMIT_FSIZE, 1, 1024)
+ prlimit = processutils.ProcessLimits(file_size=size)
+ self.check_limit(prlimit, 'RLIMIT_FSIZE', prlimit.file_size)
+
+ def test_memory_locked(self):
+ max_memory = self.memory_limit(resource.RLIMIT_MEMLOCK)
+ prlimit = processutils.ProcessLimits(memory_locked=max_memory)
+ self.check_limit(prlimit, 'RLIMIT_MEMLOCK', max_memory)
+
def test_resident_set_size(self):
max_memory = self.memory_limit(resource.RLIMIT_RSS)
prlimit = processutils.ProcessLimits(resident_set_size=max_memory)
@@ -781,6 +806,16 @@ class PrlimitTestCase(test_base.BaseTestCase):
prlimit = processutils.ProcessLimits(number_files=nfiles)
self.check_limit(prlimit, 'RLIMIT_NOFILE', nfiles)
+ def test_number_processes(self):
+ nprocs = self.soft_limit(resource.RLIMIT_NPROC, 1, 65535)
+ prlimit = processutils.ProcessLimits(number_processes=nprocs)
+ self.check_limit(prlimit, 'RLIMIT_NPROC', nprocs)
+
+ def test_stack_size(self):
+ max_memory = self.memory_limit(resource.RLIMIT_STACK)
+ prlimit = processutils.ProcessLimits(stack_size=max_memory)
+ self.check_limit(prlimit, 'RLIMIT_STACK', max_memory)
+
def test_unsupported_prlimit(self):
self.assertRaises(ValueError, processutils.ProcessLimits, xxx=33)