new release (2.24.1)
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
This commit is contained in:
parent
35eed3ca3e
commit
90c24eea03
8 changed files with 68 additions and 17 deletions
|
|
@ -43,7 +43,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -223,7 +223,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_admin</allow_any>
|
<allow_any>auth_admin</allow_any>
|
||||||
<allow_inactive>auth_admin</allow_inactive>
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
<allow_active>yes</allow_active>
|
<allow_active>auth_admin</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
|
|
||||||
10
tuned.spec
10
tuned.spec
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
Summary: A dynamic adaptive system tuning daemon
|
Summary: A dynamic adaptive system tuning daemon
|
||||||
Name: tuned
|
Name: tuned
|
||||||
Version: 2.24.0
|
Version: 2.24.1
|
||||||
Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist}
|
Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist}
|
||||||
License: GPL-2.0-or-later AND CC-BY-SA-3.0
|
License: GPL-2.0-or-later AND CC-BY-SA-3.0
|
||||||
Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
|
Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
|
||||||
|
|
@ -631,6 +631,14 @@ fi
|
||||||
%config(noreplace) %{_sysconfdir}/tuned/ppd.conf
|
%config(noreplace) %{_sysconfdir}/tuned/ppd.conf
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Nov 26 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.24.1-1
|
||||||
|
- new release
|
||||||
|
- fixed privileged execution of arbitrary scripts by active local user
|
||||||
|
resolves: CVE-2024-52336
|
||||||
|
- added sanity checks for API methods parameters
|
||||||
|
resolves: CVE-2024-52337
|
||||||
|
- tuned-ppd: fixed controller init to correctly set _on_battery
|
||||||
|
|
||||||
* Wed Aug 7 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.24.0-1
|
* Wed Aug 7 2024 Jaroslav Škarvada <jskarvad@redhat.com> - 2.24.0-1
|
||||||
- new release
|
- new release
|
||||||
- clear plugin repository when stopping tuning
|
- clear plugin repository when stopping tuning
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
|
import string
|
||||||
|
|
||||||
|
NAMES_ALLOWED_CHARS = string.ascii_letters + string.digits + " !@'+-.,/:;_$&*()%<=>?#[]{|}^~" + '"'
|
||||||
|
NAMES_MAX_LENGTH = 4096
|
||||||
|
|
||||||
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
|
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
|
||||||
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
|
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
def switch_profile(self, profile_name, caller = None):
|
def switch_profile(self, profile_name, caller = None):
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized")
|
return (False, "Unauthorized")
|
||||||
|
if not self._cmd.is_valid_name(profile_name):
|
||||||
|
return (False, "Invalid profile_name")
|
||||||
return self._switch_profile(profile_name, True)
|
return self._switch_profile(profile_name, True)
|
||||||
|
|
||||||
@exports.export("", "(bs)")
|
@exports.export("", "(bs)")
|
||||||
|
|
@ -262,8 +264,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
|
|
||||||
@exports.export("s", "(bsss)")
|
@exports.export("s", "(bsss)")
|
||||||
def profile_info(self, profile_name, caller = None):
|
def profile_info(self, profile_name, caller = None):
|
||||||
if caller == "":
|
if caller == "" or not self._cmd.is_valid_name(profile_name):
|
||||||
return tuple(False, "", "", "")
|
return (False, "", "", "")
|
||||||
if profile_name is None or profile_name == "":
|
if profile_name is None or profile_name == "":
|
||||||
profile_name = self.active_profile()
|
profile_name = self.active_profile()
|
||||||
return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""]))
|
return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""]))
|
||||||
|
|
@ -294,7 +296,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
dictionary -- {plugin_name: {parameter_name: default_value}}
|
dictionary -- {plugin_name: {parameter_name: default_value}}
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return False
|
return {}
|
||||||
plugins = {}
|
plugins = {}
|
||||||
for plugin_class in self._daemon.get_all_plugins():
|
for plugin_class in self._daemon.get_all_plugins():
|
||||||
plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1]
|
plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1]
|
||||||
|
|
@ -307,8 +309,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
@exports.export("s","s")
|
@exports.export("s","s")
|
||||||
def get_plugin_documentation(self, plugin_name, caller = None):
|
def get_plugin_documentation(self, plugin_name, caller = None):
|
||||||
"""Return docstring of plugin's class"""
|
"""Return docstring of plugin's class"""
|
||||||
if caller == "":
|
if caller == "" or not self._cmd.is_valid_name(plugin_name):
|
||||||
return False
|
return ""
|
||||||
return self._daemon.get_plugin_documentation(str(plugin_name))
|
return self._daemon.get_plugin_documentation(str(plugin_name))
|
||||||
|
|
||||||
@exports.export("s","a{ss}")
|
@exports.export("s","a{ss}")
|
||||||
|
|
@ -321,8 +323,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
Return:
|
Return:
|
||||||
dictionary -- {parameter_name: hint}
|
dictionary -- {parameter_name: hint}
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "" or not self._cmd.is_valid_name(plugin_name):
|
||||||
return False
|
return {}
|
||||||
return self._daemon.get_plugin_hints(str(plugin_name))
|
return self._daemon.get_plugin_hints(str(plugin_name))
|
||||||
|
|
||||||
@exports.export("s", "b")
|
@exports.export("s", "b")
|
||||||
|
|
@ -335,7 +337,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
Return:
|
Return:
|
||||||
bool -- True on success
|
bool -- True on success
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "" or not self._cmd.is_valid_name(path):
|
||||||
return False
|
return False
|
||||||
if self._daemon._application and self._daemon._application._unix_socket_exporter:
|
if self._daemon._application and self._daemon._application._unix_socket_exporter:
|
||||||
self._daemon._application._unix_socket_exporter.register_signal_path(path)
|
self._daemon._application._unix_socket_exporter.register_signal_path(path)
|
||||||
|
|
@ -349,6 +351,10 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
def instance_acquire_devices(self, devices, instance_name, caller = None):
|
def instance_acquire_devices(self, devices, instance_name, caller = None):
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized")
|
return (False, "Unauthorized")
|
||||||
|
if not self._cmd.is_valid_name(devices):
|
||||||
|
return (False, "Invalid devices")
|
||||||
|
if not self._cmd.is_valid_name(instance_name):
|
||||||
|
return (False, "Invalid instance_name")
|
||||||
found = False
|
found = False
|
||||||
for instance_target in self._daemon._unit_manager.instances:
|
for instance_target in self._daemon._unit_manager.instances:
|
||||||
if instance_target.name == instance_name:
|
if instance_target.name == instance_name:
|
||||||
|
|
@ -399,6 +405,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized", [])
|
return (False, "Unauthorized", [])
|
||||||
|
if not self._cmd.is_valid_name(plugin_name):
|
||||||
|
return (False, "Invalid plugin_name", [])
|
||||||
if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
|
if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
|
||||||
rets = "Plugin '%s' does not exist" % plugin_name
|
rets = "Plugin '%s' does not exist" % plugin_name
|
||||||
log.error(rets)
|
log.error(rets)
|
||||||
|
|
@ -422,6 +430,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized", [])
|
return (False, "Unauthorized", [])
|
||||||
|
if not self._cmd.is_valid_name(instance_name):
|
||||||
|
return (False, "Invalid instance_name", [])
|
||||||
for instance in self._daemon._unit_manager.instances:
|
for instance in self._daemon._unit_manager.instances:
|
||||||
if instance.name == instance_name:
|
if instance.name == instance_name:
|
||||||
return (True, "OK", sorted(list(instance.processed_devices)))
|
return (True, "OK", sorted(list(instance.processed_devices)))
|
||||||
|
|
@ -444,6 +454,13 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized")
|
return (False, "Unauthorized")
|
||||||
|
if not self._cmd.is_valid_name(plugin_name):
|
||||||
|
return (False, "Invalid plugin_name")
|
||||||
|
if not self._cmd.is_valid_name(instance_name):
|
||||||
|
return (False, "Invalid instance_name")
|
||||||
|
for (key, value) in options.items():
|
||||||
|
if not self._cmd.is_valid_name(key) or not self._cmd.is_valid_name(value):
|
||||||
|
return (False, "Invalid options")
|
||||||
plugins = {p.name: p for p in self._daemon._unit_manager.plugins}
|
plugins = {p.name: p for p in self._daemon._unit_manager.plugins}
|
||||||
if not plugin_name in plugins.keys():
|
if not plugin_name in plugins.keys():
|
||||||
rets = "Plugin '%s' not found" % plugin_name
|
rets = "Plugin '%s' not found" % plugin_name
|
||||||
|
|
@ -499,6 +516,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||||
"""
|
"""
|
||||||
if caller == "":
|
if caller == "":
|
||||||
return (False, "Unauthorized")
|
return (False, "Unauthorized")
|
||||||
|
if not self._cmd.is_valid_name(instance_name):
|
||||||
|
return (False, "Invalid instance_name")
|
||||||
try:
|
try:
|
||||||
instance = [i for i in self._daemon._unit_manager.instances if i.name == instance_name][0]
|
instance = [i for i in self._daemon._unit_manager.instances if i.name == instance_name][0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,14 @@ class Plugin(object):
|
||||||
def _instance_post_static(self, instance, enabling):
|
def _instance_post_static(self, instance, enabling):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _safe_script_path(self, path):
|
||||||
|
path = os.path.realpath(path)
|
||||||
|
profile_paths = self._global_cfg.get_list(consts.CFG_PROFILE_DIRS, consts.CFG_DEF_PROFILE_DIRS)
|
||||||
|
for p in profile_paths:
|
||||||
|
if path.startswith(p):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _call_device_script(self, instance, script, op, devices, rollback = consts.ROLLBACK_SOFT):
|
def _call_device_script(self, instance, script, op, devices, rollback = consts.ROLLBACK_SOFT):
|
||||||
if script is None:
|
if script is None:
|
||||||
return None
|
return None
|
||||||
|
|
@ -223,6 +231,10 @@ class Plugin(object):
|
||||||
log.error("Relative paths cannot be used in script_pre or script_post. " \
|
log.error("Relative paths cannot be used in script_pre or script_post. " \
|
||||||
+ "Use ${i:PROFILE_DIR}.")
|
+ "Use ${i:PROFILE_DIR}.")
|
||||||
return False
|
return False
|
||||||
|
if not self._safe_script_path(script):
|
||||||
|
log.error("Paths outside of the profile directories cannot be used in the " \
|
||||||
|
+ "script_pre or script_post, ignoring script: '%s'" % script)
|
||||||
|
return False
|
||||||
dir_name = os.path.dirname(script)
|
dir_name = os.path.dirname(script)
|
||||||
ret = True
|
ret = True
|
||||||
for dev in devices:
|
for dev in devices:
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ class ScriptPlugin(base.Plugin):
|
||||||
for script in scripts:
|
for script in scripts:
|
||||||
environ = os.environ
|
environ = os.environ
|
||||||
environ.update(self._variables.get_env())
|
environ.update(self._variables.get_env())
|
||||||
|
if not self._safe_script_path(script):
|
||||||
|
log.error("Paths outside of the profile directories cannot be used in the script, " \
|
||||||
|
+ "ignoring script: '%s'." % script)
|
||||||
|
continue
|
||||||
log.info("calling script '%s' with arguments '%s'" % (script, str(arguments)))
|
log.info("calling script '%s' with arguments '%s'" % (script, str(arguments)))
|
||||||
log.debug("using environment '%s'" % str(list(environ.items())))
|
log.debug("using environment '%s'" % str(list(environ.items())))
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -548,3 +548,7 @@ class commands:
|
||||||
import string
|
import string
|
||||||
trans = string.maketrans(source_chars, dest_chars)
|
trans = string.maketrans(source_chars, dest_chars)
|
||||||
return text.translate(trans)
|
return text.translate(trans)
|
||||||
|
|
||||||
|
# Checks if name contains only valid characters and has valid length or is empty string or None
|
||||||
|
def is_valid_name(self, name):
|
||||||
|
return not name or (all(c in consts.NAMES_ALLOWED_CHARS for c in name) and len(name) <= consts.NAMES_MAX_LENGTH)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
TUNED_VERSION_MAJOR = 2
|
TUNED_VERSION_MAJOR = 2
|
||||||
TUNED_VERSION_MINOR = 24
|
TUNED_VERSION_MINOR = 24
|
||||||
TUNED_VERSION_PATCH = 0
|
TUNED_VERSION_PATCH = 1
|
||||||
|
|
||||||
TUNED_VERSION_STR = "%d.%d.%d" % (TUNED_VERSION_MAJOR, TUNED_VERSION_MINOR, TUNED_VERSION_PATCH)
|
TUNED_VERSION_STR = "%d.%d.%d" % (TUNED_VERSION_MAJOR, TUNED_VERSION_MINOR, TUNED_VERSION_PATCH)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue