Changeset 114096


Ignore:
Timestamp:
Nov 29, 2013, 2:11:12 AM (6 years ago)
Author:
cal@…
Message:

darwintrace: fix expansion of multiple symlinks

Expanding a series of symlinks longer than a single symlink would previously
lead to re-use of a buffer that was used to store the result of readlink(2)
while the contents of the buffer were still in use in the pathComponent array.

This change refactors the path parsing and handling completely such that the
components of the normalized path will always be stored in the same buffer (and
other components will be copied there when needed), avoiding this problem.

Fixes the configure phase of stellarium and automoc (if you don't have
DARWINTRACE_DEBUG enabled).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/darwintracelib1.0/darwintrace.c

    r113469 r114096  
    708708        }
    709709
    710         char *pathComponents[MAXPATHLEN / 2 + 2];
    711         size_t componentIdx = 0;
     710        typedef struct {
     711                char *start;
     712                size_t len;
     713        } path_component_t;
     714
     715        char normPath[MAXPATHLEN];
     716        normPath[0] = '/';
     717        normPath[1] = '\0';
     718
     719        path_component_t pathComponents[MAXPATHLEN / 2 + 2];
     720        size_t numComponents = 0;
    712721
    713722        // Make sure the path is absolute.
    714         char cwd[MAXPATHLEN];
    715         if (path == NULL) {
     723        if (path == NULL || *path == '\0') {
    716724                // this is most certainly invalid, let the syscall deal with it
    717725                return true;
    718726        }
     727
     728        char *dst = NULL;
     729        const char *token = NULL;
     730        size_t idx;
    719731        if (*path != '/') {
    720732                // The path isn't absolute, start by populating pathcomponents with the
    721733                // current working directory
    722                 if (getcwd(cwd, sizeof(cwd)) == NULL) {
     734                if (getcwd(normPath, sizeof(normPath)) == NULL) {
    723735                        perror("darwintrace: getcwd");
    724736                        abort();
    725737                }
    726738
    727                 char *lastToken = cwd + 1;
    728                 char *token = NULL;
    729                 while (NULL != (token = strsep(&lastToken, "/"))) {
    730                         pathComponents[componentIdx++] = token;
    731                 }
    732         }
    733 
    734         // Copy path to a writable buffer
    735         char lpath[strlen(path) + 1];
    736         strcpy(lpath, path);
     739                char *writableToken = normPath + 1;
     740                while ((idx = strcspn(writableToken, "/")) > 0) {
     741                        // found a token, tokenize and store it
     742                        pathComponents[numComponents].start = writableToken;
     743                        pathComponents[numComponents].len   = idx;
     744                        numComponents++;
     745
     746                        bool final = writableToken[idx] == '\0';
     747                        writableToken[idx] = '\0';
     748                        if (final) {
     749                                break;
     750                        }
     751                        // advance token
     752                        writableToken += idx + 1;
     753                }
     754
     755                // copy path after the CWD into the buffer and normalize it
     756                if (numComponents > 0) {
     757                        path_component_t *lastComponent = pathComponents + (numComponents - 1);
     758                        dst = lastComponent->start + lastComponent->len + 1;
     759                } else {
     760                        dst = normPath + 1;
     761                }
     762
     763                // continue parsing at the begin of path
     764                token = path;
     765        } else {
     766                // skip leading '/'
     767                dst = normPath + 1;
     768                *dst = '\0';
     769                token = path + 1;
     770        }
    737771
    738772        /* Make sure the path is normalized. NOTE: Do _not_ use realpath(3) here.
    739773         * Doing so _will_ lead to problems. This is essentially a very simple
    740774         * re-implementation of realpath(3). */
    741         char *lastToken = lpath;
    742         char *token = NULL;
    743         while (NULL != (token = strsep(&lastToken, "/"))) {
    744                 if (token[0] == '\0') {
     775        while ((idx = strcspn(token, "/")) > 0) {
     776                // found a token, process it
     777
     778                if (token[0] == '\0' || token[0] == '/') {
    745779                        // empty entry, ignore
    746                 } else if (token[0] == '.' && token[1] == '\0') {
     780                } else if (token[0] == '.' && (token[1] == '\0' || token[1] == '/')) {
    747781                        // reference to current directory, ignore
    748                 } else if (token[0] == '.' && token[1] == '.' && token[2] == '\0') {
     782                } else if (token[0] == '.' && token[1] == '.' && (token[2] == '\0' || token[2] == '/')) {
    749783                        // walk up one directory, but not if it's the last one, because /.. -> /
    750                         if (componentIdx > 0) {
    751                                 componentIdx--;
     784                        if (numComponents > 0) {
     785                                numComponents--;
     786                                if (numComponents > 0) {
     787                                        // move dst back to the previous entry
     788                                        path_component_t *lastComponent = pathComponents + (numComponents - 1);
     789                                        dst = lastComponent->start + lastComponent->len + 1;
     790                                } else {
     791                                        // we're at the top, move dst back to the beginning
     792                                        dst = normPath + 1;
     793                                }
    752794                        }
    753795                } else {
    754                         // default case: standard path
    755                         pathComponents[componentIdx++] = token;
    756                 }
    757         }
    758 
    759         char link[MAXPATHLEN];
    760         char normPath[MAXPATHLEN];
     796                        // copy token to normPath buffer (and null-terminate it)
     797                        strlcpy(dst, token, idx + 1);
     798                        dst[idx] = '\0';
     799                        // add descriptor entry for new token
     800                        pathComponents[numComponents].start = dst;
     801                        pathComponents[numComponents].len   = idx;
     802                        numComponents++;
     803
     804                        // advance destination
     805                        dst += idx + 1;
     806                }
     807
     808                if (token[idx] == '\0') {
     809                        break;
     810                }
     811                token += idx + 1;
     812        }
     813
    761814        bool pathIsSymlink;
    762815        size_t loopCount = 0;
     
    764817                pathIsSymlink = false;
    765818
     819                // Add the slashes and the terminating \0
     820                for (size_t i = 0; i < numComponents; ++i) {
     821                        if (i == numComponents - 1) {
     822                                pathComponents[i].start[pathComponents[i].len] = '\0';
     823                        } else {
     824                                pathComponents[i].start[pathComponents[i].len] = '/';
     825                        }
     826                }
     827
    766828                if (++loopCount >= 10) {
    767829                        // assume cylce and let the OS deal with that (yes, this actually
     
    770832                }
    771833
    772                 char *normPathPos = normPath;
    773                 *normPathPos = '\0';
    774 
    775                 // Build a canonical representation of the path
    776                 for (size_t i = 0; i < componentIdx; ++i) {
    777                         *normPathPos++ = '/';
    778                         normPathPos = stpcpy(normPathPos, pathComponents[i]);
    779                 }
    780                 if (componentIdx == 0) {
    781                         // path is "/"
    782                         *normPathPos++ = '/';
    783                         *normPathPos = '\0';
    784                 }
    785 
    786834                // Check whether the last component is a symlink; if it is, check
    787835                // whether it is in the sandbox, expand it and do the same thing again.
    788836                struct stat st;
     837                //debug_printf("checking for symlink: %s\n", normPath);
    789838                if (lstat(normPath, &st) != -1 && S_ISLNK(st.st_mode)) {
    790839                        if (!__darwintrace_sandbox_check(normPath, flags)) {
     
    792841                        }
    793842
     843                        char link[MAXPATHLEN];
    794844                        pathIsSymlink = true;
    795845
     
    800850                        }
    801851                        link[linksize] = '\0';
     852                        //debug_printf("readlink(%s) = %s\n", normPath, link);
    802853
    803854                        if (*link == '/') {
    804855                                // symlink is absolute, start fresh
    805                                 componentIdx = 0;
     856                                numComponents = 0;
     857                                token = link + 1;
     858                                dst = normPath + 1;
    806859                        } else {
    807860                                // symlink is relative, remove last component
    808                                 if (componentIdx > 0) {
    809                                         componentIdx--;
     861                                token = link;
     862                                if (numComponents > 0) {
     863                                        numComponents--;
     864                                        if (numComponents > 0) {
     865                                                // move dst back to the previous entry
     866                                                path_component_t *lastComponent = pathComponents + (numComponents - 1);
     867                                                dst = lastComponent->start + lastComponent->len + 1;
     868                                        } else {
     869                                                // we're at the top, move dst back to the beginning
     870                                                dst = normPath + 1;
     871                                        }
    810872                                }
    811873                        }
    812874
    813                         lastToken = link;
    814                         token = NULL;
    815                         while (NULL != (token = strsep(&lastToken, "/"))) {
    816                                 if (token[0] == '\0') {
     875                        while ((idx = strcspn(token, "/")) > 0) {
     876                                // found a token, process it
     877
     878                                if (token[0] == '\0' || token[0] == '/') {
    817879                                        // empty entry, ignore
    818                                 } else if (token[0] == '.' && token[1] == '\0') {
     880                                } else if (token[0] == '.' && (token[1] == '\0' || token[1] == '/')) {
    819881                                        // reference to current directory, ignore
    820                                 } else if (token[0] == '.' && token[1] == '.' && token[2] == '\0') {
     882                                } else if (token[0] == '.' && token[1] == '.' && (token[2] == '\0' || token[2] == '/')) {
    821883                                        // walk up one directory, but not if it's the last one, because /.. -> /
    822                                         if (componentIdx > 0) {
    823                                                 componentIdx--;
     884                                        if (numComponents > 0) {
     885                                                numComponents--;
     886                                                if (numComponents > 0) {
     887                                                        // move dst back to the previous entry
     888                                                        path_component_t *lastComponent = pathComponents + (numComponents - 1);
     889                                                        dst = lastComponent->start + lastComponent->len + 1;
     890                                                } else {
     891                                                        // we're at the top, move dst back to the beginning
     892                                                        dst = normPath + 1;
     893                                                }
    824894                                        }
    825895                                } else {
    826                                         // default case: standard path
    827                                         pathComponents[componentIdx++] = token;
     896                                        // copy token to normPath buffer
     897                                        strlcpy(dst, token, idx + 1);
     898                                        dst[idx] = '\0';
     899                                        // add descriptor entry for new token
     900                                        pathComponents[numComponents].start = dst;
     901                                        pathComponents[numComponents].len   = idx;
     902                                        numComponents++;
     903
     904                                        // advance destination
     905                                        dst += idx + 1;
    828906                                }
     907
     908                                if (token[idx] == '\0') {
     909                                        break;
     910                                }
     911                                token += idx + 1;
    829912                        }
    830913                }
Note: See TracChangeset for help on using the changeset viewer.