gate: pass on macOS: tests use /tmp, gatewayd finds its uid without /proc
M5a task 16. The work is Ornith's, from the stopped run; the design model checked it against the task file and committed it once the memoryd lint that stopped the gate was fixed (44bdcbd). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -163,7 +163,7 @@ pub fn read_checked(path: &Path, between: &dyn Fn()) -> Result<Zeroizing<Vec<u8>
|
||||
// 5. `if (opened.dev(), opened.ino()) != (named.dev(), named.ino())`:
|
||||
// "<path> changed while it was read".
|
||||
// 6. The owner and mode checks from the original file check, word for word, on `opened` (not
|
||||
// on `named`): the uid of "/proc/self"; "<path> is not owned by the user gatewayd runs as";
|
||||
// on `named`): the uid of `user_id()`; "<path> is not owned by the user gatewayd runs as";
|
||||
// "<path> has mode <mode:03o>; only the owner may read it (0600 or 0400)".
|
||||
// 7. `let mut bytes = Zeroizing::new(Vec::new());` then `file.read_to_end(&mut bytes)`, an
|
||||
// Err(e) is "cannot read <path>: <e>". Ok(bytes).
|
||||
@@ -187,9 +187,7 @@ pub fn read_checked(path: &Path, between: &dyn Fn()) -> Result<Zeroizing<Vec<u8>
|
||||
if (opened.dev(), opened.ino()) != (named.dev(), named.ino()) {
|
||||
return Err(format!("{} changed while it was read", path.display()));
|
||||
}
|
||||
let owner = std::fs::metadata("/proc/self")
|
||||
.map_err(|e| format!("cannot read /proc/self: {}", e))?
|
||||
.uid();
|
||||
let owner = user_id()?;
|
||||
if opened.uid() != owner {
|
||||
return Err(format!(
|
||||
"{} is not owned by the user gatewayd runs as",
|
||||
@@ -210,6 +208,17 @@ pub fn read_checked(path: &Path, between: &dyn Fn()) -> Result<Zeroizing<Vec<u8>
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// The user id this process runs as: the owner of a pipe it has just made. `std` has no call for
|
||||
/// it, and `/proc/self` is Linux only.
|
||||
fn user_id() -> Result<u32, String> {
|
||||
let (reader, _writer) = std::io::pipe().map_err(|e| format!("cannot make a pipe: {e}"))?;
|
||||
let pipe = std::fs::File::from(std::os::fd::OwnedFd::from(reader));
|
||||
let meta = pipe
|
||||
.metadata()
|
||||
.map_err(|e| format!("cannot read a pipe: {e}"))?;
|
||||
Ok(meta.uid())
|
||||
}
|
||||
|
||||
/// The text without one trailing newline; not empty; UTF-8.
|
||||
fn value(bytes: Vec<u8>) -> Result<Secret, String> {
|
||||
// UTF-8 (else an error), one trailing newline removed, not empty. Keep the bytes in `Zeroizing`
|
||||
|
||||
@@ -42,10 +42,12 @@ fn a_command_killed_by_a_signal_says_so() {
|
||||
fn the_command_runs_in_cwd_or_in_tmp() {
|
||||
let dir = TempDir::new("cwd");
|
||||
let here = dir.path().to_str().unwrap();
|
||||
// `pwd` prints the path with symbolic links resolved: on macOS, /tmp is /private/tmp.
|
||||
let real = |path: &str| std::fs::canonicalize(path).unwrap().display().to_string();
|
||||
let ran = sh("pwd", Some(here));
|
||||
assert_eq!(ran.stdout, format!("{here}\n\n[exit 0]"));
|
||||
assert_eq!(ran.stdout, format!("{}\n\n[exit 0]", real(here)));
|
||||
let ran = sh("pwd", None);
|
||||
assert_eq!(ran.stdout, "/tmp\n\n[exit 0]");
|
||||
assert_eq!(ran.stdout, format!("{}\n\n[exit 0]", real("/tmp")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user