diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2017-11-20 17:32:27 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-20 17:32:27 +0100 |
commit | 72804dc0bdc560c6f7db0fa638403fdddbe692fd (patch) | |
tree | 4a50dc4c587ddeb1f263aadfe70f1614d3cfc361 | |
parent | 7474ac871b73bd4e739a547b4870b33d625d4c70 (diff) | |
parent | 07d2c6d213660e178fcdf128ea6f1f36d9d8a85d (diff) |
Merge pull request #1645 from twhitehead/stat-race
Fix (highly unlikely) race condition in readLink
-rw-r--r-- | src/libutil/util.cc | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc index f56153cd4..96c0cd783 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -216,18 +216,17 @@ bool pathExists(const Path & path) Path readLink(const Path & path) { checkInterrupt(); - struct stat st = lstat(path); - if (!S_ISLNK(st.st_mode)) - throw Error(format("'%1%' is not a symlink") % path); - auto bufSize = std::max(st.st_size, (off_t) PATH_MAX + 1); - char buf[bufSize]; - ssize_t rlsize = readlink(path.c_str(), buf, bufSize); - if (rlsize == -1) - throw SysError(format("reading symbolic link '%1%'") % path); - else if (rlsize > bufSize) - throw Error(format("symbolic link '%1%' size overflow %2% > %3%") - % path % rlsize % bufSize); - return string(buf, rlsize); + for (ssize_t bufSize = PATH_MAX/4; true; bufSize += bufSize/2) { + char buf[bufSize]; + ssize_t rlSize = readlink(path.c_str(), buf, bufSize); + if (rlSize == -1) + if (errno == EINVAL) + throw Error(format("'%1%' is not a symlink") % path); + else + throw SysError(format("reading symbolic link '%1%'") % path); + else if (rlSize < bufSize) + return string(buf, rlSize); + } } |