Repository navigation
journal_restart: seek before writing to the restarted journal - #579
Merged
Merged
Conversation
journal_seek() reads the journal with fread() up to the resume point and journal_write() then appends with fwrite() on the same "r+" stream. Without an intervening fseek() the write position is undefined; BSD and macOS stdio write at the underlying file offset left by read-ahead, corrupting the journal so it can no longer be relayed.
millert
approved these changes
Oct 23, 2026
millert
left a comment
Collaborator
There was a problem hiding this comment.
Good catch, I don't think this was tested on non-Linux systems.
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.
journal_restart()reopens an incoming relay journal withfdopen(fd, "r+")andjournal_seek()reads it withfread()up to the client's resume point. The nextjournal_write()then callsfwrite()on the same stream with nofseek()in between, which C leaves undefined. glibc happens to reposition, but BSD and macOS stdio drop the read buffer and write at the fd offset left by read-ahead: EOF for a small journal, or a block boundary in the middle of a message for a larger one. So withstore_first = true, a client that reconnects with a RestartMessage whose resume point is before the end of the journal gets its resent messages written in the wrong place.Repro on macOS with a
store_firstrelay in front of a second sudo_logsrvd:sudo_sendlog -s 3,0a 400-record session, thensudo_sendlog -i <log_id> -r 1,0. The client reports the log as transmitted, but the relay fails replaying the journal with "client message too large: 2021161080" (0x78787878, payload bytes read as a length) and nothing reaches the upstream server. With the fix the upstream ttyout matches the original byte for byte.Seek to the current position once the resume point is found, the same way
store_restart_local()already does before writing to restarted I/O log files.make checkpasses.