From 6766c14ed197fd283da22973e05511c89080c348 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Jun 2017 07:33:01 +0300 Subject: [PATCH 1/3] [3.5] bpo-30746: Prohibited the '=' character in environment variable names (GH-2382) in `os.putenv()` and `os.spawn*()`.. (cherry picked from commit 77703942c5997dff00c48f10df1b29b11645624c) --- Lib/test/test_os.py | 177 +++++++++++++++++++++++++++++++++++++++++ Lib/test/test_posix.py | 15 ++++ Misc/NEWS | 3 + Modules/posixmodule.c | 47 ++++++++++- 4 files changed, 240 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 5865783a43e9f2..a94df73eef6168 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2184,6 +2184,183 @@ def test_waitpid(self): self.assertEqual(status, (pid, 0)) +<<<<<<< HEAD +======= +class SpawnTests(unittest.TestCase): + def create_args(self, *, with_env=False, use_bytes=False): + self.exitcode = 17 + + filename = support.TESTFN + self.addCleanup(support.unlink, filename) + + if not with_env: + code = 'import sys; sys.exit(%s)' % self.exitcode + else: + self.env = dict(os.environ) + # create an unique key + self.key = str(uuid.uuid4()) + self.env[self.key] = self.key + # read the variable from os.environ to check that it exists + code = ('import sys, os; magic = os.environ[%r]; sys.exit(%s)' + % (self.key, self.exitcode)) + + with open(filename, "w") as fp: + fp.write(code) + + args = [sys.executable, filename] + if use_bytes: + args = [os.fsencode(a) for a in args] + self.env = {os.fsencode(k): os.fsencode(v) + for k, v in self.env.items()} + + return args + + @requires_os_func('spawnl') + def test_spawnl(self): + args = self.create_args() + exitcode = os.spawnl(os.P_WAIT, args[0], *args) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnle') + def test_spawnle(self): + args = self.create_args(with_env=True) + exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnlp') + def test_spawnlp(self): + args = self.create_args() + exitcode = os.spawnlp(os.P_WAIT, args[0], *args) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnlpe') + def test_spawnlpe(self): + args = self.create_args(with_env=True) + exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnv') + def test_spawnv(self): + args = self.create_args() + exitcode = os.spawnv(os.P_WAIT, args[0], args) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnve') + def test_spawnve(self): + args = self.create_args(with_env=True) + exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnvp') + def test_spawnvp(self): + args = self.create_args() + exitcode = os.spawnvp(os.P_WAIT, args[0], args) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnvpe') + def test_spawnvpe(self): + args = self.create_args(with_env=True) + exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnv') + def test_nowait(self): + args = self.create_args() + pid = os.spawnv(os.P_NOWAIT, args[0], args) + result = os.waitpid(pid, 0) + self.assertEqual(result[0], pid) + status = result[1] + if hasattr(os, 'WIFEXITED'): + self.assertTrue(os.WIFEXITED(status)) + self.assertEqual(os.WEXITSTATUS(status), self.exitcode) + else: + self.assertEqual(status, self.exitcode << 8) + + @requires_os_func('spawnve') + def test_spawnve_bytes(self): + # Test bytes handling in parse_arglist and parse_envlist (#28114) + args = self.create_args(with_env=True, use_bytes=True) + exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + self.assertEqual(exitcode, self.exitcode) + + @requires_os_func('spawnl') + def test_spawnl_noargs(self): + args = self.create_args() + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0]) + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0], '') + + @requires_os_func('spawnle') + def test_spawnle_noargs(self): + args = self.create_args() + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], {}) + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], '', {}) + + @requires_os_func('spawnv') + def test_spawnv_noargs(self): + args = self.create_args() + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ()) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], []) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ('',)) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ['']) + + @requires_os_func('spawnve') + def test_spawnve_noargs(self): + args = self.create_args() + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], (), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [], {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {}) + + @requires_os_func('spawnve') + def test_spawnve_invalid_env(self): + # null character in the enviroment variable name + args = [sys.executable, '-c', 'pass'] + newenv = os.environ.copy() + newenv["FRUIT\0VEGETABLE"] = "cabbage" + try: + exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + except ValueError: + pass + else: + self.assertEqual(exitcode, 127) + + # null character in the enviroment variable value + args = [sys.executable, '-c', 'pass'] + newenv = os.environ.copy() + newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" + try: + exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + except ValueError: + pass + else: + self.assertEqual(exitcode, 127) + + # equal character in the enviroment variable name + args = [sys.executable, '-c', 'pass'] + newenv = os.environ.copy() + newenv["FRUIT=ORANGE"] = "lemon" + try: + exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + except ValueError: + pass + else: + self.assertEqual(exitcode, 127) + + # equal character in the enviroment variable value + filename = support.TESTFN + self.addCleanup(support.unlink, filename) + with open(filename, "w") as fp: + fp.write('import sys, os\n' + 'if os.getenv("FRUIT") != "orange=lemon":\n' + ' raise AssertionError') + args = [sys.executable, filename] + newenv = os.environ.copy() + newenv["FRUIT"] = "orange=lemon" + exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + self.assertEqual(exitcode, 0) + + +>>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) # The introduction of this TestCase caused at least two different errors on # *nix buildbots. Temporarily skip this to let the buildbots move along. @unittest.skip("Skip due to platform/environment differences on *NIX buildbots") diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 2a59c381749c80..57f793d1054d10 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -747,6 +747,21 @@ def test_environ(self): self.assertEqual(type(k), item_type) self.assertEqual(type(v), item_type) + @unittest.skipUnless(hasattr(os, "putenv"), "requires os.putenv()") + def test_putenv(self): + with self.assertRaises(ValueError): + os.putenv('FRUIT\0VEGETABLE', 'cabbage') + with self.assertRaises(ValueError): + os.putenv(b'FRUIT\0VEGETABLE', b'cabbage') + with self.assertRaises(ValueError): + os.putenv('FRUIT', 'orange\0VEGETABLE=cabbage') + with self.assertRaises(ValueError): + os.putenv(b'FRUIT', b'orange\0VEGETABLE=cabbage') + with self.assertRaises(ValueError): + os.putenv('FRUIT=ORANGE', 'lemon') + with self.assertRaises(ValueError): + os.putenv(b'FRUIT=ORANGE', b'lemon') + @unittest.skipUnless(hasattr(posix, 'getcwd'), 'test needs posix.getcwd()') def test_getcwd_long_pathnames(self): dirname = 'getcwd-test-directory-0123456789abcdef-01234567890abcdef' diff --git a/Misc/NEWS b/Misc/NEWS index b731792cde6206..4a8137f55f65ea 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Extension Modules Library ------- +- bpo-30746: Prohibited the '=' character in environment variable names in + ``os.putenv()`` and ``os.spawn*()``. + - [Security] bpo-30730: Prevent environment variables injection in subprocess on Windows. Prevent passing other environment variables and command arguments. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 9dd26f51ed33de..1d1d057d5bef65 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4963,6 +4963,7 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr) Py_DECREF(key2); goto error; } +<<<<<<< HEAD k = PyBytes_AsString(key2); v = PyBytes_AsString(val2); @@ -4971,12 +4972,39 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr) p = PyMem_NEW(char, len); if (p == NULL) { PyErr_NoMemory(); +======= + /* Search from index 1 because on Windows starting '=' is allowed for + defining hidden environment variables. */ + if (PyUnicode_GET_LENGTH(key2) == 0 || + PyUnicode_FindChar(key2, '=', 1, PyUnicode_GET_LENGTH(key2), 1) != -1) + { + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); + goto error; + } + keyval = PyUnicode_FromFormat("%U=%U", key2, val2); +#else + if (!PyUnicode_FSConverter(key, &key2)) + goto error; + if (!PyUnicode_FSConverter(val, &val2)) { +>>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) Py_DECREF(key2); Py_DECREF(val2); goto error; } +<<<<<<< HEAD PyOS_snprintf(p, len, "%s=%s", k, v); envlist[envc++] = p; +======= + if (PyBytes_GET_SIZE(key2) == 0 || + strchr(PyBytes_AS_STRING(key2) + 1, '=') != NULL) + { + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); + goto error; + } + keyval = PyBytes_FromFormat("%s=%s", PyBytes_AS_STRING(key2), + PyBytes_AS_STRING(val2)); +#endif +>>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) Py_DECREF(key2); Py_DECREF(val2); } @@ -9069,9 +9097,16 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) { wchar_t *env; + /* Search from index 1 because on Windows starting '=' is allowed for + defining hidden environment variables. */ + if (PyUnicode_GET_LENGTH(name) == 0 || + PyUnicode_FindChar(name, '=', 1, PyUnicode_GET_LENGTH(name), 1) != -1) + { + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); + return NULL; + } PyObject *unicode = PyUnicode_FromFormat("%U=%U", name, value); if (unicode == NULL) { - PyErr_NoMemory(); return NULL; } if (_MAX_ENV < PyUnicode_GET_LENGTH(unicode)) { @@ -9113,12 +9148,20 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) { PyObject *bytes = NULL; char *env; +<<<<<<< HEAD char *name_string = PyBytes_AsString(name); char *value_string = PyBytes_AsString(value); +======= + const char *name_string = PyBytes_AS_STRING(name); + const char *value_string = PyBytes_AS_STRING(value); +>>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) + if (strchr(name_string, '=') != NULL) { + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); + return NULL; + } bytes = PyBytes_FromFormat("%s=%s", name_string, value_string); if (bytes == NULL) { - PyErr_NoMemory(); return NULL; } From 02b7a85468fb8b546a43be07abbd005e00143646 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Jun 2017 08:57:43 +0300 Subject: [PATCH 2/3] Add more tests for os.spawnvpe() and os.execve(). --- Lib/test/test_os.py | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index a94df73eef6168..5c7b7e27e24078 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1501,6 +1501,27 @@ def test_internal_execvpe_str(self): if os.name != "nt": self._test_internal_execvpe(bytes) + def test_execve_invalid_env(self): + args = [sys.executable, '-c', 'pass'] + + # null character in the enviroment variable name + newenv = os.environ.copy() + newenv["FRUIT\0VEGETABLE"] = "cabbage" + with self.assertRaises(ValueError): + os.execve(args[0], args, newenv) + + # null character in the enviroment variable value + newenv = os.environ.copy() + newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" + with self.assertRaises(ValueError): + os.execve(args[0], args, newenv) + + # equal character in the enviroment variable name + newenv = os.environ.copy() + newenv["FRUIT=ORANGE"] = "lemon" + with self.assertRaises(ValueError): + os.execve(args[0], args, newenv) + @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") class Win32ErrorTests(unittest.TestCase): @@ -2311,36 +2332,34 @@ def test_spawnve_noargs(self): self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {}) self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {}) - @requires_os_func('spawnve') - def test_spawnve_invalid_env(self): - # null character in the enviroment variable name + def _test_invalid_env(self, spawn): args = [sys.executable, '-c', 'pass'] + + # null character in the enviroment variable name newenv = os.environ.copy() newenv["FRUIT\0VEGETABLE"] = "cabbage" try: - exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, args[0], args, newenv) except ValueError: pass else: self.assertEqual(exitcode, 127) # null character in the enviroment variable value - args = [sys.executable, '-c', 'pass'] newenv = os.environ.copy() newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" try: - exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, args[0], args, newenv) except ValueError: pass else: self.assertEqual(exitcode, 127) # equal character in the enviroment variable name - args = [sys.executable, '-c', 'pass'] newenv = os.environ.copy() newenv["FRUIT=ORANGE"] = "lemon" try: - exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, args[0], args, newenv) except ValueError: pass else: @@ -2356,9 +2375,17 @@ def test_spawnve_invalid_env(self): args = [sys.executable, filename] newenv = os.environ.copy() newenv["FRUIT"] = "orange=lemon" - exitcode = os.spawnve(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, args[0], args, newenv) self.assertEqual(exitcode, 0) + @requires_os_func('spawnve') + def test_spawnve_invalid_env(self): + self._test_invalid_env(os.spawnve) + + @requires_os_func('spawnvpe') + def test_spawnvpe_invalid_env(self): + self._test_invalid_env(os.spawnvpe) + >>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) # The introduction of this TestCase caused at least two different errors on From 48cc00fe38fe5fdfcdcb71cc9495d340b7fd1ebd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Jun 2017 09:26:24 +0300 Subject: [PATCH 3/3] Fix merge errors. --- Lib/test/test_os.py | 131 +----------------------------------------- Modules/posixmodule.c | 43 +++----------- 2 files changed, 10 insertions(+), 164 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 5c7b7e27e24078..e9c850793a5d9b 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2205,133 +2205,7 @@ def test_waitpid(self): self.assertEqual(status, (pid, 0)) -<<<<<<< HEAD -======= class SpawnTests(unittest.TestCase): - def create_args(self, *, with_env=False, use_bytes=False): - self.exitcode = 17 - - filename = support.TESTFN - self.addCleanup(support.unlink, filename) - - if not with_env: - code = 'import sys; sys.exit(%s)' % self.exitcode - else: - self.env = dict(os.environ) - # create an unique key - self.key = str(uuid.uuid4()) - self.env[self.key] = self.key - # read the variable from os.environ to check that it exists - code = ('import sys, os; magic = os.environ[%r]; sys.exit(%s)' - % (self.key, self.exitcode)) - - with open(filename, "w") as fp: - fp.write(code) - - args = [sys.executable, filename] - if use_bytes: - args = [os.fsencode(a) for a in args] - self.env = {os.fsencode(k): os.fsencode(v) - for k, v in self.env.items()} - - return args - - @requires_os_func('spawnl') - def test_spawnl(self): - args = self.create_args() - exitcode = os.spawnl(os.P_WAIT, args[0], *args) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnle') - def test_spawnle(self): - args = self.create_args(with_env=True) - exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnlp') - def test_spawnlp(self): - args = self.create_args() - exitcode = os.spawnlp(os.P_WAIT, args[0], *args) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnlpe') - def test_spawnlpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnv') - def test_spawnv(self): - args = self.create_args() - exitcode = os.spawnv(os.P_WAIT, args[0], args) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnve') - def test_spawnve(self): - args = self.create_args(with_env=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnvp') - def test_spawnvp(self): - args = self.create_args() - exitcode = os.spawnvp(os.P_WAIT, args[0], args) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnvpe') - def test_spawnvpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnv') - def test_nowait(self): - args = self.create_args() - pid = os.spawnv(os.P_NOWAIT, args[0], args) - result = os.waitpid(pid, 0) - self.assertEqual(result[0], pid) - status = result[1] - if hasattr(os, 'WIFEXITED'): - self.assertTrue(os.WIFEXITED(status)) - self.assertEqual(os.WEXITSTATUS(status), self.exitcode) - else: - self.assertEqual(status, self.exitcode << 8) - - @requires_os_func('spawnve') - def test_spawnve_bytes(self): - # Test bytes handling in parse_arglist and parse_envlist (#28114) - args = self.create_args(with_env=True, use_bytes=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) - self.assertEqual(exitcode, self.exitcode) - - @requires_os_func('spawnl') - def test_spawnl_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0]) - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0], '') - - @requires_os_func('spawnle') - def test_spawnle_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], {}) - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], '', {}) - - @requires_os_func('spawnv') - def test_spawnv_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ()) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], []) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ('',)) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ['']) - - @requires_os_func('spawnve') - def test_spawnve_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], (), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [], {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {}) - def _test_invalid_env(self, spawn): args = [sys.executable, '-c', 'pass'] @@ -2378,16 +2252,15 @@ def _test_invalid_env(self, spawn): exitcode = spawn(os.P_WAIT, args[0], args, newenv) self.assertEqual(exitcode, 0) - @requires_os_func('spawnve') + @unittest.skipUnless(hasattr(os, 'spawnve'), "test needs os.spawnve") def test_spawnve_invalid_env(self): self._test_invalid_env(os.spawnve) - @requires_os_func('spawnvpe') + @unittest.skipUnless(hasattr(os, 'spawnvpe'), "test needs os.spawnvpe") def test_spawnvpe_invalid_env(self): self._test_invalid_env(os.spawnvpe) ->>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) # The introduction of this TestCase caused at least two different errors on # *nix buildbots. Temporarily skip this to let the buildbots move along. @unittest.skip("Skip due to platform/environment differences on *NIX buildbots") diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 1d1d057d5bef65..042deaca6f2bb5 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4963,48 +4963,26 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr) Py_DECREF(key2); goto error; } -<<<<<<< HEAD - k = PyBytes_AsString(key2); - v = PyBytes_AsString(val2); - len = PyBytes_GET_SIZE(key2) + PyBytes_GET_SIZE(val2) + 2; - - p = PyMem_NEW(char, len); - if (p == NULL) { - PyErr_NoMemory(); -======= + k = PyBytes_AS_STRING(key2); + v = PyBytes_AS_STRING(val2); /* Search from index 1 because on Windows starting '=' is allowed for defining hidden environment variables. */ - if (PyUnicode_GET_LENGTH(key2) == 0 || - PyUnicode_FindChar(key2, '=', 1, PyUnicode_GET_LENGTH(key2), 1) != -1) - { + if (*k == '\0' || strchr(k + 1, '=') != NULL) { PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); goto error; } - keyval = PyUnicode_FromFormat("%U=%U", key2, val2); -#else - if (!PyUnicode_FSConverter(key, &key2)) - goto error; - if (!PyUnicode_FSConverter(val, &val2)) { ->>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) + len = PyBytes_GET_SIZE(key2) + PyBytes_GET_SIZE(val2) + 2; + + p = PyMem_NEW(char, len); + if (p == NULL) { + PyErr_NoMemory(); Py_DECREF(key2); Py_DECREF(val2); goto error; } -<<<<<<< HEAD PyOS_snprintf(p, len, "%s=%s", k, v); envlist[envc++] = p; -======= - if (PyBytes_GET_SIZE(key2) == 0 || - strchr(PyBytes_AS_STRING(key2) + 1, '=') != NULL) - { - PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); - goto error; - } - keyval = PyBytes_FromFormat("%s=%s", PyBytes_AS_STRING(key2), - PyBytes_AS_STRING(val2)); -#endif ->>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) Py_DECREF(key2); Py_DECREF(val2); } @@ -9148,13 +9126,8 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value) { PyObject *bytes = NULL; char *env; -<<<<<<< HEAD - char *name_string = PyBytes_AsString(name); - char *value_string = PyBytes_AsString(value); -======= const char *name_string = PyBytes_AS_STRING(name); const char *value_string = PyBytes_AS_STRING(value); ->>>>>>> 77703942c5... bpo-30746: Prohibited the '=' character in environment variable names (#2382) if (strchr(name_string, '=') != NULL) { PyErr_SetString(PyExc_ValueError, "illegal environment variable name");