This commit is contained in:
root
2026-06-15 21:42:50 +00:00
parent 34a97e2577
commit 99cd92fb4a
126 changed files with 1615 additions and 1057 deletions
+57 -2
View File
@@ -1012,6 +1012,56 @@ private:
return(stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
}
// Keep cwd host behavior local to this process but guard it with the same
// write-root policy we use for file writes (plus a single parity fallback).
String resolve_guest_cwd_set(const String& raw)
{
if(raw == "" || raw.find('\0') != String::npos)
return("");
String raw_target = raw;
if(raw.rfind("/", 0) != 0)
{
String cwd = ::cwd_get();
if(cwd == "")
return("");
raw_target = cwd + "/" + raw;
}
char resolved[PATH_MAX];
if(!realpath(raw_target.c_str(), resolved))
return("");
String resolved_target(resolved);
if(!dir_exists_host(resolved_target))
return("");
// Policy: allow only roots we already expose for writable filesystem access.
std::vector<String> roots;
roots.push_back(worker.cfg.site_root);
for(auto& root : worker.cfg.write_roots)
roots.push_back(root);
for(auto& root : roots)
{
if(root == "")
continue;
char root_real[PATH_MAX];
if(!realpath(root.c_str(), root_real))
continue;
String canonical_root(root_real);
if(resolved_target == canonical_root)
return(resolved_target);
if(canonical_root != "/" && resolved_target.rfind(canonical_root + "/", 0) == 0)
return(resolved_target);
}
// Parity/fallback: allow returning to the process start directory so
// legacy behavior is not silently broken for existing native/cached flows.
String start_directory = ::process_start_directory();
if(start_directory != "" && resolved_target == start_directory)
return(resolved_target);
return("");
}
String resolve_source_path(const String& file_name, const String& current_unit)
{
std::vector<String> bases;
@@ -1378,7 +1428,8 @@ private:
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
String path;
self->hostcall_read(args[0].i32(), args[1].i32(), path);
results[0] = Val(::chdir(path.c_str()) == 0 ? (int32_t)1 : (int32_t)0);
String resolved = self->resolve_guest_cwd_set(path);
results[0] = Val(::chdir(resolved.c_str()) == 0 ? (int32_t)1 : (int32_t)0);
return(std::monostate());
}));
if(mod == "env" && name == "uce_host_process_start_directory")
@@ -1991,6 +2042,10 @@ private:
f64 interval = args[3].f64();
u64 timeout = (u64)args[4].i64();
bool repeat = args[5].i32() != 0;
// task()/task_repeat() fork and invoke this lambda only in the child
// before the hostcall stack unwinds, so `self` points to the child's
// copy of this per-request workspace. The parent request can return and
// destroy its workspace without invalidating the child copy.
auto run_callback = [self, callback_id]() {
String error = self->run_task_callback(callback_id);
if(error != "")
@@ -2049,7 +2104,7 @@ private:
}));
if(mod == "env" && name == "uce_host_regex")
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
// {op,pattern,subject,flags,replacement} in (UCEB1) → result out.
// {op,pattern,subject,flags,replacement} in (UCEB2) → result out.
// PCRE2 lives host-side; this runs the native regex_*.
String encoded;
self->hostcall_read(args[0].i32(), args[1].i32(), encoded);