Serve no file whose path cannot be resolved

When the real path of a file under a mount point could not be resolved,
the check that it stays inside the mount point was skipped and the file
was served. Do not serve it from there, and refuse a mount point whose
directory cannot be resolved.
This commit is contained in:
yhirose committed 2026-10-16 16:39:00 -04:00
1 parent 455166314b
commit eeaae4bc3c
2 files changed
+48 -17

No files matched your search

+22 -17
View File
@@ -13340,16 +13340,19 @@ inline bool Server::set_mount_point(const std::string &mount_point,
if (stat.is_dir()) {
std::string mnt = !mount_point.empty() ? mount_point : "/";
if (!mnt.empty() && mnt[0] == '/') {
// Without the resolved directory, a file could not be checked to be
// inside it.
std::string resolved_base;
if (detail::canonicalize_path(dir.c_str(), resolved_base)) {
#if defined(_WIN32)
if (resolved_base.back() != '\\' && resolved_base.back() != '/') {
resolved_base += '\\';
}
#else
if (resolved_base.back() != '/') { resolved_base += '/'; }
#endif
if (!detail::canonicalize_path(dir.c_str(), resolved_base)) {
return false;
}
#if defined(_WIN32)
if (resolved_base.back() != '\\' && resolved_base.back() != '/') {
resolved_base += '\\';
}
#else
if (resolved_base.back() != '/') { resolved_base += '/'; }
#endif
base_dirs_.push_back(
{std::move(mnt), dir, std::move(resolved_base), std::move(headers)});
return true;
@@ -14017,15 +14020,17 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
if (path.back() == '/') { path += "index.html"; }
// Defense-in-depth: is_valid_path blocks ".." traversal in the URL,
// but symlinks/junctions can still escape the base directory.
if (!entry.resolved_base_dir.empty()) {
std::string resolved_path;
if (detail::canonicalize_path(path.c_str(), resolved_path) &&
!detail::is_path_within_base(resolved_path,
entry.resolved_base_dir)) {
res.status = StatusCode::Forbidden_403;
return true;
}
// but symlinks/junctions can still escape the base directory. A path
// that cannot be resolved, which includes one that does not exist, is
// not served from here.
std::string resolved_path;
if (!detail::canonicalize_path(path.c_str(), resolved_path)) {
continue;
}
if (!detail::is_path_within_base(resolved_path,
entry.resolved_base_dir)) {
res.status = StatusCode::Forbidden_403;
return true;
}
detail::FileStat stat(path);