brokerd: refuse / and a symbolic link as a socket's directory

brokerd makes a socket's directory 0700. With a socket directly in / it would
chmod /, and through a symbolic link it would change the link's target. Both
are now refused at start with #brokerd-start-failed. Without the fix the link
case started and served, with the shared directory made private.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-22 21:44:29 -07:00
co-authored by Claude Opus 5.5
parent b1afcd5734
commit ba369f82ba
3 changed files with 73 additions and 2 deletions
+45
View File
@@ -99,6 +99,51 @@ fn a_socket_directory_that_cannot_be_made_names_the_entry() {
]));
}
/// The socket's directory is made private (0700). Through a symbolic link that would change the
/// directory it points to, so a link is refused, and the target keeps its mode.
#[test]
fn a_socket_directory_that_is_a_symbolic_link_is_refused() {
use std::os::unix::fs::PermissionsExt;
let dir = TempDir::new("ptr-link");
let shared = dir.path().join("shared");
std::fs::create_dir(&shared).unwrap();
std::fs::set_permissions(&shared, std::fs::Permissions::from_mode(0o755)).unwrap();
let link = dir.path().join("link");
std::os::unix::fs::symlink(&shared, &link).unwrap();
let path = config(
&dir,
&format!("broker = \"{}\"", link.join("broker.sock").display()),
);
let out = brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
path.as_os_str(),
]);
fails_with_pointer(&out);
assert!(stderr(&out).contains("symbolic link"), "{}", stderr(&out));
let mode = std::fs::metadata(&shared).unwrap().permissions().mode() & 0o777;
assert_eq!(mode, 0o755, "the link's target keeps its mode");
}
/// A socket directly in `/` would make `/` private: refused before anything is changed.
#[test]
fn a_socket_in_the_root_directory_is_refused() {
let dir = TempDir::new("ptr-root");
let path = config(&dir, "broker = \"/broker.sock\"");
let out = brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
path.as_os_str(),
]);
fails_with_pointer(&out);
assert!(
stderr(&out).contains("directory of its own"),
"{}",
stderr(&out)
);
}
/// A config path that is not UTF-8 is still a path: it is read (here: not found), not a panic.
#[test]
fn a_config_path_that_is_not_utf8_is_read_as_a_path() {