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
+24 -2
View File
@@ -99,9 +99,18 @@ pub fn start(
/// Bind one socket: prepare its directory at 0700, make it private, remove any stale
/// socket, bind, then make the socket itself private at 0600.
fn listen(socket: &Path) -> Result<UnixListener, ServeError> {
// A socket needs a directory of its own: step 2 makes that directory 0700, which must never
// be `/` or a shared directory reached through a symbolic link.
let dir = match socket.parent() {
Some(parent) => parent.to_path_buf(),
None => PathBuf::from("/"),
Some(parent) if parent.parent().is_some() && !parent.as_os_str().is_empty() => {
parent.to_path_buf()
}
_ => {
return Err(ServeError::Dir(
PathBuf::from(socket),
io::Error::other("a socket needs a directory of its own, not / or none"),
));
}
};
// 1. The directory, at 0700.
@@ -110,6 +119,19 @@ fn listen(socket: &Path) -> Result<UnixListener, ServeError> {
.mode(0o700)
.create(&dir)
.map_err(|e| ServeError::Dir(dir.clone(), e))?;
// `set_permissions` follows a symbolic link, so a link would make the directory it points to
// private instead: refuse it.
let kind = std::fs::symlink_metadata(&dir)
.map_err(|e| ServeError::Dir(dir.clone(), e))?
.file_type();
if !kind.is_dir() {
return Err(ServeError::Dir(
dir,
io::Error::other(
"is a symbolic link or not a directory; brokerd will not change its mode",
),
));
}
// 2. Make it private, always, even when it was already there at 0755.
std::fs::set_permissions(&dir, Permissions::from_mode(0o700))
.map_err(|e| ServeError::Dir(dir.clone(), e))?;