Skip to content

Check the peer credentials when opening a remote socket#1580

Open
aplopez wants to merge 3 commits into
trifectatechfoundation:mainfrom
aplopez:socket-fix
Open

Check the peer credentials when opening a remote socket#1580
aplopez wants to merge 3 commits into
trifectatechfoundation:mainfrom
aplopez:socket-fix

Conversation

@aplopez
Copy link
Copy Markdown
Contributor

@aplopez aplopez commented May 6, 2026

The PR fixes the TOCTOU introduced with the socket reading by checking the credentials of the peer process at the other side of the socket.

The directive is now:

@socket /path/to/socket (user:%group)

These changes are introduced in the second commit. Tests and man pages are updated and a new unit test was added. Please see the commit message for more details.

The first commit makes remote sudoers 2e2 tests use the unstable-remote-sudoers feature that was previously introduced.

The third commit is an add-on to the second one. Because the second commit added an 8th parameter to the include() function, cargo clippy complains about having too many parameters. This commit is my proposition to fix this, but I'm not sure you agree with it. Basically it introduces a new IncludeContext structure where the parameters are stored and this context is passed as the second parameter (the first one being the configuration). If you agree with this solution, I will merge both commits into a single one as it is useless to have them separate.

Resolves: #1549

Copy link
Copy Markdown
Collaborator

@bjorn3 bjorn3 left a comment

Choose a reason for hiding this comment

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

I didn't review the parsing code and tests too closely.

Comment thread test-framework/sudo-test/Cargo.toml Outdated

[features]
apparmor = []
unstable-remote-sudoers = []
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

unstable-remote-sudoers is already unconditionally enabled for the sudo binary we test:

"unstable-remote-sudoers",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread docs/man/sudoers.5.md
When managing enterprise-wide sudoers rules, it is sometimes preferable to store them in a centralized repository. The @socket directive can be used to include the contents provided by a server application over a Unix domain socket. For example, providing:

@socket /var/run/providers/sudoers.socket
@socket /var/run/providers/sudoers.socket (sssd:%sssd)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Requiring a % is inconsistent with Runas_Spec.

Copy link
Copy Markdown
Contributor Author

@aplopez aplopez May 12, 2026

Choose a reason for hiding this comment

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

Oh! Sorry. I followed a limited version of Runas_Member for each component.

So far I was accepting a single user and group. Do you want to accept a Runas_List for each of them?

Also, the user was mandatory, but I see that for Runas_spec the user is optional. Should I also accept an empty user?

Comment thread src/sudoers/ast.rs Outdated
if stream.peek() != Some('\n') {
// Allow newline, '(' for @socket peer spec, or whitespace
let next = stream.peek();
if next != Some('\n') && next != Some('(') && next != Some(' ') && next != Some('\t') {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe use skip_trailing_whitespace(stream)?;? That will also handle line continuation using \.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/sudoers/mod.rs
peer_spec: Option<&'a ast::PeerSpec>,
}

fn include(cfg: &mut Sudoers, ctx: &mut IncludeContext) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IncludeContext can be passed by-value, right?

Copy link
Copy Markdown
Contributor Author

@aplopez aplopez May 12, 2026

Choose a reason for hiding this comment

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

I think it is not possible because ctx.diagnostics needs to be mutable to call push(). Do you agree?

Comment thread src/system/audit.rs Outdated
uid: 0,
gid: 0,
};
let mut ucred_size = std::mem::size_of::<UserCreds>() as libc::socklen_t;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe size_of is already in the prelude with rust 1.85.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You are absolutely right. I missed that.

Comment thread src/system/audit.rs Outdated
libc::SO_PEERCRED,
&mut ucred as *mut _ as *mut libc::c_void,
&mut ucred_size,
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe do unsafe { cerr(libc::getsockopt(...))?; }?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/system/audit.rs Outdated
pid: libc::pid_t,
uid: libc::uid_t,
gid: libc::gid_t,
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

libc::ucred can be used instead, right? There is no guarantee that every target we will support uses this exact layout.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right!

Comment thread src/system/audit.rs Outdated
Comment on lines +121 to +124
// SAFETY:
// For the moment we use getsockopt() from libc passing a pointer to the
// correct C structure. Data is written to this structure.
// In the future this will be replaced by UnixStream::peer_cred()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// SAFETY:
// For the moment we use getsockopt() from libc passing a pointer to the
// correct C structure. Data is written to this structure.
// In the future this will be replaced by UnixStream::peer_cred()
// SAFETY: An out pointer for the correct type and length are passed.
// FIXME use UnixStream::peer_cred() once stable in our MSRV.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

aplopez added 3 commits May 12, 2026 15:08
This feature was introduced not long ago and needs to be applied also for the e2e socket tests.
The directive @socket now takes the expect user and possibly group
that the peer at the other en of the socket must be running as.
This information must follow the socket path and be enclosed in
parentheses:

   @socket /path/to/socket (user:%group)

Non-posix groups are not accepted (%:). Numeric values are accepted
preceded by #.

Existing tests where updated and a new unit test was added fori the
parsing.

Man pages were also updated.
The previous commit added an 8th paramters to include(). To reduce
this number, an IncludeContext structure was created and used to
pass only two parameters to the function (the configuration and
this structure with all the other parameters).
@aplopez aplopez changed the title Socket fix Check the peer credentials when opening a remote socket May 13, 2026
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.

@socket implementation security review

2 participants