gh-57684: Add -P cmdline option and PYTHONSAFEPATH env var (#31542)

Add the -P command line option and the PYTHONSAFEPATH environment
variable to not prepend a potentially unsafe path to sys.path.

* Add sys.flags.safe_path flag.
* Add PyConfig.safe_path member.
* Programs/_bootstrap_python.c uses config.safe_path=0.
* Update subprocess._optim_args_from_interpreter_flags() to handle
  the -P command line option.
* Modules/getpath.py sets safe_path to 1 if a "._pth" file is
  present.
This commit is contained in:
Victor Stinner 2022-05-06 01:34:11 +02:00 committed by GitHub
parent f6dd14c653
commit ada8b6d1b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 174 additions and 35 deletions

View file

@ -3,7 +3,6 @@
#include "Python.h"
#include "pycore_fileutils.h" // _Py_add_relfile()
#include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#ifdef HAVE_DIRECT_H

View file

@ -41,7 +41,7 @@ static const wchar_t *opt_ptr = L"";
/* Python command line short and long options */
#define SHORT_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
#define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?"
static const _PyOS_LongOption longopts[] = {
{L"check-hash-based-pycs", 1, 0},

View file

@ -49,6 +49,7 @@ static const char usage_2[] = "\
.pyc extension; also PYTHONOPTIMIZE=x\n\
-OO : do -O changes and also discard docstrings; add .opt-2 before\n\
.pyc extension\n\
-P : don't add sys.path[0]\n\
-q : don't print version and copyright messages on interactive startup\n\
-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
-S : don't imply 'import site' on initialization\n\
@ -113,6 +114,7 @@ PYTHONPATH : '%lc'-separated list of directories prefixed to the\n\
default module search path. The result is sys.path.\n\
";
static const char usage_5[] =
"PYTHONSAFEPATH: don't prepend a potentially unsafe path to sys.path.\n"
"PYTHONHOME : alternate <prefix> directory (or <prefix>%lc<exec_prefix>).\n"
" The default module search path uses %s.\n"
"PYTHONPLATLIBDIR : override sys.platlibdir.\n"
@ -647,6 +649,10 @@ config_check_consistency(const PyConfig *config)
assert(config->check_hash_pycs_mode != NULL);
assert(config->_install_importlib >= 0);
assert(config->pathconfig_warnings >= 0);
assert(config->_is_python_build >= 0);
assert(config->safe_path >= 0);
// config->use_frozen_modules is initialized later
// by _PyConfig_InitImportConfig().
return 1;
}
#endif
@ -737,6 +743,7 @@ _PyConfig_InitCompatConfig(PyConfig *config)
#else
config->use_frozen_modules = 1;
#endif
config->safe_path = 0;
config->_is_python_build = 0;
config->code_debug_ranges = 1;
}
@ -792,6 +799,7 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
config->use_hash_seed = 0;
config->faulthandler = 0;
config->tracemalloc = 0;
config->safe_path = 1;
config->pathconfig_warnings = 0;
#ifdef MS_WINDOWS
config->legacy_windows_stdio = 0;
@ -959,6 +967,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
COPY_ATTR(_init_main);
COPY_ATTR(_isolated_interpreter);
COPY_ATTR(use_frozen_modules);
COPY_ATTR(safe_path);
COPY_WSTRLIST(orig_argv);
COPY_ATTR(_is_python_build);
@ -1065,6 +1074,7 @@ _PyConfig_AsDict(const PyConfig *config)
SET_ITEM_INT(_isolated_interpreter);
SET_ITEM_WSTRLIST(orig_argv);
SET_ITEM_INT(use_frozen_modules);
SET_ITEM_INT(safe_path);
SET_ITEM_INT(_is_python_build);
return dict;
@ -1350,6 +1360,7 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict)
GET_UINT(_init_main);
GET_UINT(_isolated_interpreter);
GET_UINT(use_frozen_modules);
GET_UINT(safe_path);
GET_UINT(_is_python_build);
#undef CHECK_VALUE
@ -1633,6 +1644,10 @@ config_read_env_vars(PyConfig *config)
}
}
if (config_get_env(config, "PYTHONSAFEPATH")) {
config->safe_path = 1;
}
return _PyStatus_OK();
}
@ -2000,6 +2015,7 @@ config_init_import(PyConfig *config, int compute_path_config)
"(expected \"on\" or \"off\")");
}
assert(config->use_frozen_modules >= 0);
return _PyStatus_OK();
}
@ -2327,6 +2343,10 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
config->optimization_level++;
break;
case 'P':
config->safe_path = 1;
break;
case 'B':
config->write_bytecode = 0;
break;
@ -2849,6 +2869,7 @@ _PyConfig_Read(PyConfig *config, int compute_path_config)
assert(config->isolated >= 0);
if (config->isolated) {
config->safe_path = 1;
config->use_environment = 0;
config->user_site_directory = 0;
}
@ -2994,6 +3015,7 @@ _Py_DumpPathConfig(PyThreadState *tstate)
PySys_WriteStderr(" isolated = %i\n", config->isolated);
PySys_WriteStderr(" environment = %i\n", config->use_environment);
PySys_WriteStderr(" user site = %i\n", config->user_site_directory);
PySys_WriteStderr(" safe_path = %i\n", config->safe_path);
PySys_WriteStderr(" import site = %i\n", config->site_import);
PySys_WriteStderr(" is in build tree = %i\n", config->_is_python_build);
DUMP_CONFIG("stdlib dir", stdlib_dir);

View file

@ -2479,6 +2479,7 @@ static PyStructSequence_Field flags_fields[] = {
{"dev_mode", "-X dev"},
{"utf8_mode", "-X utf8"},
{"warn_default_encoding", "-X warn_default_encoding"},
{"safe_path", "-P"},
{0}
};
@ -2486,7 +2487,7 @@ static PyStructSequence_Desc flags_desc = {
"sys.flags", /* name */
flags__doc__, /* doc */
flags_fields, /* fields */
16
17
};
static int
@ -2526,6 +2527,7 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags)
SetFlagObj(PyBool_FromLong(config->dev_mode));
SetFlag(preconfig->utf8_mode);
SetFlag(config->warn_default_encoding);
SetFlagObj(PyBool_FromLong(config->safe_path));
#undef SetFlagObj
#undef SetFlag
return 0;