This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Modules/getpath.c bugs
Type: behavior Stage: resolved
Components: Versions: Python 3.1, Python 3.2, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: hfuru, vstinner
Priority: normal Keywords: patch

Created on 2010-11-04 11:27 by hfuru, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
getpath.diff hfuru, 2010-11-04 11:27 getpath.c patches
Messages (7)
msg120390 - (view) Author: Hallvard B Furuseth (hfuru) Date: 2010-11-04 11:27
Patches for getpath.c in Python 2.7 and 3.2a3:

2.7 chunk#2: copy_absolute() would use uninitialized data if getcwd()
failed.  The fix is equivalent to what 3.2a3 does.

3.2a3 chunk#2: search_for_exec_prefix() did 'unsigned value >= 0' on the
PyUnicode_AsWideChar() result.  (The fix just renames n to k of signed
type, and moves the variables.  An outer uninitialized 'size_t n' is in
scope, so renaming the inner n to k leaves 'n=fread()' still a size_t.)

Chunk #1, both versions: Fix an unlikely 'n+k' wraparound bug while I'm
at it.  The code has just checked that MAXPATHLEN-n will not wrap.
msg120711 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2010-11-08 03:52
3.2a3 chunk#2 cannot fail because PyUnicode_AsWideChar() only returns -1 if the first argument is NULL, whereas we just checked that decoded is not NULL. But it would be better to fix the variable type to avoid future bugs.
msg120918 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2010-11-10 14:27
r86399 fixes the code checking PyUnicode_AsWideChar() failure.

The following change is useless, it cannot overflow:

-    if (n + k > MAXPATHLEN)
+    if (k > MAXPATHLEN - n)
         k = MAXPATHLEN - n;

n and k maximum values are MAXPATHLEN (and the maximum value of MAXPATHLEN is 4096), whereas n and k type maximum values are at least 2^31.
msg120940 - (view) Author: Hallvard B Furuseth (hfuru) Date: 2010-11-11 08:50
STINNER Victor writes:
> The following change is useless, it cannot overflow:
> -    if (n + k > MAXPATHLEN)
> +    if (k > MAXPATHLEN - n)
>          k = MAXPATHLEN - n;
> 
> n and k maximum values are MAXPATHLEN (and the maximum value of
> MAXPATHLEN is 4096), (...)

OK.  I could only tell that for n, not for k.  But even so it would
certainly be an unlikely overflow.
msg241632 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2015-04-20 11:25
Reading msg120918 and msg120940 it looks as if work has been completed so this can be closed as fixed.
msg241688 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2015-04-20 21:48
> Reading msg120918 and msg120940 it looks as if work has been completed so this can be closed as fixed.

Attached patch contains more fixes.
msg336507 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-02-25 10:10
I reviewed getpath.diff:

diff -pru Python-2.7/Modules/getpath.c Python-2.7/Modules/getpath.c
--- Python-2.7/Modules/getpath.c
+++ Python-2.7/Modules/getpath.c
@@ -218,7 +218,7 @@ joinpath(char *buffer, char *stuff)
     if (n > MAXPATHLEN)
         Py_FatalError("buffer overflow in getpath.c's joinpath()");
     k = strlen(stuff);
-    if (n + k > MAXPATHLEN)
+    if (k > MAXPATHLEN - n)
         k = MAXPATHLEN - n;
     strncpy(buffer+n, stuff, k);
     buffer[n+k] = '\0';

As I explained in a previous comment, this change is useless: "n+k" cannot overflow.


@@ -229,10 +229,9 @@ joinpath(char *buffer, char *stuff)
 static void
 copy_absolute(char *path, char *p)
 {
-    if (p[0] == SEP)
+    if (p[0] == SEP || getcwd(path, MAXPATHLEN) == NULL)
         strcpy(path, p);
     else {
-        getcwd(path, MAXPATHLEN);
         if (p[0] == '.' && p[1] == SEP)
             p += 2;
         joinpath(path, p);

The code changed in the meanwhile (in the master branch, in 3.7 maybe, I don't recall), getcwd() error is now checked in copy_absolute():

        if (!_Py_wgetcwd(path, pathlen)) {
            /* unable to get the current directory */
            wcscpy(path, p);
            return;
        }

diff -pru Python-3.2a3/Modules/getpath.c Python-3.2a3/Modules/getpath.c
--- Python-3.2a3/Modules/getpath.c
+++ Python-3.2a3/Modules/getpath.c
@@ -351,18 +351,18 @@ search_for_exec_prefix(wchar_t *argv0_pa
         else {
             char buf[MAXPATHLEN+1];
             PyObject *decoded;
-            wchar_t rel_builddir_path[MAXPATHLEN+1];
-            size_t n;
             n = fread(buf, 1, MAXPATHLEN, f);
             buf[n] = '\0';
             fclose(f);
             decoded = PyUnicode_DecodeUTF8(buf, n, "surrogateescape");
             if (decoded != NULL) {
-                n = PyUnicode_AsWideChar((PyUnicodeObject*)decoded,
+                wchar_t rel_builddir_path[MAXPATHLEN+1];
+                Py_ssize_t k;
+                k = PyUnicode_AsWideChar((PyUnicodeObject*)decoded,
                                          rel_builddir_path, MAXPATHLEN);
                 Py_DECREF(decoded);
-                if (n >= 0) {
-                    rel_builddir_path[n] = L'\0';
+                if (k >= 0) {
+                    rel_builddir_path[k] = L'\0';
                     wcscpy(exec_prefix, argv0_path);
                     joinpath(exec_prefix, rel_builddir_path);
                     return -1;

Again, the code changed in the meanwhile:

            wchar_t *rel_builddir_path;
            ...
            rel_builddir_path = _Py_DecodeUTF8_surrogateescape(buf, n);
            if (rel_builddir_path) {

There is a new _Py_DecodeUTF8_surrogateescape() function which returns directly wchar_t* strings.

I close the issue.

--

Modules/getpath.c should be rewritten without global MAXPATHLEN limit. I rewrote the code to avoid global variables and pass buffer lengths in some functions. It's better but not perfect yet :-))
History
Date User Action Args
2022-04-11 14:57:08adminsetgithub: 54517
2019-02-25 10:10:23vstinnersetstatus: open -> closed
resolution: fixed
messages: + msg336507

stage: resolved
2019-02-24 23:02:42BreamoreBoysetnosy: - BreamoreBoy
2015-04-20 21:48:22vstinnersetmessages: + msg241688
2015-04-20 11:25:26BreamoreBoysetnosy: + BreamoreBoy
messages: + msg241632
2010-11-11 08:50:32hfurusetmessages: + msg120940
2010-11-10 14:27:36vstinnersetmessages: + msg120918
2010-11-08 03:52:47vstinnersetmessages: + msg120711
2010-11-04 13:14:44hfurusetversions: + Python 3.1, Python 2.7
2010-11-04 11:54:41vstinnersetnosy: + vstinner
2010-11-04 11:27:41hfurucreate