Skip to content

Security hardening: fix buffer handling and input validation#356

Closed
assisted-by-ai wants to merge 0 commit intoKicksecure:masterfrom
assisted-by-ai:claude/security-audit-kxcfa
Closed

Security hardening: fix buffer handling and input validation#356
assisted-by-ai wants to merge 0 commit intoKicksecure:masterfrom
assisted-by-ai:claude/security-audit-kxcfa

Conversation

@assisted-by-ai
Copy link
Copy Markdown

This PR addresses multiple security issues and improves robustness across the security-misc codebase.

Summary

Multiple security vulnerabilities and edge cases have been fixed, including buffer handling issues, input validation problems, and unsafe string operations. Additionally, several defensive programming improvements have been made to prevent potential exploitation vectors.

Key Changes

Buffer and String Handling:

  • Fixed print() function to not include null terminator in write length calculation, preventing off-by-one errors
  • Added NUL-termination guarantee for netlink message buffers to prevent out-of-bounds reads in hw_monitor()
  • Replaced unsafe strlen() calls with strnlen() to prevent reading past buffer boundaries when processing truncated netlink messages
  • Fixed FIFO creation permissions from overly permissive 0777 to restrictive 0600

Input Validation:

  • Added null pointer check for timeout value in fifo_monitor() to prevent null dereference
  • Added PAM_USER validation in pam-info to reject control characters and option injection attempts
  • Fixed strtok() call to use correct separator variable instead of hardcoded comma

Regex Pattern Matching:

  • Anchored user/group lookups in permission-hardener to line boundaries to prevent substring matches (e.g., 'roo' matching 'root')
  • Anchored file path matches in dpkg-statoverride checks to prevent partial path matches

Build Process:

  • Implemented atomic compilation for fm-shim-backend by writing to temporary file first, then moving into place to prevent corrupted binaries on interrupted builds

Code Quality:

  • Added exit(0) after kill_system() call for clarity
  • Disabled debug output (set -x) in pam_faillock_not_if_x to prevent leaking authentication details to system logs
  • Added threat model documentation for root-owned configuration file sourcing
  • Improved postinst error handling documentation to clarify intentional non-fatal error behavior

Notable Implementation Details

  • The netlink buffer fix uses strnlen() with the remaining buffer length to safely determine entry length without reading past boundaries
  • Regex anchoring uses $'\n' syntax to match line boundaries and prevent substring matches in multi-line strings
  • Atomic file operations prevent leaving corrupted binaries if the build process is interrupted

https://claude.ai/code/session_01LvyeXrhG1t4pNmiHt7iAbi

Copy link
Copy Markdown
Contributor

@ArrayBolt3 ArrayBolt3 left a comment

Choose a reason for hiding this comment

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

Mostly integrated in ArrayBolt3@3b3b586. Notes below.

Comment on lines +33 to +35
## By design: report error but return 0 to avoid breaking APT.
## A failing postinst would leave the package in a broken state,
## preventing upgrades and further security updates.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Useful, but not quite accurate. Will adjust and add.

Comment on lines +196 to +198
## By design: report error but do not fail to avoid breaking APT.
## A failing postinst would leave the package in a broken state,
## preventing upgrades and further security updates.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not useful, this is a common pattern in many of our postinst scripts and adding this comment to all of them would be undesirable. It should be obvious to someone familiar with postinst scripts what is happening here.

Comment on lines +598 to +600
if ! [[ "${passwd_file_contents}" =~ "${state_user_owner_item}:" ]]; then
## Anchor user/group lookups to line boundaries to prevent substring matches
## (e.g. 'roo' must not match 'root:...')
if ! [[ $'\n'"${passwd_file_contents}" =~ $'\n'"${state_user_owner_item}:" ]]; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Useful, will add.

Comment on lines +603 to +605
if ! [[ "${group_file_contents}" =~ "${state_group_owner_item}:" ]]; then
if ! [[ $'\n'"${group_file_contents}" =~ $'\n'"${state_group_owner_item}:" ]]; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added.

Comment on lines +608 to +611
if [[ "${orig_main_statoverride_db}" =~ "${file_name_from_stat}" ]]; then
## Anchor to line boundary to prevent substring path matches
if [[ $'\n'"${orig_main_statoverride_db}" =~ [[:space:]]"${file_name_from_stat}"($'\n'|$) ]]; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Concept is good, anchoring is slightly more complex than it needs to be though. Adding with tweaks.

Comment on lines +834 to +836
/* Ensure buffer is NUL-terminated to prevent out-of-bounds reads
* from strlen/strcmp on truncated netlink messages. */
buf[sizeof(buf) - 1] = '\0';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added. Also started explicitly initializing buf.

if (paranoid_mode) {
/* Something was removed, we don't care what, shut down now */
kill_system();
exit(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Moved exit(0) into kill_system() itself.

Comment on lines +913 to +918
len = len - (ssize_t)(strlen(tmpbuf) + 1);
tmpbuf += strlen(tmpbuf) + 1;
{
size_t entry_len = strnlen(tmpbuf, (size_t)len) + 1;
len -= (ssize_t)entry_len;
tmpbuf += entry_len;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

strnlen() isn't necessary here because the buffer is NUL-terminated after we read the netlink message. Reducing the number of times we compute that length is good though, so added with tweaks.

Comment on lines +959 to +963
if (arg_part == NULL) {
print(fd_stderr, "Timeout value is missing!\n");
print_usage();
exit(1);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added.

Comment on lines +978 to +987
if (mkfifo(trigger_fifo_path, 0777) == -1) {
if (mkfifo(trigger_fifo_path, 0600) == -1) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added.

@assisted-by-ai assisted-by-ai force-pushed the claude/security-audit-kxcfa branch from 12ac703 to 232b01e Compare April 10, 2026 10:56
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