mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 16:21:29 +00:00
LibC: Avoid silent truncation after overlong realpath
The realpath syscall can attempt to return arbitrarily long paths, in particular paths that are longer than PATH_MAX. The only way to detect this case is checking whether 'rc', the true length of the returned path including NUL byte, exceeds our buffer length. In such a case, the buffer contains invalid data. All Serenity code calls LibC's realpath() with a nullptr buffer, meaning that realpath is supposed to allocate memory on its own. All Serenity code can handle arbitrarily long paths returned by LibC's realpath, so it is safe to "do the dance" and repeat the syscall with a new buffer. Ports are likely to be graceful in this regard, too. If a Port calls realpath() with a pre-allocated buffer, however, there is nothing better we can do than return a truncated buffer.
This commit is contained in:
parent
68416d7293
commit
5dc29065e1
Notes:
sideshowbarker
2024-07-18 23:10:12 +09:00
Author: https://github.com/BenWiederhake Commit: https://github.com/SerenityOS/serenity/commit/5dc29065e1d Pull-request: https://github.com/SerenityOS/serenity/pull/4965 Reviewed-by: https://github.com/bugaevc Reviewed-by: https://github.com/emanuele6
|
@ -1051,6 +1051,8 @@ char* realpath(const char* pathname, char* buffer)
|
|||
size_t size = PATH_MAX;
|
||||
bool self_allocated = false;
|
||||
if (buffer == nullptr) {
|
||||
// Since we self-allocate, try to sneakily use a smaller buffer instead, in an attempt to use less memory.
|
||||
size = 64;
|
||||
buffer = (char*)malloc(size);
|
||||
self_allocated = true;
|
||||
}
|
||||
|
@ -1062,6 +1064,29 @@ char* realpath(const char* pathname, char* buffer)
|
|||
errno = -rc;
|
||||
return nullptr;
|
||||
}
|
||||
if (self_allocated && static_cast<size_t>(rc) > size) {
|
||||
// There was silent truncation, *and* we can simply retry without the caller noticing.
|
||||
free(buffer);
|
||||
size = static_cast<size_t>(rc);
|
||||
buffer = (char*)malloc(size);
|
||||
params.buffer = { buffer, size };
|
||||
rc = syscall(SC_realpath, ¶ms);
|
||||
if (rc < 0) {
|
||||
// Can only happen if we lose a race. Let's pretend we lost the race in the first place.
|
||||
free(buffer);
|
||||
errno = -rc;
|
||||
return nullptr;
|
||||
}
|
||||
size_t new_size = static_cast<size_t>(rc);
|
||||
if (new_size < size) {
|
||||
// If we're here, the symlink has become longer while we were looking at it.
|
||||
// There's not much we can do, unless we want to loop endlessly
|
||||
// in this case. Let's leave it up to the caller whether to loop.
|
||||
free(buffer);
|
||||
errno = EAGAIN;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
errno = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue