Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6372fe1

Browse files
committed
Fix buffer overflow vulnerabilities in calculate_path(). Code used
copied strings from environment variables and argv[0] into fixed-length buffers without checking their length. Reported by Stan Bubrouski; advice on fix from John Viega.
1 parent 23542dc commit 6372fe1

1 file changed

Lines changed: 41 additions & 16 deletions

File tree

Modules/getpath.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
*/
9999

100100
#ifndef VERSION
101-
#define VERSION "1.5"
101+
#define VERSION "2.0"
102102
#endif
103103

104104
#ifndef VPATH
@@ -122,7 +122,7 @@
122122
#ifndef LANDMARK
123123
#define LANDMARK "os.py"
124124
#endif
125-
125+
126126
static char prefix[MAXPATHLEN+1];
127127
static char exec_prefix[MAXPATHLEN+1];
128128
static char progpath[MAXPATHLEN+1];
@@ -201,6 +201,11 @@ isdir(char *filename) /* Is directory */
201201
}
202202

203203

204+
/* joinpath requires that any buffer argument passed to it has at
205+
least MAXPATHLEN + 1 bytes allocated. If this requirement is met,
206+
it guarantees that it will never overflow the buffer. If stuff
207+
is too long, buffer will contain a truncated copy of stuff.
208+
*/
204209
static void
205210
joinpath(char *buffer, char *stuff)
206211
{
@@ -219,6 +224,10 @@ joinpath(char *buffer, char *stuff)
219224
buffer[n+k] = '\0';
220225
}
221226

227+
/* init_path_from_argv0 requirs that path be allocated at least
228+
MAXPATHLEN + 1 bytes and that argv0_path be no more than MAXPATHLEN
229+
bytes.
230+
*/
222231
static void
223232
init_path_from_argv0(char *path, char *argv0_path)
224233
{
@@ -237,6 +246,9 @@ init_path_from_argv0(char *path, char *argv0_path)
237246
}
238247
}
239248

249+
/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
250+
bytes long.
251+
*/
240252
static int
241253
search_for_prefix(char *argv0_path, char *home)
242254
{
@@ -246,7 +258,7 @@ search_for_prefix(char *argv0_path, char *home)
246258
/* If PYTHONHOME is set, we believe it unconditionally */
247259
if (home) {
248260
char *delim;
249-
strcpy(prefix, home);
261+
strncpy(prefix, home, MAXPATHLEN);
250262
delim = strchr(prefix, DELIM);
251263
if (delim)
252264
*delim = '\0';
@@ -293,7 +305,7 @@ search_for_prefix(char *argv0_path, char *home)
293305
} while (prefix[0]);
294306

295307
/* Look at configure's PREFIX */
296-
strcpy(prefix, PREFIX);
308+
strncpy(prefix, PREFIX, MAXPATHLEN);
297309
joinpath(prefix, lib_python);
298310
joinpath(prefix, LANDMARK);
299311
if (ismodule(prefix))
@@ -304,6 +316,9 @@ search_for_prefix(char *argv0_path, char *home)
304316
}
305317

306318

319+
/* search_for_exec_prefix requires that argv0_path be no more than
320+
MAXPATHLEN bytes long.
321+
*/
307322
static int
308323
search_for_exec_prefix(char *argv0_path, char *home)
309324
{
@@ -314,9 +329,9 @@ search_for_exec_prefix(char *argv0_path, char *home)
314329
char *delim;
315330
delim = strchr(home, DELIM);
316331
if (delim)
317-
strcpy(exec_prefix, delim+1);
332+
strncpy(exec_prefix, delim+1, MAXPATHLEN);
318333
else
319-
strcpy(exec_prefix, home);
334+
strncpy(exec_prefix, home, MAXPATHLEN);
320335
joinpath(exec_prefix, lib_python);
321336
joinpath(exec_prefix, "lib-dynload");
322337
return 1;
@@ -343,7 +358,7 @@ search_for_exec_prefix(char *argv0_path, char *home)
343358
} while (exec_prefix[0]);
344359

345360
/* Look at configure's EXEC_PREFIX */
346-
strcpy(exec_prefix, EXEC_PREFIX);
361+
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
347362
joinpath(exec_prefix, lib_python);
348363
joinpath(exec_prefix, "lib-dynload");
349364
if (isdir(exec_prefix))
@@ -377,6 +392,7 @@ calculate_path(void)
377392
#endif
378393

379394
#ifdef WITH_NEXT_FRAMEWORK
395+
/* XXX Need to check this code for buffer overflows */
380396
pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
381397
/* Use dylib functions to find out where the framework was loaded from */
382398
buf = NSLibraryNameForModule(pythonModule);
@@ -393,26 +409,30 @@ calculate_path(void)
393409
#endif
394410

395411
/* Initialize this dynamically for K&R C */
396-
sprintf(lib_python, "lib/python%s", VERSION);
412+
sprintf(lib_python, "lib/python%.9s", VERSION);
397413

398414
/* If there is no slash in the argv0 path, then we have to
399415
* assume python is on the user's $PATH, since there's no
400416
* other way to find a directory to start the search from. If
401417
* $PATH isn't exported, you lose.
402418
*/
403419
if (strchr(prog, SEP))
404-
strcpy(progpath, prog);
420+
strncpy(progpath, prog, MAXPATHLEN);
405421
else if (path) {
422+
int bufspace = MAXPATHLEN;
406423
while (1) {
407424
char *delim = strchr(path, DELIM);
408425

409426
if (delim) {
410427
size_t len = delim - path;
428+
if (len > bufspace)
429+
len = bufspace;
411430
strncpy(progpath, path, len);
412431
*(progpath + len) = '\0';
432+
bufspace -= len;
413433
}
414434
else
415-
strcpy(progpath, path);
435+
strncpy(progpath, path, bufspace);
416436

417437
joinpath(progpath, prog);
418438
if (isxfile(progpath))
@@ -431,7 +451,7 @@ calculate_path(void)
431451
}
432452
#endif
433453

434-
strcpy(argv0_path, progpath);
454+
strncpy(argv0_path, progpath, MAXPATHLEN);
435455

436456
#if HAVE_READLINK
437457
{
@@ -441,7 +461,9 @@ calculate_path(void)
441461
/* It's not null terminated! */
442462
tmpbuffer[linklen] = '\0';
443463
if (tmpbuffer[0] == SEP)
444-
strcpy(argv0_path, tmpbuffer);
464+
/* tmpbuffer should never be longer than MAXPATHLEN,
465+
but extra check does not hurt */
466+
strncpy(argv0_path, tmpbuffer, MAXPATHLEN);
445467
else {
446468
/* Interpret relative to progpath */
447469
reduce(argv0_path);
@@ -453,12 +475,15 @@ calculate_path(void)
453475
#endif /* HAVE_READLINK */
454476

455477
reduce(argv0_path);
478+
/* At this point, argv0_path is guaranteed to be less than
479+
MAXPATHLEN bytes long.
480+
*/
456481

457482
if (!(pfound = search_for_prefix(argv0_path, home))) {
458483
if (!Py_FrozenFlag)
459484
fprintf(stderr,
460485
"Could not find platform independent libraries <prefix>\n");
461-
strcpy(prefix, PREFIX);
486+
strncpy(prefix, PREFIX, MAXPATHLEN);
462487
joinpath(prefix, lib_python);
463488
}
464489
else
@@ -468,7 +493,7 @@ calculate_path(void)
468493
if (!Py_FrozenFlag)
469494
fprintf(stderr,
470495
"Could not find platform dependent libraries <exec_prefix>\n");
471-
strcpy(exec_prefix, EXEC_PREFIX);
496+
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
472497
joinpath(exec_prefix, "lib/lib-dynload");
473498
}
474499
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
@@ -565,15 +590,15 @@ calculate_path(void)
565590
reduce(prefix);
566591
}
567592
else
568-
strcpy(prefix, PREFIX);
593+
strncpy(prefix, PREFIX, MAXPATHLEN);
569594

570595
if (efound > 0) {
571596
reduce(exec_prefix);
572597
reduce(exec_prefix);
573598
reduce(exec_prefix);
574599
}
575600
else
576-
strcpy(exec_prefix, EXEC_PREFIX);
601+
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
577602
}
578603

579604

0 commit comments

Comments
 (0)