Commit 5c0433d6 authored by Iustin Pop's avatar Iustin Pop
Browse files

Merge branch 'stable-2.0' into stable-2.1

* stable-2.0:
  Update NEWS file and release Ganeti 2.0.5
  Security issue: add validation of script names
  Move the hooks file mask into
  Improve LUQueryNodes for lockless case
  Ship rapi.rst/rapi.html in the dist archive

Conflicts:    (reverted, not needed)
	NEWS           (simple fix for RST-ification)   (reverted, not needed)
	lib/ (adapted to new RPC result style)
Signed-off-by: default avatarIustin Pop <>
Reviewed-by: default avatarMichael Hanselmann <>
parents 5bc556dd e5823b7e
......@@ -101,6 +101,15 @@ Details
- Improved burnin
Version 2.0.5
- Fix security issue due to missing validation of iallocator names; this
allows local and remote execution of arbitrary executables
- Fix failure of gnt-node list during instance removal
- Ship the RAPI documentation in the archive
Version 2.0.4
......@@ -1731,10 +1731,11 @@ def _TryOSFromDisk(name, base_dir=None):
if base_dir is None:
os_dir = utils.FindFile(name, constants.OS_SEARCH_PATH, os.path.isdir)
if os_dir is None:
return False, "Directory for OS %s not found in search path" % name
os_dir = os.path.sep.join([base_dir, name])
os_dir = utils.FindFile(name, [base_dir], os.path.isdir)
if os_dir is None:
return False, "Directory for OS %s not found in search path" % name
status, api_versions = _OSOndiskAPIVersion(name, os_dir)
if not status:
......@@ -2612,8 +2613,6 @@ class HooksRunner(object):
on the master side.
RE_MASK = re.compile("^[a-zA-Z0-9_-]+$")
def __init__(self, hooks_base_dir=None):
"""Constructor for hooks runner.
......@@ -2721,7 +2720,7 @@ class HooksRunner(object):
for relname in dir_contents:
fname = os.path.join(dir_name, relname)
if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and
self.RE_MASK.match(relname) is not None):
constants.EXT_PLUGIN_MASK.match(relname) is not None):
rrval = constants.HKR_SKIP
output = ""
......@@ -2547,10 +2547,9 @@ class LUQueryNodes(NoHooksLU):
inst_fields = frozenset(("pinst_cnt", "pinst_list",
"sinst_cnt", "sinst_list"))
if inst_fields & frozenset(self.op.output_fields):
instancelist = self.cfg.GetInstanceList()
inst_data = self.cfg.GetAllInstancesInfo()
for instance_name in instancelist:
inst = self.cfg.GetInstanceInfo(instance_name)
for instance_name, inst in inst_data.items():
if inst.primary_node in node_to_primary:
for secnode in inst.secondary_nodes:
......@@ -21,6 +21,8 @@
"""Module holding different constants."""
import re
from ganeti import _autoconf
# various versions
......@@ -174,6 +176,9 @@ VALUE_NONE = "none"
VALUE_TRUE = "true"
VALUE_FALSE = "false"
# External script validation mask
EXT_PLUGIN_MASK = re.compile("^[a-zA-Z0-9_-]+$")
# hooks-related constants
......@@ -1656,9 +1656,17 @@ def FindFile(name, search_path, test=os.path.exists):
@return: full path to the object if found, None otherwise
# validate the filename mask
if constants.EXT_PLUGIN_MASK.match(name) is None:
logging.critical("Invalid value passed for external script name: '%s'",
return None
for dir_name in search_path:
item_name = os.path.sep.join([dir_name, name])
if test(item_name):
# check the user test and that we're indeed resolving to the given
# basename
if test(item_name) and os.path.basename(item_name) == name:
return item_name
return None
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment