Reject unreadable UCE source units

This commit is contained in:
udo
2026-07-13 15:28:35 +00:00
parent cd2fa163e6
commit a288b539c6
4 changed files with 71 additions and 7 deletions
+34 -2
View File
@@ -2,8 +2,10 @@
#include "compiler-parser.h"
#include "hash.h"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <fcntl.h>
#include <mutex>
@@ -50,6 +52,7 @@ struct UnitSourceSignatureEntry
u64 modified_ns = 0;
u64 changed_ns = 0;
u64 size = 0;
bool readable = false;
String content_hash;
StringList loaded_paths;
};
@@ -128,6 +131,18 @@ StringList compiler_unit_load_paths(String file_name, String content)
return(paths);
}
bool compiler_source_readable(String file_name, const struct stat& info, int* read_error = 0)
{
int error = 0;
if((info.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0)
error = EACCES;
else if(access(file_name.c_str(), R_OK) != 0)
error = errno;
if(read_error)
*read_error = error;
return(error == 0);
}
UnitSourceSignatureEntry compiler_unit_source_entry(String file_name)
{
struct stat info;
@@ -137,10 +152,11 @@ UnitSourceSignatureEntry compiler_unit_source_entry(String file_name)
entry.modified_ns = (u64)info.st_mtim.tv_sec * 1000000000ull + (u64)info.st_mtim.tv_nsec;
entry.changed_ns = (u64)info.st_ctim.tv_sec * 1000000000ull + (u64)info.st_ctim.tv_nsec;
entry.size = (u64)info.st_size;
entry.readable = compiler_source_readable(file_name, info);
{
std::lock_guard<std::mutex> lock(unit_source_signature_cache_mutex);
auto cached = unit_source_signature_cache.find(file_name);
if(cached != unit_source_signature_cache.end() && cached->second.modified_ns == entry.modified_ns && cached->second.changed_ns == entry.changed_ns && cached->second.size == entry.size)
if(cached != unit_source_signature_cache.end() && cached->second.modified_ns == entry.modified_ns && cached->second.changed_ns == entry.changed_ns && cached->second.size == entry.size && cached->second.readable == entry.readable)
return(cached->second);
}
String content = file_get_contents(file_name);
@@ -165,7 +181,7 @@ void compiler_append_unit_source_signature(String file_name, std::set<String>& v
visited.insert(normalized);
UnitSourceSignatureEntry entry = compiler_unit_source_entry(normalized);
signature += normalized + ":" + entry.content_hash + "\n";
signature += normalized + ":" + entry.content_hash + (entry.readable ? String("") : String(":unreadable")) + "\n";
for(String loaded : entry.loaded_paths)
compiler_append_unit_source_signature(loaded, visited, signature);
}
@@ -793,6 +809,22 @@ void compile_shared_unit(Request* context, SharedUnit* su)
compiler_record_compile_result(su, time_precise() - comp_start, false, "missing_source", su->compiler_messages);
return;
}
struct stat source_info;
int read_error = 0;
bool source_readable = stat(su->file_name.c_str(), &source_info) == 0 && compiler_source_readable(su->file_name, source_info, &read_error);
if(!source_readable && read_error == 0)
read_error = errno == 0 ? ENOENT : errno;
if(!source_readable)
{
su->compiler_messages = "source file is not readable (" + su->file_name + "): " + std::strerror(read_error);
file_put_contents(su->compile_output_file_name, su->compiler_messages + "\n");
file_put_contents(su->wasm_check_file_name, su->compiler_messages + "\n");
file_put_contents(su->meta_file_name, compiler_unit_metadata_text(context, su));
file_unlink(su->wasm_name);
compiler_record_compile_result(su, time_precise() - comp_start, false, "compile_error", su->compiler_messages);
printf("%s \n", compiler_format_compile_failure(su, su->compiler_messages).c_str());
return;
}
shell_exec("mkdir -p " + shell_escape(su->pre_path));
file_put_contents(su->pre_path + "/" + su->pre_file_name, preprocess_shared_unit(context, su));
+11 -4
View File
@@ -438,8 +438,9 @@ int handle_cli_complete(FastCGIRequest& request)
// W7e: compile a cold/stale unit on demand; native execution has
// been removed, so a unit that still cannot be served by wasm is a
// request failure instead of a fallback path.
SharedUnit* cli_compile_state = 0;
if(!wasm_backend_should_handle(request, cli_unit))
get_shared_unit(&request, cli_unit);
cli_compile_state = get_shared_unit(&request, cli_unit);
if(wasm_backend_should_handle(request, cli_unit))
{
String wasm_error = wasm_backend_serve(request, cli_unit, "cli");
@@ -452,7 +453,11 @@ int handle_cli_complete(FastCGIRequest& request)
else
{
request.set_status(500, "Internal Server Error");
print("UCE CLI wasm unit unavailable after compile: ", script_filename, "\n");
String compile_error = cli_compile_state ? first(cli_compile_state->compiler_messages, cli_compile_state->compile_error_status) : String("");
print("UCE CLI wasm unit unavailable after compile: ", script_filename);
if(compile_error != "")
print(": ", compile_error);
print("\n");
}
}
}
@@ -575,14 +580,16 @@ int handle_complete(FastCGIRequest& request) {
// unit on demand — get_shared_unit() builds the .wasm side-module — and
// recheck. Native execution has been removed, so a unit that still cannot
// be served by wasm becomes a clean 500 request failure.
SharedUnit* entry_compile_state = 0;
auto wasm_ready = [&](const String& unit) -> bool {
if(!wasm_backend_should_handle(request, unit))
get_shared_unit(&request, unit);
entry_compile_state = get_shared_unit(&request, unit);
return(wasm_backend_should_handle(request, unit));
};
auto fail_wasm_unavailable = [&](const String& handler) {
failure_title = "wasm unit unavailable after compile";
failure_details = handler + " handler could not be served by wasm";
String compile_error = entry_compile_state ? first(entry_compile_state->compiler_messages, entry_compile_state->compile_error_status) : String("");
failure_details = compile_error != "" ? compile_error : handler + " handler could not be served by wasm";
failure_trace = "source: " + request.params["SCRIPT_FILENAME"];
};