-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
backport patches for two security issues:
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
Showing
6 changed files
with
310 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 '' | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |