diff --git a/tuned/consts.py b/tuned/consts.py index 3749363..3b41ed9 100644 --- a/tuned/consts.py +++ b/tuned/consts.py @@ -1,4 +1,8 @@ import logging +import string + +NAMES_ALLOWED_CHARS = string.ascii_letters + string.digits + " !@'+-.,/:;_$&*()%<=>?#[]{|}^~" + '"' +NAMES_MAX_LENGTH = 4096 GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf" ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile" diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index 6a59a1d..94e9022 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -182,6 +182,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): def switch_profile(self, profile_name, caller = None): if caller == "": return (False, "Unauthorized") + if not self._cmd.is_valid_name(profile_name): + return (False, "Invalid profile_name") return self._switch_profile(profile_name, True) @exports.export("", "(bs)") @@ -255,8 +257,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): @exports.export("s", "(bsss)") def profile_info(self, profile_name, caller = None): - if caller == "": - return tuple(False, "", "", "") + if caller == "" or not self._cmd.is_valid_name(profile_name): + return (False, "", "", "") if profile_name is None or profile_name == "": 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], [""])) @@ -287,7 +289,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface): dictionary -- {plugin_name: {parameter_name: default_value}} """ if caller == "": - return False + return {} plugins = {} for plugin_class in self._daemon.get_all_plugins(): plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1] @@ -300,8 +302,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): @exports.export("s","s") def get_plugin_documentation(self, plugin_name, caller = None): """Return docstring of plugin's class""" - if caller == "": - return False + if caller == "" or not self._cmd.is_valid_name(plugin_name): + return "" return self._daemon.get_plugin_documentation(str(plugin_name)) @exports.export("s","a{ss}") @@ -314,8 +316,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): Return: dictionary -- {parameter_name: hint} """ - if caller == "": - return False + if caller == "" or not self._cmd.is_valid_name(plugin_name): + return {} return self._daemon.get_plugin_hints(str(plugin_name)) @exports.export("s", "b") @@ -328,7 +330,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface): Return: bool -- True on success """ - if caller == "": + if caller == "" or not self._cmd.is_valid_name(path): return False if self._daemon._application and self._daemon._application._unix_socket_exporter: self._daemon._application._unix_socket_exporter.register_signal_path(path) @@ -342,6 +344,10 @@ class Controller(tuned.exports.interfaces.ExportableInterface): def instance_acquire_devices(self, devices, instance_name, caller = None): if caller == "": 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 for instance_target in self._daemon._unit_manager.instances: if instance_target.name == instance_name: @@ -388,6 +394,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): """ if caller == "": 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(): rets = "Plugin '%s' does not exist" % plugin_name log.error(rets) @@ -411,6 +419,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface): """ if caller == "": 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: if instance.name == instance_name: return (True, "OK", sorted(list(instance.processed_devices))) diff --git a/tuned/utils/commands.py b/tuned/utils/commands.py index ce51fc0..38d95ef 100644 --- a/tuned/utils/commands.py +++ b/tuned/utils/commands.py @@ -544,3 +544,7 @@ class commands: import string trans = string.maketrans(source_chars, dest_chars) 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)