Skip to content

Use Linux abstract socket namespace for OsIpcOneShotServer, avoid requiring a writable temp directory - #456

Open
miruji wants to merge 3 commits into
servo:mainfrom
miruji:add/linux-abstract-ns
Open

miruji wants to merge 3 commits into
servo:mainfrom
miruji:add/linux-abstract-ns

Conversation

@miruji

@miruji miruji commented Sep 26, 2026

Copy link
Copy Markdown

OsIpcOneShotServer::new() currently requires a writable temp directory (via tempfile::Builder::tempdir()) purely to obtain a filesystem path for the bootstrap unix socket.

On Linux, this is unnecessary: the abstract socket namespace lets us bind/connect without touching the filesystem at all.

This PR switches the one-shot server to an abstract-namespace address on Linux only.

Non-Linux platforms are untouched (#[cfg(not(target_os = "linux"))] keeps the original tempdir-based path).

The public API is unchanged — the returned "name" is still an opaque String handed to connect(), exactly as documented; nothing about its format was ever part of the contract.

Motivation: in containers/sandboxes where /tmp is read-only or otherwise unwritable, tempdir() fails with a PermissionDenied-style io::Error that carries no raw_os_error() (it's wrapped by tempfile in a PathError).

That trips the assert!(e.kind() == ConnectionReset) in From<io::Error> for UnixError, causing a hard panic instead of a recoverable error — this happens today for any consumer bootstrapping via IpcOneShotServer in such an environment.

This PR removes the precondition entirely rather than handling the error more gracefully.

Comment thread src/platform/unix/mod.rs Outdated
/// other name goes through the regular filesystem-backed encoding.
unsafe fn build_sockaddr(name: &str) -> Result<(sockaddr_un, usize), UnixError> {
#[cfg(target_os = "linux")]
if let Some(abstract_name) = name.strip_prefix('@') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On linux, how can abstract_name starts with anything other than @? If so, what's the point of the @ prefix convention?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. To clarify:

build_sockaddr is intentionally a generic utility rather than something coupled to OsIpcOneShotServer::new() / make_abstract_name(). The current PR is the only caller, and yes, on Linux it currently always passes @-prefixed names.

The @ prefix is simply the user-space convention used here to distinguish abstract socket names from filesystem-backed paths:

  • @name → Linux abstract namespace
  • name → regular filesystem-backed socket

This convention is also commonly used by tools such as systemd, socat, and ss to represent abstract sockets; it corresponds to sun_path[0] == 0.

On non-Linux platforms, names go through the existing filesystem-path encoding unchanged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Some developers regard dead code as technical debt. Maybe a comment in the code is warranted, but I won't insist.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@miruji Please note that I am not a maintainer of this project, so I defer to maintainers to set coding standards etc. However, should you wish to adopt my suggestion to remove the technical debt, the steps are to:

  1. Not prefix the path returned from make_abstract_name with @ (e.g. change format!("@ipc-osn-{hex}") to format!("ipc-osn-{hex}")).
  2. Change the linux code in build_sockaddr to use name (rather than abstract_name) and delete the test for the @ prefix. (You may wish to replace the if statement with a {} block so it can be compiled for linux only.)
  3. Fix up the comments to match the above changes.

So, on Linux, build_sockaddr is passed the return value of make_abstract_name without the prefix @ convention.

Note: since I am not a maintainer, I cannot approve/merge this PR, but hopefully someone else will.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glyn

I’ve made the changes you pointed out.

And don’t worry, I understand that you’re not a maintainer. I just wanted to say that I really do take your feedback into account.

If I were doing this for myself, I would probably do quite a few things differently. So it’s completely fine that we’re adapting the code to fit the project.

As a contributor, you have every right to review the PR and suggest changes, which is exactly what you did, and I appreciate that.

I left all three commits separate so that the development process is visible. When merging into the main branch, they should be squashed into a single commit to keep the history clean.

I’ve tested it again, and everything works perfectly without any further changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Those changes look good to me.

Comment thread src/platform/unix/mod.rs
Comment on lines +112 to +114
for (i, b) in bytes.iter().enumerate() {
sockaddr.sun_path[i + 1] = *b as c_char;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://www.man7.org/linux/man-pages/man2/connect.2.html, sun_path is a null-terminated string for AF_UNIX sockets (at least for portable programs), so adding bytes after the null seems strange.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. The null-termination requirement in connect(2) applies to pathname sockets. For abstract sockets, man 7 unix (https://man7.org/linux/man-pages/man7/unix.7.html) says they are distinguished by sun_path[0] being a null byte, and the address is given by the additional bytes covered by the address length.

So here sun_path[0] is a marker, not a terminator: the kernel reads the name using addrlen (sizeof(sa_family_t) + 1 + name.len()), not strlen. The branch is gated by #[cfg(target_os = "linux")], so other platforms never reach it.

I added comments explaining this in e75cee3.

@glyn glyn left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the latest changes. Looks good to me. (It seems I can approve after all.)

@miruji

miruji commented Sep 30, 2026

Copy link
Copy Markdown
Author

Yes, I also just mentioned this in my chillffi framework, where I originally discovered this issue.

I did this now so that it is already fixed on my side while this is still being accepted here.

And also because I have quite a lot of tests on Linux, macOS, and Windows, and my FFI is very heavily tied to ipc-channel.

I mean this to say that everything works for me. This is just additional confirmation that nothing has been broken.

I also checked this in those limited environments I mentioned, and there is no issue there either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants