+70
-8
lines changedFilter options
+70
-8
lines changed Original file line number Diff line number Diff line change
@@ -1363,8 +1363,12 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
1363
1363
# and pass it to fork_exec()
1364
1364
1365
1365
if env is not None:
1366
-
env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
1367
-
for k, v in env.items()]
1366
+
env_list = []
1367
+
for k, v in env.items():
1368
+
k = os.fsencode(k)
1369
+
if b'=' in k:
1370
+
raise ValueError("illegal environment variable name")
1371
+
env_list.append(k + b'=' + os.fsencode(v))
1368
1372
else:
1369
1373
env_list = None # Use execv instead of execve.
1370
1374
executable = os.fsencode(executable)
Original file line number Diff line number Diff line change
@@ -588,6 +588,46 @@ def test_empty_env(self):
588
588
# environment
589
589
b"['__CF_USER_TEXT_ENCODING']"))
590
590
591
+
def test_invalid_cmd(self):
592
+
# null character in the command name
593
+
cmd = sys.executable + '\0'
594
+
with self.assertRaises((ValueError, TypeError)):
595
+
subprocess.Popen([cmd, "-c", "pass"])
596
+
597
+
# null character in the command argument
598
+
with self.assertRaises((ValueError, TypeError)):
599
+
subprocess.Popen([sys.executable, "-c", "pass#\0"])
600
+
601
+
def test_invalid_env(self):
602
+
# null character in the enviroment variable name
603
+
newenv = os.environ.copy()
604
+
newenv["FRUIT\0VEGETABLE"] = "cabbage"
605
+
with self.assertRaises((ValueError, TypeError)):
606
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
607
+
608
+
# null character in the enviroment variable value
609
+
newenv = os.environ.copy()
610
+
newenv["FRUIT"] = "orange\0VEGETABLE=cabbage"
611
+
with self.assertRaises((ValueError, TypeError)):
612
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
613
+
614
+
# equal character in the enviroment variable name
615
+
newenv = os.environ.copy()
616
+
newenv["FRUIT=ORANGE"] = "lemon"
617
+
with self.assertRaises(ValueError):
618
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
619
+
620
+
# equal character in the enviroment variable value
621
+
newenv = os.environ.copy()
622
+
newenv["FRUIT"] = "orange=lemon"
623
+
with subprocess.Popen([sys.executable, "-c",
624
+
'import sys, os;'
625
+
'sys.stdout.write(os.getenv("FRUIT"))'],
626
+
stdout=subprocess.PIPE,
627
+
env=newenv) as p:
628
+
stdout, stderr = p.communicate()
629
+
self.assertEqual(stdout, b"orange=lemon")
630
+
591
631
def test_communicate_stdin(self):
592
632
p = subprocess.Popen([sys.executable, "-c",
593
633
'import sys;'
Original file line number Diff line number Diff line change
@@ -35,6 +35,9 @@ Core and Builtins
35
35
Library
36
36
-------
37
37
38
+
- [Security] bpo-30730: Prevent environment variables injection in subprocess on
39
+
Windows. Prevent passing other invalid environment variables and command arguments.
40
+
38
41
- [Security] bpo-30585: Fix TLS stripping vulnerability in smptlib,
39
42
CVE-2016-0772. Reported by Team Oststrom
40
43
Original file line number Diff line number Diff line change
@@ -513,6 +513,20 @@ getenvironment(PyObject* environment)
513
513
"environment can only contain strings");
514
514
goto error;
515
515
}
516
+
if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
517
+
PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
518
+
{
519
+
PyErr_SetString(PyExc_ValueError, "embedded null character");
520
+
goto error;
521
+
}
522
+
/* Search from index 1 because on Windows starting '=' is allowed for
523
+
defining hidden environment variables. */
524
+
if (PyUnicode_GET_LENGTH(key) == 0 ||
525
+
PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
526
+
{
527
+
PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
528
+
goto error;
529
+
}
516
530
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
517
531
PyErr_SetString(PyExc_OverflowError, "environment too long");
518
532
goto error;
@@ -621,12 +635,13 @@ winapi_CreateProcess(PyObject* self, PyObject* args)
621
635
622
636
if (env_mapping != Py_None) {
623
637
environment = getenvironment(env_mapping);
624
-
if (! environment)
638
+
if (environment == NULL) {
625
639
return NULL;
640
+
}
641
+
/* contains embedded null characters */
626
642
wenvironment = PyUnicode_AsUnicode(environment);
627
-
if (wenvironment == NULL)
628
-
{
629
-
Py_XDECREF(environment);
643
+
if (wenvironment == NULL) {
644
+
Py_DECREF(environment);
630
645
return NULL;
631
646
}
632
647
}
Original file line number Diff line number Diff line change
@@ -2682,8 +2682,8 @@ _PySequence_BytesToCharpArray(PyObject* self)
2682
2682
array[i] = NULL;
2683
2683
goto fail;
2684
2684
}
2685
-
data = PyBytes_AsString(item);
2686
-
if (data == NULL) {
2685
+
/* check for embedded null bytes */
2686
+
if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) {
2687
2687
/* NULL terminate before freeing. */
2688
2688
array[i] = NULL;
2689
2689
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