File CVE-2022-21699-unnecessary-privs.patch of Package python-ipython
From 1ec91ebf328bdf3450130de4b4604c79dc1e19d9 Mon Sep 17 00:00:00 2001
From: Matthias Bussonnier <bussonniermatthias@gmail.com>
Date: Sat, 15 Jan 2022 19:43:14 +0100
Subject: [PATCH 1/3] FIX CVE-2022-21699
See https://github.com/ipython/ipython/security/advisories/GHSA-pq7m-3gw7-gq5x
---
IPython/__init__.py | 4 +++
IPython/core/application.py | 2 -
IPython/core/profileapp.py | 7 +++--
IPython/core/profiledir.py | 4 +--
IPython/tests/cve.py | 56 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 67 insertions(+), 6 deletions(-)
--- a/IPython/__init__.py
+++ b/IPython/__init__.py
@@ -65,6 +65,10 @@ __author__ = '%s <%s>' % (release.author
__license__ = release.license
__version__ = release.version
version_info = release.version_info
+# list of CVEs that should have been patched in this release.
+# this is informational and should not be relied upon.
+__patched_cves__ = {"CVE-2022-21699"}
+
def embed_kernel(module=None, local_ns=None, **kwargs):
"""Embed and start an IPython kernel in a given scope.
--- a/IPython/core/application.py
+++ b/IPython/core/application.py
@@ -133,7 +133,7 @@ class BaseIPythonApplication(Application
config_file_paths = List(Unicode())
@default('config_file_paths')
def _config_file_paths_default(self):
- return [os.getcwd()]
+ return []
extra_config_file = Unicode(
help="""Path to an extra config file to load.
--- a/IPython/core/profileapp.py
+++ b/IPython/core/profileapp.py
@@ -181,9 +181,10 @@ class ProfileList(Application):
profiles = list_profiles_in(os.getcwd())
if profiles:
print()
- print("Available profiles in current directory (%s):" % os.getcwd())
- self._print_profiles(profiles)
-
+ print(
+ "Profiles from CWD have been removed for security reason, see CVE-2022-21699:"
+ )
+
print()
print("To use any of the above profiles, start IPython with:")
print(" ipython --profile=<name>")
--- a/IPython/core/profiledir.py
+++ b/IPython/core/profiledir.py
@@ -186,7 +186,7 @@ class ProfileDir(LoggingConfigurable):
is not found, a :class:`ProfileDirError` exception will be raised.
The search path algorithm is:
- 1. ``os.getcwd()``
+ 1. ``os.getcwd()`` # removed for security reason.
2. ``ipython_dir``
Parameters
@@ -198,7 +198,7 @@ class ProfileDir(LoggingConfigurable):
will be "profile_<profile>".
"""
dirname = u'profile_' + name
- paths = [os.getcwd(), ipython_dir]
+ paths = [ipython_dir]
for p in paths:
profile_dir = os.path.join(p, dirname)
if os.path.isdir(profile_dir):
--- /dev/null
+++ b/IPython/tests/cve.py
@@ -0,0 +1,56 @@
+"""
+Test that CVEs stay fixed.
+"""
+
+from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
+from pathlib import Path
+import random
+import sys
+import os
+import string
+import subprocess
+import time
+
+def test_cve_2022_21699():
+ """
+ Here we test CVE-2022-21699.
+
+ We create a temporary directory, cd into it.
+ Make a profile file that should not be executed and start IPython in a subprocess,
+ checking for the value.
+
+
+
+ """
+
+ dangerous_profile_dir = Path('profile_default')
+
+ dangerous_startup_dir = dangerous_profile_dir / 'startup'
+ dangerous_expected = 'CVE-2022-21699-'+''.join([random.choice(string.ascii_letters) for i in range(10)])
+
+ with TemporaryWorkingDirectory() as t:
+ dangerous_startup_dir.mkdir(parents=True)
+ (dangerous_startup_dir/ 'foo.py').write_text(f'print("{dangerous_expected}")')
+ # 1 sec to make sure FS is flushed.
+ #time.sleep(1)
+ cmd = [sys.executable,'-m', 'IPython']
+ env = os.environ.copy()
+ env['IPY_TEST_SIMPLE_PROMPT'] = '1'
+
+
+ # First we fake old behavior, making sure the profile is/was actually dangerous
+ p_dangerous = subprocess.Popen(cmd + [f'--profile-dir={dangerous_profile_dir}'], env=env, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out_dangerous, err_dangerouns = p_dangerous.communicate(b"exit\r")
+ assert dangerous_expected in out_dangerous.decode()
+
+ # Now that we know it _would_ have been dangerous, we test it's not loaded
+ p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate(b"exit\r")
+ assert b'IPython' in out
+ assert dangerous_expected not in out.decode()
+ assert err == b''
+
+
+