Skip to content

Commit 8e03613

Browse files
committed
Measure starting a program that needs an interpreter
openkal-linux could not start one AT ALL --- every `#!` script on every architecture --- and no suite anywhere looked, which is why it survived until a foreign binary made the same failure loud on aarch64. ⚠️ THIS IMPLEMENTATION IS EXPECTED TO PASS AND IS CHECKED ANYWAY. It has no `execveat': it enters the directory and calls `execve' with a whole path, so the kernel never holds a name the interpreter cannot reopen. That is a reason to BELIEVE it works. Believing is exactly how the other one went unmeasured, and the reasoning that said "not ours" there was three true observations pointing the wrong way. Test-only; no behaviour changes and no version bump.
1 parent 6546f16 commit 8e03613

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

tests/conformance_process_task.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,57 @@ int main() {
187187
"the started program observes the argument vector the caller supplied, unaltered");
188188
kal_process_close(r);
189189
}
190+
191+
// ⭐⭐ A PROGRAM THAT NEEDS AN INTERPRETER, WHICH openkal-linux COULD NOT
192+
// START AND NOBODY HAD MEASURED ANYWHERE.
193+
//
194+
// There, `execveat' with a directory descriptor gives the kernel the
195+
// name as `/dev/fd/<dirfd>/<name>' --- and the kernel hands THAT to the
196+
// interpreter to open, after the replacement, by which time a
197+
// close-on-exec descriptor is gone. Every `#!' script was unstartable on
198+
// every architecture, and it was found only because a foreign binary
199+
// needs an interpreter too and so aarch64 failed loudly.
200+
//
201+
// ⚠️ THIS IMPLEMENTATION IS EXPECTED TO PASS AND IS CHECKED ANYWAY. It
202+
// has no `execveat': it enters the directory and calls `execve' with a
203+
// whole path, so the kernel never has a name the interpreter cannot
204+
// reopen. That is a reason to believe it works, and believing was how
205+
// the other one went unmeasured for as long as it did.
206+
{
207+
const char* mk =
208+
"printf '#!/bin/sh\\nexit 0\\n' > /tmp/okm-interp.sh && chmod 755 /tmp/okm-interp.sh";
209+
kal_uintptr mk_len = 0; while (mk[mk_len]) ++mk_len;
210+
kal_process m{};
211+
const char* mav[] = { "sh", "-c", mk };
212+
const kal_uintptr mlen[] = { 2, 2, mk_len };
213+
int made = kal_err_invalid;
214+
if (sh >= 0)
215+
made = kal_process_spawn(&how, sh_paths[sh], sh_lens[sh], mav, mlen, 3,
216+
nullptr, nullptr, 0, nullptr, &m);
217+
if (made == kal_ok) {
218+
int ms = -1, mt = -1;
219+
kal_process_wait(m, &ms, &mt);
220+
kal_process_close(m);
221+
}
222+
check(made == kal_ok, "a shell makes an executable script to start");
223+
224+
kal_process s{};
225+
const char* sav[] = { "okm-interp.sh" };
226+
const kal_uintptr slen[] = { 13 };
227+
const int se = kal_process_spawn(&how, "tmp/okm-interp.sh", 17,
228+
sav, slen, 1,
229+
nullptr, nullptr, 0, nullptr, &s);
230+
if (se == kal_ok) {
231+
int ss = -1, st2 = -1;
232+
kal_process_wait(s, &ss, &st2);
233+
check(ss == 0 && st2 == 0,
234+
"a program that needs an interpreter starts, and runs");
235+
say(" interpreter: a #! script started and ran\n");
236+
kal_process_close(s);
237+
} else {
238+
check(false, "a program that needs an interpreter starts");
239+
}
240+
}
190241
}
191242

192243
// A name that ascends is refused here as it is in the file system.

0 commit comments

Comments
 (0)