Visitar URL original
device-nodes: always NUL-terminate encode_devnode_name() output by naruto-lgtm · Pull Request #44424 · systemd/systemd · GitHub
Skip to content

device-nodes: always NUL-terminate encode_devnode_name() output - #44424

Merged
bluca merged 1 commit into
systemd:mainfrom
naruto-lgtm:devnode-encode-nul-terminate
Nov 1, 2026
Merged

bluca merged 1 commit into
systemd:mainfrom
naruto-lgtm:devnode-encode-nul-terminate

Conversation

@naruto-lgtm

Copy link
Copy Markdown
Contributor

Repro: a USB device whose product string is 85 x U+4E00 followed by one ASCII letter fills the 256-byte model_str_enc buffer in usb_id exactly, and udevd then strdup()s ID_MODEL_ENC past the end of the stack array. A standalone ASan harness reports a 257-byte read from a 256-byte buffer, and the new test case fails on the current code.
Cause: encode_devnode_name() returns -EINVAL without writing the terminating NUL when the output does not fit, while usb_id, ata_id and scsi_id ignore the return value and export the buffer as a property. Adjacent stack bytes end up in ID_MODEL_ENC/ID_USB_MODEL_ENC, which unprivileged users can read with udevadm info.
Fix: reserve room for the NUL in every length check and terminate the truncated output on failure, so all callers get a valid string without each one having to handle the error. Output for strings that fit is unchanged.

@github-actions github-actions Bot added the please-review PR is ready for (re-)review by a maintainer label Oct 27, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Reviewed 9004056 (architecture, correctness, lifetimes, security, style, tests). No new issues found, 2 still open.

Suggestions

  • src/test/test-device-nodes.c:54 No success case ends with a multi-byte sequence exactly at the buffer end, so the < → <= seqlen check isn't pinned down; an over-strict off-by-one would still pass. Add e.g. ASSERT_OK(encode_devnode_name("ab一", buf, 6)); ASSERT_STREQ(buf, "ab一");.

Nits

  • src/test/test-device-nodes.c:40 The new len == 0 guard is untested, yet it is what keeps the truncated: path from writing str_enc[0] into a zero-sized buffer. Add a len = 0 case (EINVAL, buffer untouched) and a len = 1 case (EINVAL, empty string).

Workflow run


memset(buf, 'X', sizeof(buf));
ASSERT_OK(encode_devnode_name("abcdefg", buf, sizeof(buf)));
ASSERT_STREQ(buf, "abcdefg");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude: suggestion: No success case ends with a multi-byte sequence exactly at the buffer end, so the < → <= seqlen check isn't pinned down; an over-strict off-by-one would still pass. Add e.g. ASSERT_OK(encode_devnode_name("ab一", buf, 6)); ASSERT_STREQ(buf, "ab一");.

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 as a success case with len 6.

char buf[8];

/* On truncation the output must still be NUL terminated, and only contain complete sequences */
memset(buf, 'X', sizeof(buf));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude: nit: The new len == 0 guard is untested, yet it is what keeps the truncated: path from writing str_enc[0] into a zero-sized buffer. Add a len = 0 case (EINVAL, buffer untouched) and a len = 1 case (EINVAL, empty string).

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 both the len 0 and len 1 cases.

@yuwata

yuwata commented Oct 30, 2026

Copy link
Copy Markdown
Member

Please do not stack fix, but squash.

@yuwata yuwata added reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks and removed please-review PR is ready for (re-)review by a maintainer labels Oct 30, 2026
@naruto-lgtm
naruto-lgtm force-pushed the devnode-encode-nul-terminate branch from 20bf1cd to 13a6842 Compare October 30, 2026 06:28
@naruto-lgtm

Copy link
Copy Markdown
Contributor Author

Squashed into a single commit, content unchanged.

@yuwata

yuwata commented Oct 30, 2026

Copy link
Copy Markdown
Member

Please also address suggestions by Claude.

When the encoded string does not fit, encode_devnode_name() returned
-EINVAL without terminating the output buffer. The callers in usb_id,
ata_id and scsi_id ignore the return value and add the buffer as a
property. With a USB product or manufacturer string that fills the
256-byte buffer in usb_id exactly (e.g. 85 three-byte UTF-8 characters
followed by one ASCII letter) udevd then reads past the end of the stack
array and copies adjacent stack bytes into ID_MODEL_ENC/ID_VENDOR_ENC.

Leave room for the NUL in each length check and terminate the truncated
output on failure. Output for strings that fit is unchanged.
@naruto-lgtm
naruto-lgtm force-pushed the devnode-encode-nul-terminate branch from 13a6842 to 9004056 Compare October 31, 2026 06:07
@github-actions github-actions Bot added please-review PR is ready for (re-)review by a maintainer and removed reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Oct 31, 2026
@naruto-lgtm

Copy link
Copy Markdown
Contributor Author

Added both: a success case with a multi-byte sequence ending right before the NUL ("ab一" into 6 bytes), and the len 0 / len 1 cases (EINVAL with the buffer untouched, EINVAL with an empty string). Squashed into the single commit, no change to the fix itself.

@poettering poettering added good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed and removed please-review PR is ready for (re-)review by a maintainer labels Oct 31, 2026
@bluca
bluca merged commit b2501ee into systemd:main Nov 1, 2026
70 of 89 checks passed
@github-actions github-actions Bot removed the good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed label Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

4 participants