Repository navigation
json_append_string: compute hex escape from the unsigned byte - #559
Merged
Merged
Conversation
millert
approved these changes
Oct 8, 2026
millert
left a comment
Collaborator
There was a problem hiding this comment.
Looks good, thanks for adding a test too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
json_append_string escapes control characters as \u00XX and takes the two hex digits from hex[ch >> 4] and hex[ch & 0x0f], where ch is a plain char. The iscntrl() test above it is cast to unsigned char, so bytes with the high bit set do reach that code wherever the ctype table marks the C1 range as control characters, which macOS does in the default en_US.UTF-8 locale and glibc does in the ISO-8859-x locales. For one of those bytes ch is negative, ch >> 4 is negative too, and hex[-8] reads eight bytes before the array. The byte it picks up becomes the first hex digit, so a command, argument, user name or environment value containing 0x85 writes an adjacent stack byte into log.json instead of '8'. cvtsudoers -f json over a sudoers file holding such a byte reproduces it (ubsan reports "index -8 out of bounds for type 'const char[17]'", asan a stack-buffer-underflow in json_append_string), and sudo_logsrvd reaches the same code with strings supplied by a client. Taking both nibbles from an unsigned copy of the byte fixes it, which is what escape() in lbuf.c already does; this is the only place in the tree with the pattern. The json regress test now walks every byte value and compares the escape it gets against iscntrl().