File cleanoldsepoldir.sh of Package selinux-policy
#!/bin/bash
#set -x
# Function to check overlayfs directory and snapper
check_overlayfs() {
local overlayfs_dir="/var/lib/overlay"
local overlay_numbers="0"
local snapper_path=`command -v snapper`
#local tu_system=`grep micro /etc/issue`
local tu_path=`command -v transactional-update`
if [ -e /etc/selinux/${target_file} ]; then
if [ -x $snapper_path ]; then
if [[ -n ${tu_path} ]]; then
tu_version=`transactional-update --version | grep -oe "transactional-update ."`
if [ "${tu_version##*[!0-9]}" -lt "5" ]; then
echo "INFO: Detected t-u version <5.0, fallback to overlayfs."
overlayfs_fallback=true
if [ ! -d $overlayfs_dir ]; then
echo "INFO: Overlayfs directory does not exist, skipping."
#exit 0
fi
else
echo "INFO: Detected t-u version <5.0."
fi
else
echo "INFO: Detected non-transactional system."
fi
#overlay_layers=`ls -rd ${overlayfs_dir}/*| grep -oE '[0-9]+'`
overlay_layers=`/usr/bin/snapper --no-headers --machine-readable csv list | awk -F , '$3+0>=1 {print $3}'`
else
echo "ERROR: no snapper found on the system."
exit 1
fi
else
echo "ERROR: ${target_file} does not exists on the filesystem. Exiting."
exit 1
fi
}
# Function to check if a file exists in a given overlay layer
check_overlay_layer() {
local layer_number="$1"
local filename="$2"
local overlayfs_fallback="${3:-false}"
local base_overlay_path="/.snapshots/${layer_number}/snapshot"
# echo "-$base_overlay_path"
if "$overlayfs_fallback" ; then
# echo "promnnena $overlayfs_fallback"
local base_overlay_path="/var/lib/overlay/${layer_number}"
fi
local full_path="$base_overlay_path/etc/selinux/$filename"
#local full_path="$base_overlay_path/$layer_number/snapshot/etc/selinux/$filename"
# echo "+$base_overlay_path"
if [ -e "$full_path" ]; then
echo " Found: $full_path in layer $layer_number"
return 0 # File exists
else
echo " Not found: $full_path in layer $layer_number"
return 1 # File does not exist
fi
}
# Function to print out custom selinux policy modules in /var/lib/selinux
check_custom_selinux_modules () {
echo "INFO: Checking for possibly not migrated custom selinux modules in /var/lib/selinux/..."
local old_selinux_dir="/var/lib/selinux"
local new_selinux_dir="/etc/selinux"
local custom_package_dir="/usr/share/selinux/packages" # Ensure this is correct
# Collect all module directories and their basenames exept base "100"
# Collect all 'active' module directories from old_selinux_dir
local old_modules=()
for i in minimum sandbox targeted; do
if [ -d "${old_selinux_dir}/${i}/active/modules" ]; then
mapfile -t current_modules < <(find "${old_selinux_dir}/${i}/active/modules/" -maxdepth 2 -type d '!' -empty | grep -vE '/(modules/|100|200|400|disabled)$')
#mapfile -t current_modules < <(find "${old_selinux_dir}/${i}/active/modules/" -maxdepth 2 -type d '!' -empty |grep -vE '/100/' | grep -vE '/(modules/|100|200|400|disabled)$')
old_modules+=("${current_modules[@]}")
fi
done
# Sort and unique the old_modules basenames
IFS=$'\n' read -r -d '' -a old_modules_unique < <(printf "%s\n" "${old_modules[@]}" | sort -u && printf '\0')
# Collect all 'active' module directories from new_selinux_dir
local new_modules=()
for i in minimum sandbox targeted; do
if [ -d "${new_selinux_dir}/${i}/active/modules" ]; then
mapfile -t current_modules < <(find "${new_selinux_dir}/${i}/active/modules/" -maxdepth 2 -type d '!' -empty | grep -vE '/(modules/100|200|400|disabled)$')
new_modules+=("${current_modules[@]}")
fi
done
# Sort and unique the new_modules basenames
IFS=$'\n' read -r -d '' -a new_modules_unique < <(printf "%s\n" "${new_modules[@]}" | sort -u && printf '\0')
local custom_modules=()
if [ -d "${custom_package_dir}" ]; then
mapfile -t current_modules < <(find "${custom_package_dir}" -maxdepth 2 -type f '!' -empty)
custom_modules+=("${current_modules[@]}")
fi
# Sort and unique the new_modules basenames
IFS=$'\n' read -r -d '' -a custom_modules_unique < <(printf "%s\n" "${custom_modules[@]}" | sort -u && printf '\0')
local missing_modules=()
local modules_with_packages=()
local modules_without_packages=()
# Compare old_modules_unique with new_modules_unique
local -A new_modules_unique_basename
for new_module_name in "${new_modules_unique[@]}"; do
local new_module_name_basename=$(basename "$new_module_name")
new_modules_unique_basename["$new_module_name_basename"]=1
done
for old_module_name in "${old_modules_unique[@]}"; do
local old_module_name_basename=$(basename "$old_module_name")
if [[ -z "${new_modules_unique_basename[$old_module_name_basename]}" ]]; then
missing_modules+=("$old_module_name_basename (module dir: $old_module_name)")
fi
done
# for old_module_name in "${old_modules_unique[@]}"; do
# echo " $old_module_name"
# local old_module_name_basename=$(basename "${old_module_name}")
# local found_in_new="false"
# # Check if old_module_name exists in new_modules_unique
# # Using a loop or 'printf "%s\n" ... | grep -Fxq ...' is more robust than =~
# for new_module_name in "${new_modules_unique[@]}"; do
# local new_module_name_basename=$(basename "${new_module_name}")
# if [ "$old_module_name_basename" == "$new_module_name_basename" ]; then
# found_in_new="true"
# break
# fi
# done
#
# if [ "$found_in_new" == "false" ]; then
# missing_modules+=("$old_module_name_basename (module dir: $old_module_name)")
# fi
# done
# Now, process the missing modules to determine if they have packages
if [ ${#missing_modules[@]} -eq 0 ]; then
echo "INFO: No custom modules found missing from /etc/selinux."
else
echo "INFO: Found possible missing custom selinux modules:"
for module_name in "${missing_modules[@]}"; do
local package_found="false"
# Check for files like module_name.pp under custom_package_dir/module_name/
# Search for any file inside that directory, indicating it was part of a custom package structure
for custom_module_name in "${custom_modules[@]}"; do
local short_module_name=$(basename "${module_name##*/}")
local module_basename="${short_module_name%)}"
if [[ ${custom_module_name} =~ ${module_basename}.pp.(bz2|gz) ]]; then
# Get RPM name that owns this file
local rpm_query_name=$(rpm -qf --queryformat "%{NAME}" "${custom_module_name}" 2>/dev/null)
if [[ -n "$rpm_query_name" ]]; then
modules_with_packages+=("$module_name (from package: $rpm_query_name)")
package_found="true"
fi
fi
done
if [ "$package_found" == "false" ]; then
modules_without_packages+=("$module_name")
fi
done
echo "---"
echo "These modules have corresponding packages (if file belongs to any), try to reinstall them:"
if [ ${#modules_with_packages[@]} -eq 0 ]; then
echo " (None)"
else
printf " * %s\n" "${modules_with_packages[@]}"
fi
echo "These modules do not have coresponding packages available."
echo " Modules in \`200 or 400 or disabled\` directory could require manual intervention," \
"if you did not install these or you believe there is an error, please open a bug:"
echo " Modules in \`*/modules/100/*\` directory are in base policy and can be ignored."
if [ ${#modules_without_packages[@]} -eq 0 ]; then
echo " (None)"
else
printf " * %s\n" "${modules_without_packages[@]}"
fi
echo "---"
echo "INFO: To manually check it again run /usr/libexec/selinux/cleanoldsepoldir.sh --check-custom-selinux-modules"
fi
echo
}
## Main function
# Definitions
# Variables
target_file_dir="/etc/selinux"
target_file="${1:-tmpselipoldir_migrated}"
first_layer_with_file=0
custom_package_dir="/usr/share/selinux/packages"
# Script parameters
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
echo "This script is part of tools used to check if it is safe to remove old selinux directory /var/lib/selinux"
echo "Usage: $0 -h|--help, -f $target_file, --check-custom-selinux-modules"
exit 0
;;
-f|--file)
shift
target_file="$1"
;;
--check-custom-selinux-modules)
check_custom_selinux_modules
exit 0
;;
*)
echo "Wrong param: $1, use -h for help"
exit 1
esac
shift
done
# variables
target_file_dir="/etc/selinux"
target_file="${target_file:-tmpselipoldir_created}"
first_layer_with_file=0
if [ $TRANSACTIONAL_UPDATE ];then
echo "INFO: Cannot run in transactional-shell, skipping."
exit 0;
fi
check_overlayfs
[ -n "$overlay_layers" ] && echo "Checking for file: ${target_file_dir}/${target_file}"
for i in $(echo ${overlay_layers} | awk '{ for(i=NF;i>0;i--) printf "%s ", $i }'); do
first_layer="$i"
shift 1 # Remove the lower and upper numbers from the arguments
check_overlay_layer "$first_layer" "$target_file"
return_value=$?
if (( $return_value == 0 )); then
first_layer_with_file=$i
fi
if [ "$overlayfs_fallback" ]; then
check_overlay_layer "$first_layer" "$target_file" "$overlayfs_fallback"
echo
fi
done
# check if all snapshots have ${target_file}
# !!! TODO - FIX issue on TW, all snapshots has to have tmpselipoldir_created before deleting /var/lib
if [[ ${#summary_not_found_array[@]} -eq 0 ]]; then
if (( $first_layer == $first_layer_with_file )); then
echo "INFO: Lowest numbered layer matches first numbered layer with file, deleting /var/lib/selinux."
echo "DEBUG: these files would be normally deleted | head."
find /var/lib/selinux -type d -print | head -10 #-delete
if [[ -f %{_sysconfdir}/selinux/tmpselipoldir_migrated ]]; then
rm /etc/selinux/tmpselipoldir_migrated
echo "DO NOT DELETE THIS FILE - Part of SELinux policy migration" > %{_sysconfdir}/selinux/tmpselipoldir_deleted
fi
fi
else
echo "INFO: Layer without $target_file exists," \
"that means older snapshot expecting selinux policy in /var/lib/selinux" \
"therefore not deleting /var/lib/selinux."
fi
exit 0