+72
-9
lines changedFilter options
+72
-9
lines changed Original file line number Diff line number Diff line change
@@ -1239,8 +1239,12 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
1239
1239
# and pass it to fork_exec()
1240
1240
1241
1241
if env is not None:
1242
-
env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
1243
-
for k, v in env.items()]
1242
+
env_list = []
1243
+
for k, v in env.items():
1244
+
k = os.fsencode(k)
1245
+
if b'=' in k:
1246
+
raise ValueError("illegal environment variable name")
1247
+
env_list.append(k + b'=' + os.fsencode(v))
1244
1248
else:
1245
1249
env_list = None # Use execv instead of execve.
1246
1250
executable = os.fsencode(executable)
Original file line number Diff line number Diff line change
@@ -644,6 +644,46 @@ def test_empty_env(self):
644
644
# environment
645
645
b"['__CF_USER_TEXT_ENCODING']"))
646
646
647
+
def test_invalid_cmd(self):
648
+
# null character in the command name
649
+
cmd = sys.executable + '\0'
650
+
with self.assertRaises(ValueError):
651
+
subprocess.Popen([cmd, "-c", "pass"])
652
+
653
+
# null character in the command argument
654
+
with self.assertRaises(ValueError):
655
+
subprocess.Popen([sys.executable, "-c", "pass#\0"])
656
+
657
+
def test_invalid_env(self):
658
+
# null character in the enviroment variable name
659
+
newenv = os.environ.copy()
660
+
newenv["FRUIT\0VEGETABLE"] = "cabbage"
661
+
with self.assertRaises(ValueError):
662
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
663
+
664
+
# null character in the enviroment variable value
665
+
newenv = os.environ.copy()
666
+
newenv["FRUIT"] = "orange\0VEGETABLE=cabbage"
667
+
with self.assertRaises(ValueError):
668
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
669
+
670
+
# equal character in the enviroment variable name
671
+
newenv = os.environ.copy()
672
+
newenv["FRUIT=ORANGE"] = "lemon"
673
+
with self.assertRaises(ValueError):
674
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
675
+
676
+
# equal character in the enviroment variable value
677
+
newenv = os.environ.copy()
678
+
newenv["FRUIT"] = "orange=lemon"
679
+
with subprocess.Popen([sys.executable, "-c",
680
+
'import sys, os;'
681
+
'sys.stdout.write(os.getenv("FRUIT"))'],
682
+
stdout=subprocess.PIPE,
683
+
env=newenv) as p:
684
+
stdout, stderr = p.communicate()
685
+
self.assertEqual(stdout, b"orange=lemon")
686
+
647
687
def test_communicate_stdin(self):
648
688
p = subprocess.Popen([sys.executable, "-c",
649
689
'import sys;'
Original file line number Diff line number Diff line change
@@ -13,6 +13,9 @@ Core and Builtins
13
13
Library
14
14
-------
15
15
16
+
- [Security] bpo-30730: Prevent environment variables injection in subprocess on
17
+
Windows. Prevent passing other environment variables and command arguments.
18
+
16
19
- [Security] bpo-30694: Upgrade expat copy from 2.2.0 to 2.2.1 to get fixes
17
20
of multiple security vulnerabilities including: CVE-2017-9233 (External
18
21
entity infinite loop DoS), CVE-2016-9063 (Integer overflow, re-fix),
Original file line number Diff line number Diff line change
@@ -744,6 +744,20 @@ getenvironment(PyObject* environment)
744
744
"environment can only contain strings");
745
745
goto error;
746
746
}
747
+
if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
748
+
PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
749
+
{
750
+
PyErr_SetString(PyExc_ValueError, "embedded null character");
751
+
goto error;
752
+
}
753
+
/* Search from index 1 because on Windows starting '=' is allowed for
754
+
defining hidden environment variables. */
755
+
if (PyUnicode_GET_LENGTH(key) == 0 ||
756
+
PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
757
+
{
758
+
PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
759
+
goto error;
760
+
}
747
761
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
748
762
PyErr_SetString(PyExc_OverflowError, "environment too long");
749
763
goto error;
@@ -830,7 +844,8 @@ _winapi_CreateProcess_impl(PyObject *module, Py_UNICODE *application_name,
830
844
PROCESS_INFORMATION pi;
831
845
STARTUPINFOW si;
832
846
PyObject* environment;
833
-
wchar_t *wenvironment;
847
+
const wchar_t *wenvironment;
848
+
Py_ssize_t wenvironment_size;
834
849
835
850
ZeroMemory(&si, sizeof(si));
836
851
si.cb = sizeof(si);
@@ -846,12 +861,13 @@ _winapi_CreateProcess_impl(PyObject *module, Py_UNICODE *application_name,
846
861
847
862
if (env_mapping != Py_None) {
848
863
environment = getenvironment(env_mapping);
849
-
if (! environment)
864
+
if (environment == NULL) {
850
865
return NULL;
866
+
}
867
+
/* contains embedded null characters */
851
868
wenvironment = PyUnicode_AsUnicode(environment);
852
-
if (wenvironment == NULL)
853
-
{
854
-
Py_XDECREF(environment);
869
+
if (wenvironment == NULL) {
870
+
Py_DECREF(environment);
855
871
return NULL;
856
872
}
857
873
}
Original file line number Diff line number Diff line change
@@ -3193,8 +3193,8 @@ _PySequence_BytesToCharpArray(PyObject* self)
3193
3193
array[i] = NULL;
3194
3194
goto fail;
3195
3195
}
3196
-
data = PyBytes_AsString(item);
3197
-
if (data == NULL) {
3196
+
/* check for embedded null bytes */
3197
+
if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) {
3198
3198
/* NULL terminate before freeing. */
3199
3199
array[i] = NULL;
3200
3200
goto fail;
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4