Skip to content

expand_iolog_path: don't pass escape values to strftime - #577

Merged
millert merged 2 commits into
sudo-project:mainfrom
iefa-m:iolog-path-escape-percent
Oct 27, 2026
Merged

millert merged 2 commits into
sudo-project:mainfrom
iefa-m:iolog-path-escape-percent

Conversation

@iefa-m

@iefa-m iefa-m commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

expand_iolog_path() copies the %{user}, %{group}, %{runas_user}, %{runas_group}, %{hostname} and %{command} values into the path and then, if iolog_dir or iolog_file uses any strftime escape, passes the whole buffer to strftime(3). A % inside a substituted value is therefore treated as a conversion. In sudo_logsrvd those values come straight from the client's AcceptMessage, so with iolog_dir = /var/log/sudo-io/%{user}/%Y a submituser of %D lands in /var/log/sudo-io/10/22/26/2026. That puts back the / characters that strlcpy_no_slash() just replaced, which the sudoers and sudo_logsrvd.conf manuals promise doesn't happen, and lets the client pick extra directory levels (%n and %t add control characters too). A literal %% in the configured path had a related problem: it was collapsed before strftime ran, so %%Y_%Y became 2026_2026.

The fix doubles any % in each substituted value and keeps %% as-is while expanding. strftime then collapses it, or a small loop does when the path has no strftime escapes, so paths without a % in them come out the same as before. The fix sits in expand_iolog_path() because the sudoers plugin and sudo_logsrvd both use it with their own escape tables. The iolog_path regress data gains cases for a % in a user name and command, a % value with no strftime escapes, and %% next to a strftime escape. The first and third fail before this change, and make check passes after it.

The %{user}, %{group}, %{runas_user}, %{runas_group}, %{hostname}
and %{command} values are copied into the path before it is run
through strftime(3), so a '%' in one of them was treated as a
conversion.  In sudo_logsrvd these come from the client, and a
submituser of "%D" expands to "10/22/26", re-introducing the '/'
that strlcpy_no_slash() replaced.  A literal "%%" in iolog_dir or
iolog_file was also collapsed before strftime(3) saw it.

Double any '%' in substituted values and leave "%%" alone during
expansion, collapsing it afterwards via strftime(3) or by hand.
Comment thread lib/iolog/iolog_path.c Outdated

/* Shift right from the end, duplicating each '%'. */
for (i = len, n = nesc; n > 0; ) {
i--;

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.

While it is not currently possible for the i-- to underflow I'd still prefer a check. Something like:

if (i-- == 0)
    debug_return_size_t((size_t)-1);

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.

Added that check in d6e1f43, so escape_percent now returns (size_t)-1 rather than decrementing i past zero. The iolog regress tests still pass.

@millert
millert merged commit 265e10a into sudo-project:main Oct 27, 2026
5 checks passed
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