| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ad1fb81 commit fe82c46
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1375,8 +1375,12 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, | |||
| 1375 | 1375 | # and pass it to fork_exec() | |
| 1376 | 1376 | ||
| 1377 | 1377 | if env is not None: | |
| 1378 | - env_list = [os.fsencode(k) + b'=' + os.fsencode(v) | ||
| 1379 | - for k, v in env.items()] | ||
| 1378 | + env_list = [] | ||
| 1379 | + for k, v in env.items(): | ||
| 1380 | + k = os.fsencode(k) | ||
| 1381 | + if b'=' in k: | ||
| 1382 | + raise ValueError("illegal environment variable name") | ||
| 1383 | + env_list.append(k + b'=' + os.fsencode(v)) | ||
| 1380 | 1384 | else: | |
| 1381 | 1385 | env_list = None # Use execv instead of execve. | |
| 1382 | 1386 | executable = os.fsencode(executable) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -606,6 +606,46 @@ def test_empty_env(self): | |||
| 606 | 606 | # environment | |
| 607 | 607 | b"['__CF_USER_TEXT_ENCODING']")) | |
| 608 | 608 | ||
| 609 | + def test_invalid_cmd(self): | ||
| 610 | + # null character in the command name | ||
| 611 | + cmd = sys.executable + '\0' | ||
| 612 | + with self.assertRaises(ValueError): | ||
| 613 | + subprocess.Popen([cmd, "-c", "pass"]) | ||
| 614 | + | ||
| 615 | + # null character in the command argument | ||
| 616 | + with self.assertRaises(ValueError): | ||
| 617 | + subprocess.Popen([sys.executable, "-c", "pass#\0"]) | ||
| 618 | + | ||
| 619 | + def test_invalid_env(self): | ||
| 620 | + # null character in the enviroment variable name | ||
| 621 | + newenv = os.environ.copy() | ||
| 622 | + newenv["FRUIT\0VEGETABLE"] = "cabbage" | ||
| 623 | + with self.assertRaises(ValueError): | ||
| 624 | + subprocess.Popen([sys.executable, "-c", "pass"], env=newenv) | ||
| 625 | + | ||
| 626 | + # null character in the enviroment variable value | ||
| 627 | + newenv = os.environ.copy() | ||
| 628 | + newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" | ||
| 629 | + with self.assertRaises(ValueError): | ||
| 630 | + subprocess.Popen([sys.executable, "-c", "pass"], env=newenv) | ||
| 631 | + | ||
| 632 | + # equal character in the enviroment variable name | ||
| 633 | + newenv = os.environ.copy() | ||
| 634 | + newenv["FRUIT=ORANGE"] = "lemon" | ||
| 635 | + with self.assertRaises(ValueError): | ||
| 636 | + subprocess.Popen([sys.executable, "-c", "pass"], env=newenv) | ||
| 637 | + | ||
| 638 | + # equal character in the enviroment variable value | ||
| 639 | + newenv = os.environ.copy() | ||
| 640 | + newenv["FRUIT"] = "orange=lemon" | ||
| 641 | + with subprocess.Popen([sys.executable, "-c", | ||
| 642 | + 'import sys, os;' | ||
| 643 | + 'sys.stdout.write(os.getenv("FRUIT"))'], | ||
| 644 | + stdout=subprocess.PIPE, | ||
| 645 | + env=newenv) as p: | ||
| 646 | + stdout, stderr = p.communicate() | ||
| 647 | + self.assertEqual(stdout, b"orange=lemon") | ||
| 648 | + | ||
| 609 | 649 | def test_communicate_stdin(self): | |
| 610 | 650 | p = subprocess.Popen([sys.executable, "-c", | |
| 611 | 651 | 'import sys;' | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,9 +19,13 @@ Documentation | |||
| 19 | 19 | Library | |
| 20 | 20 | ------- | |
| 21 | 21 | ||
| 22 | + - [Security] bpo-30730: Prevent environment variables injection in subprocess on | ||
| 23 | + Windows. Prevent passing other invalid environment variables and command arguments. | ||
| 24 | + | ||
| 22 | 25 | - Issue #27850: Remove 3DES from ssl module's default cipher list to counter | |
| 23 | 26 | measure sweet32 attack (CVE-2016-2183). | |
| 24 | 27 | ||
| 28 | + | ||
| 25 | 29 | What's New in Python 3.4.6? | |
| 26 | 30 | =========================== | |
| 27 | 31 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -535,6 +535,20 @@ getenvironment(PyObject* environment) | |||
| 535 | 535 | "environment can only contain strings"); | |
| 536 | 536 | goto error; | |
| 537 | 537 | } | |
| 538 | + if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 || | ||
| 539 | + PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1) | ||
| 540 | + { | ||
| 541 | + PyErr_SetString(PyExc_ValueError, "embedded null character"); | ||
| 542 | + goto error; | ||
| 543 | + } | ||
| 544 | + /* Search from index 1 because on Windows starting '=' is allowed for | ||
| 545 | + defining hidden environment variables. */ | ||
| 546 | + if (PyUnicode_GET_LENGTH(key) == 0 || | ||
| 547 | + PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1) | ||
| 548 | + { | ||
| 549 | + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); | ||
| 550 | + goto error; | ||
| 551 | + } | ||
| 538 | 552 | if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) { | |
| 539 | 553 | PyErr_SetString(PyExc_OverflowError, "environment too long"); | |
| 540 | 554 | goto error; | |
@@ -643,12 +657,13 @@ winapi_CreateProcess(PyObject* self, PyObject* args) | |||
| 643 | 657 | ||
| 644 | 658 | if (env_mapping != Py_None) { | |
| 645 | 659 | environment = getenvironment(env_mapping); | |
| 646 | - if (! environment) | ||
| 660 | + if (environment == NULL) { | ||
| 647 | 661 | return NULL; | |
| 662 | + } | ||
| 663 | + /* contains embedded null characters */ | ||
| 648 | 664 | wenvironment = PyUnicode_AsUnicode(environment); | |
| 649 | - if (wenvironment == NULL) | ||
| 650 | - { | ||
| 651 | - Py_XDECREF(environment); | ||
| 665 | + if (wenvironment == NULL) { | ||
| 666 | + Py_DECREF(environment); | ||
| 652 | 667 | return NULL; | |
| 653 | 668 | } | |
| 654 | 669 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2714,8 +2714,8 @@ _PySequence_BytesToCharpArray(PyObject* self) | |||
| 2714 | 2714 | array[i] = NULL; | |
| 2715 | 2715 | goto fail; | |
| 2716 | 2716 | } | |
| 2717 | - data = PyBytes_AsString(item); | ||
| 2718 | - if (data == NULL) { | ||
| 2717 | + /* check for embedded null bytes */ | ||
| 2718 | + if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) { | ||
| 2719 | 2719 | /* NULL terminate before freeing. */ | |
| 2720 | 2720 | array[i] = NULL; | |
| 2721 | 2721 | goto fail; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments