Skip to content

Commit

Permalink
backport patches for two security issues:
Browse files Browse the repository at this point in the history
commit f47e4856497231eb672da2ce0df3e641581d47e6
Author: Daniel A. Wozniak <[email protected]>
Date:   Mon Apr 13 06:41:04 2020 +0000

    Fix CVE-2020-11651

    Resolve issue which allows access to un-intended methods in the
    ClearFuncs class of the salt-master process

commit 7bd0ab195fbec4f34523dad11149f741c154e2b7
Author: Daniel A. Wozniak <[email protected]>
Date:   Mon Apr 13 06:44:58 2020 +0000

    Fix CVE-2020-11652

    Sanitize paths in ClearFuncs methods provided by salt-master. This
    ensures we do not allow access to un-intended files and directories.

ok sthen@, jasper@
  • Loading branch information
rnagy committed May 1, 2020
1 parent 0bb148d commit 63530a4
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 2 deletions.
4 changes: 2 additions & 2 deletions sysutils/salt/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.137 2020/04/18 09:22:32 ajacoutot Exp $
# $OpenBSD: Makefile,v 1.138 2020/05/01 08:01:08 robert Exp $

# optional dependencies
# https://github.com/saltstack/salt/blob/develop/doc/conf.py#L54
Expand All @@ -19,7 +19,7 @@ COMMENT = remote execution and configuration management system

MODPY_EGG_VERSION = 2018.3.3
DISTNAME = salt-${MODPY_EGG_VERSION}
REVISION = 1
REVISION = 2

CATEGORIES = sysutils net devel

Expand Down
110 changes: 110 additions & 0 deletions sysutils/salt/patches/patch-salt_master_py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
$OpenBSD: patch-salt_master_py,v 1.1 2020/05/01 08:01:08 robert Exp $

commit f47e4856497231eb672da2ce0df3e641581d47e6
Author: Daniel A. Wozniak <[email protected]>
Date: Mon Apr 13 06:41:04 2020 +0000

Fix CVE-2020-11651

Resolve issue which allows access to un-intended methods in the
ClearFuncs class of the salt-master process

Index: salt/master.py
--- salt/master.py.orig
+++ salt/master.py
@@ -1045,12 +1045,13 @@ class MWorker(salt.utils.process.SignalHandlingMultipr
'''
log.trace('Clear payload received with command %s', load['cmd'])
cmd = load['cmd']
- if cmd.startswith('__'):
- return False
+ method = self.clear_funcs.get_method(cmd)
+ if not method:
+ return {}, {'fun': 'send_clear'}
if self.opts['master_stats']:
start = time.time()
self.stats[cmd]['runs'] += 1
- ret = getattr(self.clear_funcs, cmd)(load), {'fun': 'send_clear'}
+ ret = method(load), {'fun': 'send_clear'}
if self.opts['master_stats']:
self._post_stats(start, cmd)
return ret
@@ -1068,8 +1069,9 @@ class MWorker(salt.utils.process.SignalHandlingMultipr
return {}
cmd = data['cmd']
log.trace('AES payload received with command %s', data['cmd'])
- if cmd.startswith('__'):
- return False
+ method = self.aes_funcs.get_method(cmd)
+ if not method:
+ return {}, {'fun': 'send'}
if self.opts['master_stats']:
start = time.time()
self.stats[cmd]['runs'] += 1
@@ -1092,13 +1094,43 @@ class MWorker(salt.utils.process.SignalHandlingMultipr
self.__bind()


+class TransportMethods(object):
+ '''
+ Expose methods to the transport layer, methods with their names found in
+ the class attribute 'expose_methods' will be exposed to the transport layer
+ via 'get_method'.
+ '''
+
+ expose_methods = ()
+
+ def get_method(self, name):
+ '''
+ Get a method which should be exposed to the transport layer
+ '''
+ if name in self.expose_methods:
+ try:
+ return getattr(self, name)
+ except AttributeError:
+ log.error("Expose method not found: %s", name)
+ else:
+ log.error("Requested method not exposed: %s", name)
+
# TODO: rename? No longer tied to "AES", just "encrypted" or "private" requests
-class AESFuncs(object):
+class AESFuncs(TransportMethods):
'''
Set up functions that are available when the load is encrypted with AES
'''
- # The AES Functions:
- #
+
+ expose_methods = (
+ 'verify_minion', '_master_tops', '_ext_nodes', '_master_opts',
+ '_mine_get', '_mine', '_mine_delete', '_mine_flush', '_file_recv',
+ '_pillar', '_minion_event', '_handle_minion_event', '_return',
+ '_syndic_return', '_minion_runner', 'pub_ret', 'minion_pub',
+ 'minion_publish', 'revoke_auth', 'run_func', '_serve_file',
+ '_file_find', '_file_hash', '_file_find_and_stat', '_file_list',
+ '_file_list_emptydirs', '_dir_list', '_symlink_list', '_file_envs',
+ )
+
def __init__(self, opts):
'''
Create a new AESFuncs
@@ -1812,11 +1844,18 @@ class AESFuncs(object):
return ret, {'fun': 'send'}


-class ClearFuncs(object):
+class ClearFuncs(TransportMethods):
'''
Set up functions that are safe to execute when commands sent to the master
without encryption and authentication
'''
+
+ # These methods will be exposed to the transport layer by
+ # MWorker._handle_clear
+ expose_methods = (
+ 'ping', 'publish', 'get_token', 'mk_token', 'wheel', 'runner',
+ )
+
# The ClearFuncs object encapsulates the functions that can be executed in
# the clear:
# publish (The publish from the LocalClient)
31 changes: 31 additions & 0 deletions sysutils/salt/patches/patch-salt_tokens_localfs_py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
$OpenBSD: patch-salt_tokens_localfs_py,v 1.1 2020/05/01 08:01:08 robert Exp $

commit 7bd0ab195fbec4f34523dad11149f741c154e2b7
Author: Daniel A. Wozniak <[email protected]>
Date: Mon Apr 13 06:44:58 2020 +0000

Fix CVE-2020-11652

Sanitize paths in ClearFuncs methods provided by salt-master. This
ensures we do not allow access to un-intended files and directories.

Index: salt/tokens/localfs.py
--- salt/tokens/localfs.py.orig
+++ salt/tokens/localfs.py
@@ -12,6 +12,7 @@ import logging

import salt.utils.files
import salt.utils.path
+import salt.utils.verify
import salt.payload

from salt.ext import six
@@ -34,6 +35,8 @@ def mk_token(opts, tdata):
hash_type = getattr(hashlib, opts.get('hash_type', 'md5'))
tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
t_path = os.path.join(opts['token_dir'], tok)
+ if not salt.utils.verify.clean_path(opts['token_dir'], t_path):
+ return {}
while os.path.isfile(t_path):
tok = six.text_type(hash_type(os.urandom(512)).hexdigest())
t_path = os.path.join(opts['token_dir'], tok)
97 changes: 97 additions & 0 deletions sysutils/salt/patches/patch-salt_utils_verify_py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
$OpenBSD: patch-salt_utils_verify_py,v 1.1 2020/05/01 08:01:08 robert Exp $

commit 7bd0ab195fbec4f34523dad11149f741c154e2b7
Author: Daniel A. Wozniak <[email protected]>
Date: Mon Apr 13 06:44:58 2020 +0000

Fix CVE-2020-11652

Sanitize paths in ClearFuncs methods provided by salt-master. This
ensures we do not allow access to un-intended files and directories.

Index: salt/utils/verify.py
--- salt/utils/verify.py.orig
+++ salt/utils/verify.py
@@ -31,6 +31,7 @@ import salt.utils.files
import salt.utils.path
import salt.utils.platform
import salt.utils.user
+import salt.ext.six

log = logging.getLogger(__name__)

@@ -472,23 +473,69 @@ def check_max_open_files(opts):
log.log(level=level, msg=msg)


+def _realpath_darwin(path):
+ base = ''
+ for part in path.split(os.path.sep)[1:]:
+ if base != '':
+ if os.path.islink(os.path.sep.join([base, part])):
+ base = os.readlink(os.path.sep.join([base, part]))
+ else:
+ base = os.path.abspath(os.path.sep.join([base, part]))
+ else:
+ base = os.path.abspath(os.path.sep.join([base, part]))
+ return base
+
+
+def _realpath_windows(path):
+ base = ''
+ for part in path.split(os.path.sep):
+ if base != '':
+ try:
+ part = os.readlink(os.path.sep.join([base, part]))
+ base = os.path.abspath(part)
+ except OSError:
+ base = os.path.abspath(os.path.sep.join([base, part]))
+ else:
+ base = part
+ return base
+
+
+def _realpath(path):
+ '''
+ Cross platform realpath method. On Windows when python 3, this method
+ uses the os.readlink method to resolve any filesystem links. On Windows
+ when python 2, this method is a no-op. All other platforms and version use
+ os.realpath
+ '''
+ if salt.utils.platform.is_darwin():
+ return _realpath_darwin(path)
+ elif salt.utils.platform.is_windows():
+ if salt.ext.six.PY3:
+ return _realpath_windows(path)
+ else:
+ return path
+ return os.path.realpath(path)
+
+
def clean_path(root, path, subdir=False):
'''
Accepts the root the path needs to be under and verifies that the path is
under said root. Pass in subdir=True if the path can result in a
subdirectory of the root instead of having to reside directly in the root
'''
- if not os.path.isabs(root):
+ real_root = _realpath(root)
+ if not os.path.isabs(real_root):
return ''
if not os.path.isabs(path):
path = os.path.join(root, path)
path = os.path.normpath(path)
+ real_path = _realpath(path)
if subdir:
- if path.startswith(root):
- return path
+ if real_path.startswith(real_root):
+ return real_path
else:
- if os.path.dirname(path) == os.path.normpath(root):
- return path
+ if os.path.dirname(real_path) == os.path.normpath(real_root):
+ return real_path
return ''


35 changes: 35 additions & 0 deletions sysutils/salt/patches/patch-salt_wheel_config_py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
$OpenBSD: patch-salt_wheel_config_py,v 1.1 2020/05/01 08:01:08 robert Exp $

commit 7bd0ab195fbec4f34523dad11149f741c154e2b7
Author: Daniel A. Wozniak <[email protected]>
Date: Mon Apr 13 06:44:58 2020 +0000

Fix CVE-2020-11652

Sanitize paths in ClearFuncs methods provided by salt-master. This
ensures we do not allow access to un-intended files and directories.

Index: salt/wheel/config.py
--- salt/wheel/config.py.orig
+++ salt/wheel/config.py
@@ -75,13 +75,19 @@ def update_config(file_name, yaml_contents):
dir_path = os.path.join(__opts__['config_dir'],
os.path.dirname(__opts__['default_include']))
try:
- yaml_out = salt.utils.yaml.safe_dump(yaml_contents, default_flow_style=False)
+ yaml_out = salt.utils.yaml.safe_dump(
+ yaml_contents,
+ default_flow_style=False,
+ )

if not os.path.exists(dir_path):
log.debug('Creating directory %s', dir_path)
os.makedirs(dir_path, 0o755)

file_path = os.path.join(dir_path, file_name)
+ if not salt.utils.verify.clean_path(dir_path, file_path):
+ return 'Invalid path'
+
with salt.utils.files.fopen(file_path, 'w') as fp_:
fp_.write(yaml_out)

35 changes: 35 additions & 0 deletions sysutils/salt/patches/patch-salt_wheel_file_roots_py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
$OpenBSD: patch-salt_wheel_file_roots_py,v 1.1 2020/05/01 08:01:08 robert Exp $

commit 7bd0ab195fbec4f34523dad11149f741c154e2b7
Author: Daniel A. Wozniak <[email protected]>
Date: Mon Apr 13 06:44:58 2020 +0000

Fix CVE-2020-11652

Sanitize paths in ClearFuncs methods provided by salt-master. This
ensures we do not allow access to un-intended files and directories.

Index: salt/wheel/file_roots.py
--- salt/wheel/file_roots.py.orig
+++ salt/wheel/file_roots.py
@@ -25,6 +25,8 @@ def find(path, saltenv='base'):
return ret
for root in __opts__['file_roots'][saltenv]:
full = os.path.join(root, path)
+ if not salt.utils.verify.clean_path(root, full):
+ continue
if os.path.isfile(full):
# Add it to the dict
with salt.utils.files.fopen(full, 'rb') as fp_:
@@ -107,7 +109,10 @@ def write(data, path, saltenv='base', index=0):
if os.path.isabs(path):
return ('The path passed in {0} is not relative to the environment '
'{1}').format(path, saltenv)
- dest = os.path.join(__opts__['file_roots'][saltenv][index], path)
+ root = __opts__['file_roots'][saltenv][index]
+ dest = os.path.join(root, path)
+ if not salt.utils.verify.clean_path(root, dest, subdir=True):
+ return 'Invalid path: {}'.format(path)
dest_dir = os.path.dirname(dest)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)

0 comments on commit 63530a4

Please sign in to comment.