diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f19d81..803c300 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -288,6 +288,15 @@ jobs: grep -q "argc as kal_env_arg_count = 3" <<<"$out" || { echo "::error::the image's arguments"; exit 1; } grep -q "mix = 204" <<<"$out" || { echo "::error::the calling convention"; exit 1; } grep -q "tls main=1 ctx1=10 ctx2=20" <<<"$out" || { echo "::error::thread-local storage or the callback"; exit 1; } + # A RELATIVE NAME THAT CLIMBS (0.6.2): `..' above the working + # directory folds against its name and opens through the supplied + # directory that then holds it; `./' beside it and an absolute name + # already ran. + mkdir -p rel/below + (cd rel/below && "$OKRUN" ../../"out/$a/hello.oke" one | tr -d '\r' \ + | grep -q "argc as kal_env_arg_count = 2") \ + || { echo "::error::a relative image name with .. was not opened"; exit 1; } + echo " ok a relative name that climbs opens the image" n=$("$OKRUN" "out/$a/needed.oke" | tr -d '\r') echo "$n" grep -q "twice(21) = 42, next_value() = 41" <<<"$n" || { echo "::error::an image another needs"; exit 1; } diff --git a/README.md b/README.md index 2c06b2f..9250762 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,14 @@ states the system's base), where openkal-freebsd is hosted, and over openkal-musl (`-freebsd-musl`), whose graph already holds openkal-freebsd standalone. No other change. +Version 0.6.2 opens an image whose relative name climbs above the working +directory (`../image.oke`). Such a name was passed to the file system as it +stood, and an openkal name admits no `..` component, so the image was refused. +The runner now folds a relative name against the first directory's name --- +`..' and `.' lexically, a symlink left to the file system --- into the absolute +name beneath it, which is matched against the supplied directories as an +absolute one is. No other change. + ## An image ```sh diff --git a/bind/mcpp.toml b/bind/mcpp.toml index a9c555c..5634b77 100644 --- a/bind/mcpp.toml +++ b/bind/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-bind" -version = "0.6.1" +version = "0.6.2" # `mcpp::xpkg_request', `mcpp::decision' (protocol 15). mcpp = ">=2026.10.1.3" description = "A build plugin: a library published as an ok image (.okso) and a C header is called from a program of any system, through a binding generated from the header and libokrun." diff --git a/ld/mcpp.toml b/ld/mcpp.toml index b3583f7..30598ea 100644 --- a/ld/mcpp.toml +++ b/ld/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-ld" -version = "0.6.1" +version = "0.6.2" description = "libokld: the ok format (openkal image format) --- its definition, a reader of bytes, a checker, a signer, and a loader. Freestanding: no C library, no exceptions." license = "Apache-2.0" authors = ["mcpplibs"] diff --git a/run/mcpp.toml b/run/mcpp.toml index 66163ce..2d39a3e 100644 --- a/run/mcpp.toml +++ b/run/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-run" -version = "0.6.1" +version = "0.6.2" description = "libokrun: the runner's core --- an ok image's names bound to this process's one openkal implementation, in the image's calling convention, and its entry entered." license = "Apache-2.0" authors = ["mcpplibs"] diff --git a/run/src/run.cpp b/run/src/run.cpp index 2369d84..97e21e2 100644 --- a/run/src/run.cpp +++ b/run/src/run.cpp @@ -67,33 +67,61 @@ void* allocate(okld_size n, void*) { return kal_alloc(n, 16); } void deallocate(void* p, okld_size n, void*) { kal_free(p, n, 16); } // A name as openkal names things: the supplied directory that is the longest -// prefix of it, and the rest. A relative name is beneath the first. +// prefix of it, and the rest. A relative name is folded against the first +// directory's name --- `..' and `.' lexically, a symlink not resolved --- into +// the absolute one beneath it and matched as that. It folds into `g_folded', +// which outlives the call: the rest points into it. bool separator(char c) { return c == '/' || c == '\\'; } char lower(char c) { return (c >= 'A' && c <= 'Z') ? static_cast(c - 'A' + 'a') : c; } +char g_folded[1024]; + bool locate(const char* path, kal_dir& dir, const char*& rest) { - const bool absolute = separator(path[0]) || (path[0] && path[1] == ':'); - if (!absolute) { - char name[8]; kal_uintptr len = 0; - if (kal_fs_preopen(0, &dir, name, sizeof name, &len) != kal_ok) return false; - rest = path; - while (rest[0] == '.' && separator(rest[1])) rest += 2; - return true; + const char* name = path; + if (!(separator(path[0]) || (path[0] && path[1] == ':'))) { + char base[1024]; kal_uintptr blen = 0; + if (kal_fs_preopen(0, &dir, base, sizeof base, &blen) != kal_ok + || blen == 0 || blen >= sizeof g_folded) return false; + unsigned long at = 0; + while (at < blen) { g_folded[at] = base[at]; ++at; } + if (!separator(g_folded[at - 1])) g_folded[at++] = '/'; + // `..' may climb out of the first directory, to the root of what it + // then names: the whole tree, or a drive's. No higher. + unsigned long floor = at; + if (blen > 1 && separator(g_folded[0])) floor = 1; + else if (blen > 3 && g_folded[1] == ':' && separator(g_folded[2])) floor = 3; + for (const char* p = path; *p;) { + const char* s = p; + while (*p && !separator(*p)) ++p; + const unsigned long n = static_cast(p - s); + while (separator(*p)) ++p; + if (n == 0 || (n == 1 && s[0] == '.')) continue; + if (n == 2 && s[0] == '.' && s[1] == '.') { + if (at <= floor) return false; + do --at; while (at > floor && !separator(g_folded[at - 1])); + continue; + } + if (at && !separator(g_folded[at - 1])) g_folded[at++] = '/'; + if (at + n >= sizeof g_folded) return false; + for (unsigned long i = 0; i < n; ++i) g_folded[at++] = s[i]; + } + g_folded[at] = 0; + name = g_folded; } unsigned long best = 0; bool found = false; for (kal_uintptr i = 0; i < kal_fs_preopen_count(); ++i) { - kal_dir d{}; char name[1024]; kal_uintptr len = 0; - if (kal_fs_preopen(i, &d, name, sizeof name, &len) != kal_ok || len == 0 || len >= sizeof name) continue; + kal_dir d{}; char pname[1024]; kal_uintptr len = 0; + if (kal_fs_preopen(i, &d, pname, sizeof pname, &len) != kal_ok || len == 0 || len >= sizeof pname) continue; unsigned long k = 0; - while (k < len && path[k] && (lower(path[k]) == lower(name[k]) || (separator(path[k]) && separator(name[k])))) ++k; + while (k < len && name[k] && (lower(name[k]) == lower(pname[k]) || (separator(name[k]) && separator(pname[k])))) ++k; if (k != len) continue; - if (!separator(name[len - 1]) && path[len] && !separator(path[len])) continue; + if (!separator(pname[len - 1]) && name[len] && !separator(name[len])) continue; if (found && len <= best) continue; best = len; found = true; dir = d; } if (!found) return false; - rest = path + best; + rest = name + best; while (separator(*rest)) ++rest; return true; } diff --git a/tools/mcpp.toml b/tools/mcpp.toml index d377004..042969c 100644 --- a/tools/mcpp.toml +++ b/tools/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-tools" -version = "0.6.1" +version = "0.6.2" description = "okrun, which runs an ok image on this system, and okld, the format's tool on a build machine (check, note, sign, inspect)." license = "Apache-2.0" authors = ["mcpplibs"]