Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.2
backintime
backintime-security_hardening_backport.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File backintime-security_hardening_backport.patch of Package backintime
--- common/backintime.orig +++ common/backintime @@ -24,4 +24,4 @@ else APP_PATH=$(readlink -m "${CUR_PATH}/../share/backintime/common") fi -python3 $APP_PATH/backintime.py "$@" +python3 -Es $APP_PATH/backintime.py "$@" --- common/backintime-askpass.orig +++ common/backintime-askpass @@ -28,4 +28,4 @@ else APP_PATH=$(readlink -m "${CUR_PATH}/../share/backintime/common") fi -python3 $APP_PATH/askpass.py "$@" +python3 -Es $APP_PATH/askpass.py "$@" --- common/config.py.orig +++ common/config.py @@ -36,7 +36,7 @@ import sshtools import encfstools import password import pluginmanager -from exceptions import PermissionDeniedByPolicy, InvalidChar +from exceptions import PermissionDeniedByPolicy, InvalidChar, InvalidCmd, LimitExceeded _=gettext.gettext @@ -930,7 +930,7 @@ class Config( configfile.ConfigFileWithP self.set_profile_bool_value( 'snapshots.backup_on_restore.enabled', value, profile_id ) def is_run_nice_from_cron_enabled( self, profile_id = None ): - #?Run cronjobs with 'nice \-n 19'. This will give BackInTime the + #?Run cronjobs with 'nice \-n19'. This will give BackInTime the #?lowest CPU priority to not interupt any other working process. return self.get_profile_bool_value( 'snapshots.cron.nice', self.DEFAULT_RUN_NICE_FROM_CRON, profile_id ) @@ -955,7 +955,7 @@ class Config( configfile.ConfigFileWithP self.set_profile_bool_value( 'snapshots.user_backup.ionice', value, profile_id ) def is_run_nice_on_remote_enabled(self, profile_id = None): - #?Run rsync and other commands on remote host with 'nice \-n 19' + #?Run rsync and other commands on remote host with 'nice \-n19' return self.get_profile_bool_value('snapshots.ssh.nice', self.DEFAULT_RUN_NICE_ON_REMOTE, profile_id) def set_run_nice_on_remote_enabled(self, value, profile_id = None): @@ -1530,7 +1530,7 @@ class Config( configfile.ConfigFileWithP self.set_profile_str_value('snapshots.path.uuid', uuid, profile_id) try: self.setupUdev.addRule(self.cron_cmd(profile_id), uuid) - except InvalidChar as e: + except (InvalidChar, InvalidCmd, LimitExceeded) as e: logger.error(str(e), self) self.notify_error(str(e)) return False @@ -1560,7 +1560,7 @@ class Config( configfile.ConfigFileWithP if self.is_run_ionice_from_cron_enabled(profile_id) and tools.check_command('ionice'): cmd = tools.which('ionice') + ' -c2 -n7 ' + cmd if self.is_run_nice_from_cron_enabled( profile_id ) and tools.check_command('nice'): - cmd = tools.which('nice') + ' -n 19 ' + cmd + cmd = tools.which('nice') + ' -n19 ' + cmd return cmd if __name__ == "__main__": --- common/exceptions.py.orig +++ common/exceptions.py @@ -39,6 +39,20 @@ class InvalidChar(BackInTimeException): def __str__(self): return self.msg +class InvalidCmd(BackInTimeException): + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + +class LimitExceeded(BackInTimeException): + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + class PermissionDeniedByPolicy(BackInTimeException): def __init__(self, msg): self.msg = msg --- common/password.py.orig +++ common/password.py @@ -52,7 +52,7 @@ class Password_Cache(tools.Daemon): os.mkdir(pw_cache_path, 0o700) else: os.chmod(pw_cache_path, 0o700) - super(Password_Cache, self).__init__(self.config.get_password_cache_pid(), *args, **kwargs) + super(Password_Cache, self).__init__(self.config.get_password_cache_pid(), umask=0o077, *args, **kwargs) self.db_keyring = {} self.db_usr = {} self.fifo = password_ipc.FIFO(self.config.get_password_cache_fifo()) --- common/tools.py.orig +++ common/tools.py @@ -53,7 +53,7 @@ except ImportError: import configfile import logger from applicationinstance import ApplicationInstance -from exceptions import Timeout, InvalidChar, PermissionDeniedByPolicy +from exceptions import Timeout, InvalidChar, InvalidCmd, LimitExceeded, PermissionDeniedByPolicy ON_AC = 0 ON_BATTERY = 1 @@ -379,7 +379,7 @@ def _execute( cmd, callback = None, user def is_process_alive( pid ): try: - os.kill( pid, 0 ) #this will raise an exception if the pid is not valid + os.kill(pid, 0) #this will raise an exception if the pid is not valid except: return False @@ -1231,6 +1231,10 @@ class SetupUdev(object): except dbus.exceptions.DBusException as e: if e._dbus_error_name == 'net.launchpad.backintime.InvalidChar': raise InvalidChar(str(e)) + elif e._dbus_error_name == 'net.launchpad.backintime.InvalidCmd': + raise InvalidCmd(str(e)) + elif e._dbus_error_name == 'net.launchpad.backintime.LimitExceeded': + raise LimitExceeded(str(e)) else: raise @@ -1299,11 +1303,12 @@ class Daemon: License CC BY-SA 3.0 http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ """ - def __init__(self, pidfile = None, stdin='/dev/null', stdout='/dev/stdout', stderr='/dev/null'): + def __init__(self, pidfile = None, stdin='/dev/null', stdout='/dev/stdout', stderr='/dev/null', umask=0o022): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile + self.umask = umask if pidfile: self.appInstance = ApplicationInstance(pidfile, auto_exit = False, flock = False) @@ -1327,7 +1332,7 @@ class Daemon: logger.debug('decouple from parent environment', self) os.chdir("/") os.setsid() - os.umask(0) + os.umask(self.umask) # do second fork try: --- qt4/backintime-qt4.orig +++ qt4/backintime-qt4 @@ -28,4 +28,4 @@ else APP_PATH=$(readlink -m "${CUR_PATH}/../share/backintime/qt4") fi -python3 ${APP_PATH}/app.py "$@" +python3 -Es ${APP_PATH}/app.py "$@" --- qt4/net.launchpad.backintime.serviceHelper.conf.orig +++ qt4/net.launchpad.backintime.serviceHelper.conf @@ -7,13 +7,11 @@ <!-- Only root can own the service --> <policy user="root"> <allow own="net.launchpad.backintime.serviceHelper"/> - <allow send_destination="net.launchpad.backintime.serviceHelper"/> - <allow send_interface="net.launchpad.backintime.serviceHelper.UdevRules"/> + <allow send_destination="net.launchpad.backintime.serviceHelper" send_interface="net.launchpad.backintime.serviceHelper.UdevRules"/> </policy> <!-- Allow anyone to invoke methods on the interfaces --> <policy context="default"> - <deny own="net.launchpad.backintime.serviceHelper"/> - <allow send_destination="net.launchpad.backintime.serviceHelper"/> + <allow send_destination="net.launchpad.backintime.serviceHelper" send_interface="net.launchpad.backintime.serviceHelper.UdevRules"/> </policy> </busconfig> --- qt4/net.launchpad.backintime.serviceHelper.service.orig +++ qt4/net.launchpad.backintime.serviceHelper.service @@ -1,4 +1,4 @@ [D-BUS Service] Name=net.launchpad.backintime.serviceHelper -Exec=/usr/bin/python3 /usr/share/backintime/qt4/serviceHelper.py +Exec=/usr/bin/python3 -Es /usr/share/backintime/qt4/serviceHelper.py User=root --- qt4/serviceHelper.py.orig +++ qt4/serviceHelper.py @@ -79,6 +79,12 @@ UDEV_RULES_PATH = '/etc/udev/rules.d/99- class InvalidChar(dbus.DBusException): _dbus_error_name = 'net.launchpad.backintime.InvalidChar' +class InvalidCmd(dbus.DBusException): + _dbus_error_name = 'net.launchpad.backintime.InvalidCmd' + +class LimitExceeded(dbus.DBusException): + _dbus_error_name = 'net.launchpad.backintime.LimitExceeded' + class PermissionDeniedByPolicy(dbus.DBusException): _dbus_error_name = 'com.ubuntu.DeviceDriver.PermissionDeniedByPolicy' @@ -93,10 +99,61 @@ class UdevRules(dbus.service.Object): self.tmpDict = {} #find su path - proc = Popen(['which', 'su'], stdout = PIPE) - self.su = proc.communicate()[0].strip().decode() - if proc.returncode or not self.su: - self.su = '/bin/su' + self.su = self._which('su', '/bin/su') + self.backintime = self._which('backintime', '/usr/bin/backintime') + self.nice = self._which('nice', '/usr/bin/nice') + self.ionice = self._which('ionice', '/usr/bin/ionice') + self.max_rules = 100 + self.max_users = 20 + self.max_cmd_len = 100 + + def _which(self, exe, fallback): + proc = Popen(['which', exe], stdout = PIPE) + ret = proc.communicate()[0].strip().decode() + if proc.returncode or not ret: + return fallback + + return ret + + def _validateCmd(self, cmd): + + if cmd.find("&&") != -1: + raise InvalidCmd("Parameter 'cmd' contains '&&' concatenation") + # make sure it starts with an absolute path + elif not cmd.startswith(os.path.sep): + raise InvalidCmd("Parameter 'cmd' does not start with '/'") + + parts = cmd.split() + + # make sure only well known commands and switches are used + whitelist = ( + (self.nice, ("-n")), + (self.ionice, ("-c", "-n")), + ) + + for c, switches in whitelist: + if parts and parts[0] == c: + parts.pop(0) + for sw in switches: + while parts and parts[0].startswith(sw): + parts.pop(0) + + if not parts: + raise InvalidCmd("Parameter 'cmd' does not contain the backintime command") + elif parts[0] != self.backintime: + raise InvalidCmd("Parameter 'cmd' contains non-whitelisted cmd/parameter (%s)" % parts[0]) + + def _checkLimits(self, owner, cmd): + + if len(self.tmpDict.get(owner, [])) >= self.max_rules: + raise LimitExceeded("Maximum number of cached rules reached (%d)" + % self.max_rules) + elif len(self.tmpDict) >= self.max_users: + raise LimitExceeded("Maximum number of cached users reached (%d)" + % self.max_users) + elif len(cmd) > self.max_cmd_len: + raise LimitExceeded("Maximum length of command line reached (%d)" + % self.max_cmd_len) @dbus.service.method("net.launchpad.backintime.serviceHelper.UdevRules", in_signature='ss', out_signature='', @@ -117,10 +174,14 @@ class UdevRules(dbus.service.Object): raise InvalidChar("Parameter 'uuid' contains invalid character(s) %s" % '|'.join(set(chars)) ) + self._validateCmd(cmd) + info = SenderInfo(sender, conn) user = info.connectionUnixUser() owner = info.nameOwner() + self._checkLimits(owner, cmd) + #create su command sucmd = "%s - '%s' -c '%s'" %(self.su, user, cmd) #create Udev rule
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor