From 5e60416c864a7d06f635161a185864fc36d5685c Mon Sep 17 00:00:00 2001 From: Aaron Rainbolt Date: Tue, 21 Jan 2025 21:05:03 -0600 Subject: [PATCH 1/2] Make permission-hardener always apply changes to real files, not symlinks --- usr/bin/permission-hardener | 32 ++++++++++++------- ...on-hardener-existing-mode-legacy-hardcoded | 4 +-- ...mission-hardener-new-mode-legacy-hardcoded | 4 +-- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/usr/bin/permission-hardener b/usr/bin/permission-hardener index 58c0797..7d5028a 100755 --- a/usr/bin/permission-hardener +++ b/usr/bin/permission-hardener @@ -168,6 +168,12 @@ line: '${processed_config_line}' log error "Existing group is empty. Stat output: '${stat_output}', line: '${processed_config_line}'" >&2 return 1 fi + + ## If a symlink was passed as input, return the original file's path rather + ## than the symlink to avoid problems stemming from using the wrong path + if [ -h "${file_name_from_stat}" ]; then + file_name_from_stat="$(realpath "${file_name_from_stat}")" + fi } print_usage(){ @@ -194,6 +200,10 @@ add_to_policy() { file_capabilities="${5:-}" updated_entry=false + if [ -h "${file_name}" ]; then + file_name="$(realpath "${file_name}")" || return 1 + fi + for (( policy_idx=0; policy_idx < ${#policy_file_list[@]}; policy_idx++ )); do if [ "${policy_file_list[policy_idx]}" = "${file_name}" ]; then policy_mode_list[policy_idx]="${file_mode}" @@ -279,7 +289,7 @@ load_early_nosuid_policy() { local new_mode new_mode='744' - add_to_policy "${find_list_item}" "${new_mode}" "${existing_owner}" \ + add_to_policy "${file_name_from_stat}" "${new_mode}" "${existing_owner}" \ "${existing_group}" done < <(safe_echo_nonewline "${target_file}" \ | find -files0-from - -perm /u=s,g=s -print0) @@ -468,7 +478,7 @@ load_state() { if [ -z "${file_name_from_stat}" ]; then continue fi - state_file_list+=( "${policy_file_item}" ) + state_file_list+=( "${file_name_from_stat}" ) state_user_owner_list+=( "${existing_owner}" ) state_group_owner_list+=( "${existing_group}" ) state_mode_list+=( "${existing_mode}" ) @@ -476,7 +486,7 @@ load_state() { echo_wrapper_audit silent dpkg-statoverride \ ${dpkg_admindir_parameter_existing_mode} \ --add "${existing_owner}" "${existing_group}" "${existing_mode}" \ - "${policy_file_item}" + "${file_name_from_stat}" done ## Fix up nosuid policies using state information @@ -557,26 +567,26 @@ commit_policy() { continue fi ## Remove and reapply in main list - if [[ "${orig_main_statoverride_db}" =~ "${state_file_item}" ]]; then + if [[ "${orig_main_statoverride_db}" =~ "${file_name_from_stat}" ]]; then echo_wrapper_ignore silent dpkg-statoverride --remove \ - "${state_file_item}" + "${file_name_from_stat}" fi echo_wrapper_audit verbose dpkg-statoverride --add --update \ "${state_user_owner_item}" "${state_group_owner_item}" \ - "${state_mode_item}" "${state_file_item}" + "${state_mode_item}" "${file_name_from_stat}" ## Update item in secondary list - if [[ "${orig_new_statoverride_db}" =~ "${state_file_item}" ]]; then + if [[ "${orig_new_statoverride_db}" =~ "${file_name_from_stat}" ]]; then # shellcheck disable=SC2086 echo_wrapper_ignore silent dpkg-statoverride \ ${dpkg_admindir_parameter_new_mode} --remove \ - "${state_file_item}" + "${file_name_from_stat}" fi # shellcheck disable=SC2086 echo_wrapper_audit verbose dpkg-statoverride \ ${dpkg_admindir_parameter_new_mode} --add \ "${state_user_owner_item}" "${state_group_owner_item}" \ - "${state_mode_item}" "${state_file_item}" + "${state_mode_item}" "${file_name_from_stat}" fi done @@ -805,7 +815,7 @@ print_fs_audit() { output_stat "${state_file_item}" if [ -z "${file_name_from_stat}" ]; then - echo "... '${state_file_item}' does not exist" + echo "... '${file_name_from_stat}' does not exist" continue fi @@ -823,7 +833,7 @@ print_fs_audit() { fi echo "^^^ ${file_name_from_stat} ${existing_owner}:${existing_group} ${existing_mode}" - echo "vvv ${state_file_item} ${state_user_owner_item}:${state_group_owner_item} ${state_mode_item}" + echo "vvv ${file_name_from_stat} ${state_user_owner_item}:${state_group_owner_item} ${state_mode_item}" else echo "*** ${file_name_from_stat} ${existing_owner}:${existing_group} ${existing_mode}" fi diff --git a/usr/share/security-misc/permission-hardener-existing-mode-legacy-hardcoded b/usr/share/security-misc/permission-hardener-existing-mode-legacy-hardcoded index e8a4bbe..7f87a45 100644 --- a/usr/share/security-misc/permission-hardener-existing-mode-legacy-hardcoded +++ b/usr/share/security-misc/permission-hardener-existing-mode-legacy-hardcoded @@ -15,7 +15,7 @@ root root 644 /etc/hosts.allow root root 700 /root root root 755 /etc/cron.daily root root 755 /bin/ping -root root 777 /etc/motd +root root 777 /etc/motd.kicksecure root root 755 /boot root root 755 /home root shadow 2755 /usr/bin/chage @@ -27,7 +27,7 @@ root root 755 /etc/permission-hardener.d root root 644 /etc/passwd root root 755 /usr/src root root 4755 /usr/bin/mount -root root 777 /etc/issue +root root 777 /etc/issue.kicksecure root root 755 /etc/cron.d root root 4755 /usr/bin/sudo root root 4755 /usr/bin/pkexec diff --git a/usr/share/security-misc/permission-hardener-new-mode-legacy-hardcoded b/usr/share/security-misc/permission-hardener-new-mode-legacy-hardcoded index 142686e..37f1088 100644 --- a/usr/share/security-misc/permission-hardener-new-mode-legacy-hardcoded +++ b/usr/share/security-misc/permission-hardener-new-mode-legacy-hardcoded @@ -9,7 +9,7 @@ root root 700 /etc/cron.weekly root root 744 /usr/bin/su root root 700 /etc/cron.daily root root 755 /bin/ping -root root 644 /etc/motd +root root 644 /etc/motd.kicksecure root _ssh 744 /usr/bin/ssh-agent root root 700 /boot root shadow 744 /usr/bin/chage @@ -20,5 +20,5 @@ root root 744 /usr/bin/chfn root root 600 /etc/permission-hardener.d root root 700 /usr/src root root 755 /usr/bin/mount -root root 644 /etc/issue +root root 644 /etc/issue.kicksecure root root 700 /etc/cron.d From 42f34f5a4ccf95d504e28a26aeb0747fef4685ba Mon Sep 17 00:00:00 2001 From: Aaron Rainbolt Date: Tue, 21 Jan 2025 21:49:03 -0600 Subject: [PATCH 2/2] Don't handle files with multiple hardlinks --- usr/bin/permission-hardener | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/usr/bin/permission-hardener b/usr/bin/permission-hardener index 7d5028a..9f70834 100755 --- a/usr/bin/permission-hardener +++ b/usr/bin/permission-hardener @@ -80,7 +80,7 @@ block_newlines() { } output_stat() { - local file_name stat_output stat_output_newlined + local file_name stat_output stat_output_newlined hardlink_count declare -a arr file_name="${1:-}" @@ -101,7 +101,7 @@ output_stat() { fi if ! stat_output="$(stat -L \ - --format="%a${delimiter}%U${delimiter}%G${delimiter}%n${delimiter}" \ + --format="%a${delimiter}%U${delimiter}%G${delimiter}%n${delimiter}%h${delimiter}" \ -- "${file_name}")"; then log error "Failed to run 'stat' on file: '${file_name}'!" >&2 return 1 @@ -145,6 +145,7 @@ line: '${processed_config_line}' existing_owner="${arr[1]}" existing_group="${arr[2]}" file_name_from_stat="${arr[3]}" + hardlink_count="${arr[4]}" if [ "$file_name" != "$file_name_from_stat" ]; then log error "\ @@ -156,6 +157,22 @@ line: '${processed_config_line}' return 1 fi + ## We can't handle files with hardlinks because figuring out all of the files + ## in a "hardlink pool" requires scanning the whole filesystem, which would + ## result in an unacceptable performance hit for this script. We don't check + ## directory hardlinks since directories can't have traditional hardlinks. + if [ ! -d "${file_name_from_stat}" ]; then + if (( hardlink_count > 1 )); then + log error "\ +File has unexpected hardlinks, cannot handle. +File name: '${file_name}' +File name from stat: '${file_name_from_stat}' +line: '${processed_config_line}' +" >&2 + return 1 + fi + fi + if [ -z "${existing_mode}" ]; then log error "Existing mode is empty. Stat output: '${stat_output}', line: '${processed_config_line}'" >&2 return 1