diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-03-19 01:58:14 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-19 01:58:14 (GMT) |
commit | faddaedd05ca81a9fed3f315e7bc8dcf455824a2 (patch) | |
tree | 90679ab39bba190bd5cfa055ae3f564255d29495 /Modules | |
parent | 5f9cf23502febe0eb3bc02e45c7d2bfc79424757 (diff) | |
download | cpython-faddaedd05ca81a9fed3f315e7bc8dcf455824a2.zip cpython-faddaedd05ca81a9fed3f315e7bc8dcf455824a2.tar.gz cpython-faddaedd05ca81a9fed3f315e7bc8dcf455824a2.tar.bz2 |
bpo-36352: Avoid hardcoded MAXPATHLEN size in getpath.c (GH-12423)
* Use Py_ARRAY_LENGTH() rather than hardcoded MAXPATHLEN in getpath.c.
* Pass string length to functions modifying strings.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/getpath.c | 384 |
1 files changed, 234 insertions, 150 deletions
diff --git a/Modules/getpath.c b/Modules/getpath.c index 4364317..dd188c6 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -159,14 +159,16 @@ static void reduce(wchar_t *dir) { size_t i = wcslen(dir); - while (i > 0 && dir[i] != SEP) + while (i > 0 && dir[i] != SEP) { --i; + } dir[i] = '\0'; } +/* Is file, not directory */ static int -isfile(wchar_t *filename) /* Is file, not directory */ +isfile(const wchar_t *filename) { struct stat buf; if (_Py_wstat(filename, &buf) != 0) { @@ -179,15 +181,16 @@ isfile(wchar_t *filename) /* Is file, not directory */ } +/* Is module -- check for .pyc too */ static int -ismodule(wchar_t *filename) /* Is module -- check for .pyc too */ +ismodule(wchar_t *filename, size_t filename_len) { if (isfile(filename)) { return 1; } /* Check for the compiled version of prefix. */ - if (wcslen(filename) < MAXPATHLEN) { + if (wcslen(filename) + 2 <= filename_len) { wcscat(filename, L"c"); if (isfile(filename)) { return 1; @@ -199,7 +202,7 @@ ismodule(wchar_t *filename) /* Is module -- check for .pyc too */ /* Is executable file */ static int -isxfile(wchar_t *filename) +isxfile(const wchar_t *filename) { struct stat buf; if (_Py_wstat(filename, &buf) != 0) { @@ -231,58 +234,71 @@ isdir(wchar_t *filename) /* Add a path component, by appending stuff to buffer. - buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a - NUL-terminated string with no more than MAXPATHLEN characters (not counting - the trailing NUL). It's a fatal error if it contains a string longer than - that (callers must be careful!). If these requirements are met, it's - guaranteed that buffer will still be a NUL-terminated string with no more - than MAXPATHLEN characters at exit. If stuff is too long, only as much of - stuff as fits will be appended. -*/ + buflen: 'buffer' length in characters including trailing NUL. */ static _PyInitError -joinpath(wchar_t *buffer, wchar_t *stuff) +joinpath(wchar_t *buffer, const wchar_t *stuff, size_t buflen) { size_t n, k; - if (stuff[0] == SEP) { - n = 0; - } - else { + if (stuff[0] != SEP) { n = wcslen(buffer); - if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) { + if (n >= buflen) { + return PATHLEN_ERR(); + } + + if (n > 0 && buffer[n-1] != SEP) { buffer[n++] = SEP; } } - if (n > MAXPATHLEN) { - return PATHLEN_ERR(); + else { + n = 0; } + k = wcslen(stuff); - if (n + k > MAXPATHLEN) { - k = MAXPATHLEN - n; + if (n + k >= buflen) { + return PATHLEN_ERR(); } wcsncpy(buffer+n, stuff, k); buffer[n+k] = '\0'; + return _Py_INIT_OK(); } +static inline int +safe_wcscpy(wchar_t *dst, const wchar_t *src, size_t n) +{ + size_t srclen = wcslen(src); + if (n <= srclen) { + dst[0] = L'\0'; + return -1; + } + memcpy(dst, src, (srclen + 1) * sizeof(wchar_t)); + return 0; +} + + /* copy_absolute requires that path be allocated at least - MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */ + 'pathlen' characters (including trailing NUL). */ static _PyInitError -copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen) +copy_absolute(wchar_t *path, const wchar_t *p, size_t pathlen) { if (p[0] == SEP) { - wcscpy(path, p); + if (safe_wcscpy(path, p, pathlen) < 0) { + return PATHLEN_ERR(); + } } else { if (!_Py_wgetcwd(path, pathlen)) { /* unable to get the current directory */ - wcscpy(path, p); + if (safe_wcscpy(path, p, pathlen) < 0) { + return PATHLEN_ERR(); + } return _Py_INIT_OK(); } if (p[0] == '.' && p[1] == SEP) { p += 2; } - _PyInitError err = joinpath(path, p); + _PyInitError err = joinpath(path, p, pathlen); if (_Py_INIT_FAILED(err)) { return err; } @@ -291,56 +307,54 @@ copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen) } -/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */ +/* path_len: path length in characters including trailing NUL */ static _PyInitError -absolutize(wchar_t *path) +absolutize(wchar_t *path, size_t path_len) { - wchar_t buffer[MAXPATHLEN+1]; - if (path[0] == SEP) { return _Py_INIT_OK(); } - _PyInitError err = copy_absolute(buffer, path, MAXPATHLEN+1); + wchar_t abs_path[MAXPATHLEN+1]; + _PyInitError err = copy_absolute(abs_path, path, Py_ARRAY_LENGTH(abs_path)); if (_Py_INIT_FAILED(err)) { return err; } - wcscpy(path, buffer); + + if (safe_wcscpy(path, abs_path, path_len) < 0) { + return PATHLEN_ERR(); + } return _Py_INIT_OK(); } #if defined(__CYGWIN__) || defined(__MINGW32__) -/* add_exe_suffix requires that progpath be allocated at least - MAXPATHLEN + 1 bytes. -*/ - #ifndef EXE_SUFFIX #define EXE_SUFFIX L".exe" #endif +/* pathlen: 'path' length in characters including trailing NUL */ static _PyInitError -add_exe_suffix(wchar_t *progpath) +add_exe_suffix(wchar_t *progpath, size_t progpathlen) { /* Check for already have an executable suffix */ size_t n = wcslen(progpath); size_t s = wcslen(EXE_SUFFIX); - if (wcsncasecmp(EXE_SUFFIX, progpath+n-s, s) != 0) { - if (n + s > MAXPATHLEN) { - return PATHLEN_ERR(); - } - /* Save original path for revert */ - wchar_t orig[MAXPATHLEN+1]; - wcsncpy(orig, progpath, MAXPATHLEN); + if (wcsncasecmp(EXE_SUFFIX, progpath + n - s, s) == 0) { + return _Py_INIT_OK(); + } - wcsncpy(progpath+n, EXE_SUFFIX, s); - progpath[n+s] = '\0'; + if (n + s >= progpathlen) { + return PATHLEN_ERR(); + } + wcsncpy(progpath + n, EXE_SUFFIX, s); + progpath[n+s] = '\0'; - if (!isxfile(progpath)) { - /* Path that added suffix is invalid */ - wcsncpy(progpath, orig, MAXPATHLEN); - } + if (!isxfile(progpath)) { + /* Path that added suffix is invalid: truncate (remove suffix) */ + progpath[n] = '\0'; } + return _Py_INIT_OK(); } #endif @@ -350,8 +364,9 @@ add_exe_suffix(wchar_t *progpath) bytes long. */ static _PyInitError -search_for_prefix(const _PyCoreConfig *core_config, - PyCalculatePath *calculate, wchar_t *prefix, int *found) +search_for_prefix(const _PyCoreConfig *core_config, PyCalculatePath *calculate, + wchar_t *prefix, size_t prefix_len, + int *found) { _PyInitError err; size_t n; @@ -359,17 +374,18 @@ search_for_prefix(const _PyCoreConfig *core_config, /* If PYTHONHOME is set, we believe it unconditionally */ if (core_config->home) { - wcsncpy(prefix, core_config->home, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; + if (safe_wcscpy(prefix, core_config->home, prefix_len) < 0) { + return PATHLEN_ERR(); + } wchar_t *delim = wcschr(prefix, DELIM); if (delim) { *delim = L'\0'; } - err = joinpath(prefix, calculate->lib_python); + err = joinpath(prefix, calculate->lib_python, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(prefix, LANDMARK); + err = joinpath(prefix, LANDMARK, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -378,9 +394,10 @@ search_for_prefix(const _PyCoreConfig *core_config, } /* Check to see if argv[0] is in the build directory */ - wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - err = joinpath(prefix, L"Modules/Setup.local"); + if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(prefix, L"Modules/Setup.local", prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -389,24 +406,25 @@ search_for_prefix(const _PyCoreConfig *core_config, /* Check VPATH to see if argv0_path is in the build directory. */ vpath = Py_DecodeLocale(VPATH, NULL); if (vpath != NULL) { - wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - err = joinpath(prefix, vpath); + if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(prefix, vpath, prefix_len); PyMem_RawFree(vpath); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(prefix, L"Lib"); + err = joinpath(prefix, L"Lib", prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(prefix, LANDMARK); + err = joinpath(prefix, LANDMARK, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - if (ismodule(prefix)) { + if (ismodule(prefix, prefix_len)) { *found = -1; return _Py_INIT_OK(); } @@ -414,23 +432,23 @@ search_for_prefix(const _PyCoreConfig *core_config, } /* Search from argv0_path, until root is found */ - err = copy_absolute(prefix, calculate->argv0_path, MAXPATHLEN+1); + err = copy_absolute(prefix, calculate->argv0_path, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } do { n = wcslen(prefix); - err = joinpath(prefix, calculate->lib_python); + err = joinpath(prefix, calculate->lib_python, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(prefix, LANDMARK); + err = joinpath(prefix, LANDMARK, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - if (ismodule(prefix)) { + if (ismodule(prefix, prefix_len)) { *found = 1; return _Py_INIT_OK(); } @@ -439,18 +457,19 @@ search_for_prefix(const _PyCoreConfig *core_config, } while (prefix[0]); /* Look at configure's PREFIX */ - wcsncpy(prefix, calculate->prefix, MAXPATHLEN); - prefix[MAXPATHLEN] = L'\0'; - err = joinpath(prefix, calculate->lib_python); + if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(prefix, calculate->lib_python, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(prefix, LANDMARK); + err = joinpath(prefix, LANDMARK, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - if (ismodule(prefix)) { + if (ismodule(prefix, prefix_len)) { *found = 1; return _Py_INIT_OK(); } @@ -463,11 +482,12 @@ search_for_prefix(const _PyCoreConfig *core_config, static _PyInitError calculate_prefix(const _PyCoreConfig *core_config, - PyCalculatePath *calculate, wchar_t *prefix) + PyCalculatePath *calculate, wchar_t *prefix, size_t prefix_len) { _PyInitError err; - err = search_for_prefix(core_config, calculate, prefix, &calculate->prefix_found); + err = search_for_prefix(core_config, calculate, prefix, prefix_len, + &calculate->prefix_found); if (_Py_INIT_FAILED(err)) { return err; } @@ -477,8 +497,10 @@ calculate_prefix(const _PyCoreConfig *core_config, fprintf(stderr, "Could not find platform independent libraries <prefix>\n"); } - wcsncpy(prefix, calculate->prefix, MAXPATHLEN); - err = joinpath(prefix, calculate->lib_python); + if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(prefix, calculate->lib_python, prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -490,8 +512,9 @@ calculate_prefix(const _PyCoreConfig *core_config, } -static void -calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix) +static _PyInitError +calculate_reduce_prefix(PyCalculatePath *calculate, + wchar_t *prefix, size_t prefix_len) { /* Reduce prefix and exec_prefix to their essence, * e.g. /usr/local/lib/python1.5 is reduced to /usr/local. @@ -508,8 +531,11 @@ calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix) } } else { - wcsncpy(prefix, calculate->prefix, MAXPATHLEN); + if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) { + return PATHLEN_ERR(); + } } + return _Py_INIT_OK(); } @@ -518,7 +544,8 @@ calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix) */ static _PyInitError search_for_exec_prefix(const _PyCoreConfig *core_config, - PyCalculatePath *calculate, wchar_t *exec_prefix, + PyCalculatePath *calculate, + wchar_t *exec_prefix, size_t exec_prefix_len, int *found) { _PyInitError err; @@ -528,17 +555,20 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, if (core_config->home) { wchar_t *delim = wcschr(core_config->home, DELIM); if (delim) { - wcsncpy(exec_prefix, delim+1, MAXPATHLEN); + if (safe_wcscpy(exec_prefix, delim+1, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } } else { - wcsncpy(exec_prefix, core_config->home, MAXPATHLEN); + if (safe_wcscpy(exec_prefix, core_config->home, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } } - exec_prefix[MAXPATHLEN] = L'\0'; - err = joinpath(exec_prefix, calculate->lib_python); + err = joinpath(exec_prefix, calculate->lib_python, exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(exec_prefix, L"lib-dynload"); + err = joinpath(exec_prefix, L"lib-dynload", exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -549,9 +579,10 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, /* Check to see if argv[0] is in the build directory. "pybuilddir.txt" is written by setup.py and contains the relative path to the location of shared library modules. */ - wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - err = joinpath(exec_prefix, L"pybuilddir.txt"); + if (safe_wcscpy(exec_prefix, calculate->argv0_path, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(exec_prefix, L"pybuilddir.txt", exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -562,21 +593,22 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, errno = 0; } else { - char buf[MAXPATHLEN+1]; - n = fread(buf, 1, MAXPATHLEN, f); + char buf[MAXPATHLEN + 1]; + n = fread(buf, 1, Py_ARRAY_LENGTH(buf) - 1, f); buf[n] = '\0'; fclose(f); - size_t dec_len; wchar_t *pybuilddir; + size_t dec_len; pybuilddir = _Py_DecodeUTF8_surrogateescape(buf, n, &dec_len); if (!pybuilddir) { return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len); } - wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - err = joinpath(exec_prefix, pybuilddir); + if (safe_wcscpy(exec_prefix, calculate->argv0_path, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(exec_prefix, pybuilddir, exec_prefix_len); PyMem_RawFree(pybuilddir ); if (_Py_INIT_FAILED(err)) { return err; @@ -588,18 +620,18 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, } /* Search from argv0_path, until root is found */ - err = copy_absolute(exec_prefix, calculate->argv0_path, MAXPATHLEN+1); + err = copy_absolute(exec_prefix, calculate->argv0_path, exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } do { n = wcslen(exec_prefix); - err = joinpath(exec_prefix, calculate->lib_python); + err = joinpath(exec_prefix, calculate->lib_python, exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(exec_prefix, L"lib-dynload"); + err = joinpath(exec_prefix, L"lib-dynload", exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -612,13 +644,14 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, } while (exec_prefix[0]); /* Look at configure's EXEC_PREFIX */ - wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN); - exec_prefix[MAXPATHLEN] = L'\0'; - err = joinpath(exec_prefix, calculate->lib_python); + if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(exec_prefix, calculate->lib_python, exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } - err = joinpath(exec_prefix, L"lib-dynload"); + err = joinpath(exec_prefix, L"lib-dynload", exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -635,11 +668,13 @@ search_for_exec_prefix(const _PyCoreConfig *core_config, static _PyInitError calculate_exec_prefix(const _PyCoreConfig *core_config, - PyCalculatePath *calculate, wchar_t *exec_prefix) + PyCalculatePath *calculate, + wchar_t *exec_prefix, size_t exec_prefix_len) { _PyInitError err; - err = search_for_exec_prefix(core_config, calculate, exec_prefix, + err = search_for_exec_prefix(core_config, calculate, + exec_prefix, exec_prefix_len, &calculate->exec_prefix_found); if (_Py_INIT_FAILED(err)) { return err; @@ -650,8 +685,10 @@ calculate_exec_prefix(const _PyCoreConfig *core_config, fprintf(stderr, "Could not find platform dependent libraries <exec_prefix>\n"); } - wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN); - err = joinpath(exec_prefix, L"lib/lib-dynload"); + if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } + err = joinpath(exec_prefix, L"lib/lib-dynload", exec_prefix_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -661,8 +698,9 @@ calculate_exec_prefix(const _PyCoreConfig *core_config, } -static void -calculate_reduce_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix) +static _PyInitError +calculate_reduce_exec_prefix(PyCalculatePath *calculate, + wchar_t *exec_prefix, size_t exec_prefix_len) { if (calculate->exec_prefix_found > 0) { reduce(exec_prefix); @@ -673,8 +711,11 @@ calculate_reduce_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix) } } else { - wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN); + if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) { + return PATHLEN_ERR(); + } } + return _Py_INIT_OK(); } @@ -683,16 +724,17 @@ calculate_program_full_path(const _PyCoreConfig *core_config, PyCalculatePath *calculate, _PyPathConfig *config) { _PyInitError err; - wchar_t program_full_path[MAXPATHLEN+1]; + wchar_t program_full_path[MAXPATHLEN + 1]; + const size_t program_full_path_len = Py_ARRAY_LENGTH(program_full_path); memset(program_full_path, 0, sizeof(program_full_path)); #ifdef __APPLE__ + char execpath[MAXPATHLEN + 1]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - uint32_t nsexeclength = MAXPATHLEN; + uint32_t nsexeclength = Py_ARRAY_LENGTH(execpath) - 1; #else - unsigned long nsexeclength = MAXPATHLEN; + unsigned long nsexeclength = Py_ARRAY_LENGTH(execpath) - 1; #endif - char execpath[MAXPATHLEN+1]; #endif /* If there is no slash in the argv0 path, then we have to @@ -701,7 +743,10 @@ calculate_program_full_path(const _PyCoreConfig *core_config, * $PATH isn't exported, you lose. */ if (wcschr(core_config->program_name, SEP)) { - wcsncpy(program_full_path, core_config->program_name, MAXPATHLEN); + if (safe_wcscpy(program_full_path, core_config->program_name, + program_full_path_len) < 0) { + return PATHLEN_ERR(); + } } #ifdef __APPLE__ /* On Mac OS X, if a script uses an interpreter of the form @@ -722,7 +767,10 @@ calculate_program_full_path(const _PyCoreConfig *core_config, if (path == NULL) { return DECODE_LOCALE_ERR("executable path", len); } - wcsncpy(program_full_path, path, MAXPATHLEN); + if (safe_wcscpy(program_full_path, path, program_full_path_len) < 0) { + PyMem_RawFree(path); + return PATHLEN_ERR(); + } PyMem_RawFree(path); } #endif /* __APPLE__ */ @@ -733,17 +781,21 @@ calculate_program_full_path(const _PyCoreConfig *core_config, if (delim) { size_t len = delim - path; - if (len > MAXPATHLEN) { - len = MAXPATHLEN; + if (len >= program_full_path_len) { + return PATHLEN_ERR(); } wcsncpy(program_full_path, path, len); program_full_path[len] = '\0'; } else { - wcsncpy(program_full_path, path, MAXPATHLEN); + if (safe_wcscpy(program_full_path, path, + program_full_path_len) < 0) { + return PATHLEN_ERR(); + } } - err = joinpath(program_full_path, core_config->program_name); + err = joinpath(program_full_path, core_config->program_name, + program_full_path_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -763,7 +815,7 @@ calculate_program_full_path(const _PyCoreConfig *core_config, program_full_path[0] = '\0'; } if (program_full_path[0] != SEP && program_full_path[0] != '\0') { - err = absolutize(program_full_path); + err = absolutize(program_full_path, program_full_path_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -775,7 +827,7 @@ calculate_program_full_path(const _PyCoreConfig *core_config, * path (bpo-28441). */ if (program_full_path[0] != '\0') { - err = add_exe_suffix(program_full_path); + err = add_exe_suffix(program_full_path, program_full_path_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -793,8 +845,10 @@ calculate_program_full_path(const _PyCoreConfig *core_config, static _PyInitError calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_path) { - wcsncpy(calculate->argv0_path, program_full_path, MAXPATHLEN); - calculate->argv0_path[MAXPATHLEN] = '\0'; + const size_t argv0_path_len = Py_ARRAY_LENGTH(calculate->argv0_path); + if (safe_wcscpy(calculate->argv0_path, program_full_path, argv0_path_len) < 0) { + return PATHLEN_ERR(); + } #ifdef WITH_NEXT_FRAMEWORK NSModule pythonModule; @@ -823,50 +877,61 @@ calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_pat return DECODE_LOCALE_ERR("framework location", len); } - wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); + if (safe_wcscpy(calculate->argv0_path, wbuf, argv0_path_len) < 0) { + return PATHLEN_ERR(); + } reduce(calculate->argv0_path); - err = joinpath(calculate->argv0_path, calculate->lib_python); + err = joinpath(calculate->argv0_path, calculate->lib_python, argv0_path_len); if (_Py_INIT_FAILED(err)) { PyMem_RawFree(wbuf); return err; } - err = joinpath(calculate->argv0_path, LANDMARK); + err = joinpath(calculate->argv0_path, LANDMARK, argv0_path_len); if (_Py_INIT_FAILED(err)) { PyMem_RawFree(wbuf); return err; } - if (!ismodule(calculate->argv0_path)) { + if (!ismodule(calculate->argv0_path, + Py_ARRAY_LENGTH(calculate->argv0_path))) { /* We are in the build directory so use the name of the executable - we know that the absolute path is passed */ - wcsncpy(calculate->argv0_path, program_full_path, MAXPATHLEN); + if (safe_wcscpy(calculate->argv0_path, program_full_path, + argv0_path_len) < 0) { + return PATHLEN_ERR(); + } } else { /* Use the location of the library as the program_full_path */ - wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); + if (safe_wcscpy(calculate->argv0_path, wbuf, argv0_path_len) < 0) { + return PATHLEN_ERR(); + } } PyMem_RawFree(wbuf); } #endif #if HAVE_READLINK - wchar_t tmpbuffer[MAXPATHLEN+1]; - int linklen = _Py_wreadlink(program_full_path, tmpbuffer, MAXPATHLEN); + wchar_t tmpbuffer[MAXPATHLEN + 1]; + const size_t buflen = Py_ARRAY_LENGTH(tmpbuffer); + int linklen = _Py_wreadlink(program_full_path, tmpbuffer, buflen); while (linklen != -1) { if (tmpbuffer[0] == SEP) { /* tmpbuffer should never be longer than MAXPATHLEN, but extra check does not hurt */ - wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN); + if (safe_wcscpy(calculate->argv0_path, tmpbuffer, argv0_path_len) < 0) { + return PATHLEN_ERR(); + } } else { /* Interpret relative to program_full_path */ _PyInitError err; reduce(calculate->argv0_path); - err = joinpath(calculate->argv0_path, tmpbuffer); + err = joinpath(calculate->argv0_path, tmpbuffer, argv0_path_len); if (_Py_INIT_FAILED(err)) { return err; } } - linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, MAXPATHLEN); + linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, buflen); } #endif /* HAVE_READLINK */ @@ -886,12 +951,15 @@ calculate_read_pyenv(PyCalculatePath *calculate) { _PyInitError err; wchar_t tmpbuffer[MAXPATHLEN+1]; + const size_t buflen = Py_ARRAY_LENGTH(tmpbuffer); wchar_t *env_cfg = L"pyvenv.cfg"; FILE *env_file; - wcscpy(tmpbuffer, calculate->argv0_path); + if (safe_wcscpy(tmpbuffer, calculate->argv0_path, buflen) < 0) { + return PATHLEN_ERR(); + } - err = joinpath(tmpbuffer, env_cfg); + err = joinpath(tmpbuffer, env_cfg, buflen); if (_Py_INIT_FAILED(err)) { return err; } @@ -901,7 +969,7 @@ calculate_read_pyenv(PyCalculatePath *calculate) reduce(tmpbuffer); reduce(tmpbuffer); - err = joinpath(tmpbuffer, env_cfg); + err = joinpath(tmpbuffer, env_cfg, buflen); if (_Py_INIT_FAILED(err)) { return err; } @@ -917,8 +985,11 @@ calculate_read_pyenv(PyCalculatePath *calculate) } /* Look for a 'home' variable and set argv0_path to it, if found */ - if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, MAXPATHLEN)) { - wcscpy(calculate->argv0_path, tmpbuffer); + if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, buflen)) { + if (safe_wcscpy(calculate->argv0_path, tmpbuffer, + Py_ARRAY_LENGTH(calculate->argv0_path)) < 0) { + return PATHLEN_ERR(); + } } fclose(env_file); return _Py_INIT_OK(); @@ -929,8 +1000,10 @@ static _PyInitError calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix) { _PyInitError err; - wcsncpy(calculate->zip_path, prefix, MAXPATHLEN); - calculate->zip_path[MAXPATHLEN] = L'\0'; + const size_t zip_path_len = Py_ARRAY_LENGTH(calculate->zip_path); + if (safe_wcscpy(calculate->zip_path, prefix, zip_path_len) < 0) { + return PATHLEN_ERR(); + } if (calculate->prefix_found > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */ @@ -938,9 +1011,11 @@ calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix) reduce(calculate->zip_path); } else { - wcsncpy(calculate->zip_path, calculate->prefix, MAXPATHLEN); + if (safe_wcscpy(calculate->zip_path, calculate->prefix, zip_path_len) < 0) { + return PATHLEN_ERR(); + } } - err = joinpath(calculate->zip_path, L"lib/python00.zip"); + err = joinpath(calculate->zip_path, L"lib/python00.zip", zip_path_len); if (_Py_INIT_FAILED(err)) { return err; } @@ -1111,7 +1186,8 @@ calculate_path_impl(const _PyCoreConfig *core_config, wchar_t prefix[MAXPATHLEN+1]; memset(prefix, 0, sizeof(prefix)); - err = calculate_prefix(core_config, calculate, prefix); + err = calculate_prefix(core_config, calculate, + prefix, Py_ARRAY_LENGTH(prefix)); if (_Py_INIT_FAILED(err)) { return err; } @@ -1123,7 +1199,8 @@ calculate_path_impl(const _PyCoreConfig *core_config, wchar_t exec_prefix[MAXPATHLEN+1]; memset(exec_prefix, 0, sizeof(exec_prefix)); - err = calculate_exec_prefix(core_config, calculate, exec_prefix); + err = calculate_exec_prefix(core_config, calculate, + exec_prefix, Py_ARRAY_LENGTH(exec_prefix)); if (_Py_INIT_FAILED(err)) { return err; } @@ -1141,14 +1218,21 @@ calculate_path_impl(const _PyCoreConfig *core_config, return err; } - calculate_reduce_prefix(calculate, prefix); + err = calculate_reduce_prefix(calculate, prefix, Py_ARRAY_LENGTH(prefix)); + if (_Py_INIT_FAILED(err)) { + return err; + } config->prefix = _PyMem_RawWcsdup(prefix); if (config->prefix == NULL) { return _Py_INIT_NO_MEMORY(); } - calculate_reduce_exec_prefix(calculate, exec_prefix); + err = calculate_reduce_exec_prefix(calculate, + exec_prefix, Py_ARRAY_LENGTH(exec_prefix)); + if (_Py_INIT_FAILED(err)) { + return err; + } config->exec_prefix = _PyMem_RawWcsdup(exec_prefix); if (config->exec_prefix == NULL) { |