mirror of
https://github.com/SELinuxProject/selinux
synced 2024-12-26 07:52:07 +00:00
26a4c19ecf
I can't think of a good reason why they should be excluded. On the contrary, excluding them can cause trouble very easily if some labeling rules for these directories change. For example, we changed the label for /dev/nvme* from nvme_device_t to fixed_disk_device_t in Fedora (updating the allow rules accordingly) and after policy update they ended up with an invalid context, causing denials. Thus, remove /dev and /run from the excludes. While there, also add /root to the basic excludes to match the regex that excludes fc rules (that should be effectively no functional change). I did a sanity check on my system by running `restorecon -nv /dev /run` and it didn't report any label differences. Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> Acked-by: Petr Lautrbach <plautrba@redhat.com>
438 lines
11 KiB
Bash
Executable File
438 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
# fixfiles
|
|
#
|
|
# Script to restore labels on a SELinux box
|
|
#
|
|
# Copyright (C) 2004-2013 Red Hat, Inc.
|
|
# Authors: Dan Walsh <dwalsh@redhat.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
set -o nounset
|
|
|
|
#
|
|
# seclabel support was added in 2.6.30. This function will return a positive
|
|
# number if the current kernel version is greater than 2.6.30, a negative
|
|
# number if the current is less than 2.6.30 and 0 if they are the same.
|
|
#
|
|
function useseclabel {
|
|
VER=`uname -r`
|
|
SUP=2.6.30
|
|
expr '(' "$VER" : '\([^.]*\)' ')' '-' '(' "$SUP" : '\([^.]*\)' ')' '|' \
|
|
'(' "$VER.0" : '[^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0" : '[^.]*[.]\([^.]*\)' ')' '|' \
|
|
'(' "$VER.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')' '-' '(' "$SUP.0.0" : '[^.]*[.][^.]*[.]\([^.]*\)' ')'
|
|
}
|
|
|
|
#
|
|
# Get all mount points that support labeling. Use the 'seclabel' field if it
|
|
# is available. Else fall back to known fs types which likely support xattrs
|
|
# and we know were not context mounted.
|
|
#
|
|
get_all_labeled_mounts() {
|
|
FS="`cat /proc/self/mounts | sort | uniq | awk '{print $2}'`"
|
|
for i in $FS; do
|
|
if [ `useseclabel` -ge 0 ]
|
|
then
|
|
grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)seclabel(,|$)' && echo $i
|
|
else
|
|
grep " $i " /proc/self/mounts | grep -v "context=" | egrep --silent '(ext[234]| ext4dev | gfs2 | xfs | jfs | btrfs )' && echo $i
|
|
fi
|
|
done
|
|
}
|
|
|
|
get_rw_labeled_mounts() {
|
|
FS=`get_all_labeled_mounts | sort | uniq`
|
|
for i in $FS; do
|
|
grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)rw(,|$)' && echo $i
|
|
done
|
|
}
|
|
|
|
get_ro_labeled_mounts() {
|
|
FS=`get_all_labeled_mounts | sort | uniq`
|
|
for i in $FS; do
|
|
grep " $i " /proc/self/mounts | awk '{print $4}' | egrep --silent '(^|,)ro(,|$)' && echo $i
|
|
done
|
|
}
|
|
|
|
#
|
|
# Get the default label returned from the kernel for a file with a label the
|
|
# kernel does not understand
|
|
#
|
|
get_undefined_type() {
|
|
SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'`
|
|
cat ${SELINUXMNT}/initial_contexts/unlabeled | secon -t
|
|
}
|
|
|
|
#
|
|
# Get the default label for a file without a label
|
|
#
|
|
get_unlabeled_type() {
|
|
SELINUXMNT=`grep selinuxfs /proc/self/mountinfo | head -1 | awk '{ print $5 }'`
|
|
cat $SELINUXMNT/initial_contexts/file | secon -t
|
|
}
|
|
|
|
exclude_dirs_from_relabelling() {
|
|
exclude_from_relabelling=
|
|
if [ -e /etc/selinux/fixfiles_exclude_dirs ]
|
|
then
|
|
while read i
|
|
do
|
|
# skip blank line and comment
|
|
# skip not absolute path
|
|
# skip not directory
|
|
[ -z "${i}" ] && continue
|
|
[[ "${i}" =~ ^[[:blank:]]*# ]] && continue
|
|
[[ ! "${i}" =~ ^/.* ]] && continue
|
|
[[ ! -d "${i}" ]] && continue
|
|
exclude_from_relabelling="$exclude_from_relabelling -e $i"
|
|
done < /etc/selinux/fixfiles_exclude_dirs
|
|
fi
|
|
echo "$exclude_from_relabelling"
|
|
}
|
|
|
|
#
|
|
# Set global Variables
|
|
#
|
|
fullFlag=0
|
|
BOOTTIME=""
|
|
VERBOSE="-p"
|
|
FORCEFLAG=""
|
|
RPMFILES=""
|
|
PREFC=""
|
|
RESTORE_MODE=""
|
|
BIND_MOUNT_FILESYSTEMS=""
|
|
SETFILES=/sbin/setfiles
|
|
RESTORECON=/sbin/restorecon
|
|
FILESYSTEMSRW=`get_rw_labeled_mounts`
|
|
FILESYSTEMSRO=`get_ro_labeled_mounts`
|
|
SELINUXTYPE="targeted"
|
|
if [ -e /etc/selinux/config ]; then
|
|
. /etc/selinux/config
|
|
FC=/etc/selinux/${SELINUXTYPE}/contexts/files/file_contexts
|
|
else
|
|
FC=/etc/security/selinux/file_contexts
|
|
fi
|
|
|
|
#
|
|
# Log all Read Only file systems
|
|
#
|
|
LogReadOnly() {
|
|
if [ ! -z "$FILESYSTEMSRO" ]; then
|
|
echo "Warning: Skipping the following R/O filesystems:"
|
|
echo "$FILESYSTEMSRO"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Log directories excluded from relabelling by configuration file
|
|
#
|
|
LogExcluded() {
|
|
for i in ${EXCLUDEDIRS//-e / }; do
|
|
echo "skipping the directory $i"
|
|
done
|
|
}
|
|
|
|
#
|
|
# Find files newer then the passed in date and fix the label
|
|
#
|
|
newer() {
|
|
DATE=$1
|
|
shift
|
|
LogReadOnly
|
|
for m in `echo $FILESYSTEMSRW`; do
|
|
find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} $* -i -0 -f -
|
|
done;
|
|
}
|
|
|
|
#
|
|
# Compare PREVious File Context to currently installed File Context and
|
|
# run restorecon on all files affected by the differences.
|
|
#
|
|
diff_filecontext() {
|
|
EXCLUDEDIRS="`exclude_dirs_from_relabelling`"
|
|
for i in /sys /proc /mnt /var/tmp /var/lib/BackupPC /home /root /tmp; do
|
|
[ -e $i ] && EXCLUDEDIRS="${EXCLUDEDIRS} -e $i";
|
|
done
|
|
LogExcluded
|
|
|
|
if [ -f ${PREFC} -a -x /usr/bin/diff ]; then
|
|
TEMPFILE=`mktemp ${FC}.XXXXXXXXXX`
|
|
test -z "$TEMPFILE" && exit
|
|
PREFCTEMPFILE=`mktemp ${PREFC}.XXXXXXXXXX`
|
|
sed -r -e 's,:s0, ,g' $PREFC | sort -u > ${PREFCTEMPFILE}
|
|
sed -r -e 's,:s0, ,g' $FC | sort -u | \
|
|
/usr/bin/diff -b ${PREFCTEMPFILE} - | \
|
|
grep '^[<>]'|cut -c3-| grep ^/ | \
|
|
egrep -v '(^/home|^/root|^/tmp)' |\
|
|
sed -r -e 's,[[:blank:]].*,,g' \
|
|
-e 's|\(([/[:alnum:]]+)\)\?|{\1,}|g' \
|
|
-e 's|([/[:alnum:]])\?|{\1,}|g' \
|
|
-e 's|\?.*|*|g' \
|
|
-e 's|\{.*|*|g' \
|
|
-e 's|\(.*|*|g' \
|
|
-e 's|\[.*|*|g' \
|
|
-e 's|\.\*.*|*|g' \
|
|
-e 's|\.\+.*|*|g' | \
|
|
# These two sorts need to be separate commands \
|
|
sort -u | \
|
|
sort -d | \
|
|
while read pattern ; \
|
|
do if ! echo "$pattern" | grep -q -f ${TEMPFILE} 2>/dev/null; then \
|
|
echo "$pattern"; \
|
|
case "$pattern" in *"*") \
|
|
echo "$pattern" | sed -e 's,^,^,' -e 's,\*$,,g' >> ${TEMPFILE};;
|
|
esac; \
|
|
fi; \
|
|
done | \
|
|
${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -i -R -f -; \
|
|
rm -f ${TEMPFILE} ${PREFCTEMPFILE}
|
|
fi
|
|
}
|
|
|
|
rpmlist() {
|
|
rpm -q --qf '[%{FILESTATES} %{FILENAMES}\n]' "$1" | grep '^0 ' | cut -f2- -d ' '
|
|
[ ${PIPESTATUS[0]} != 0 ] && echo "$1 not found" >/dev/stderr
|
|
}
|
|
|
|
#
|
|
# restore
|
|
# if called with -n will only check file context
|
|
#
|
|
restore () {
|
|
OPTION=$1
|
|
shift
|
|
|
|
# [-B | -N time ]
|
|
if [ -n "$BOOTTIME" ]; then
|
|
newer $BOOTTIME $*
|
|
return
|
|
fi
|
|
|
|
# -C PREVIOUS_FILECONTEXT
|
|
if [ "$RESTORE_MODE" == PREFC ]; then
|
|
diff_filecontext $*
|
|
return
|
|
fi
|
|
|
|
[ -x /usr/sbin/genhomedircon ] && /usr/sbin/genhomedircon
|
|
|
|
EXCLUDEDIRS="`exclude_dirs_from_relabelling`"
|
|
LogExcluded
|
|
|
|
case "$RESTORE_MODE" in
|
|
RPMFILES)
|
|
for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do
|
|
rpmlist $i | ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -i -R -f -
|
|
done
|
|
;;
|
|
FILEPATH)
|
|
${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -R -- "$FILEPATH"
|
|
;;
|
|
*)
|
|
if [ -n "${FILESYSTEMSRW}" ]; then
|
|
LogReadOnly
|
|
echo "${OPTION}ing `echo ${FILESYSTEMSRW}`"
|
|
|
|
if [ -z "$BIND_MOUNT_FILESYSTEMS" ]; then
|
|
${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${FC} ${FILESYSTEMSRW}
|
|
else
|
|
# we bind mount so we can fix the labels of files that have already been
|
|
# mounted over
|
|
for m in `echo $FILESYSTEMSRW`; do
|
|
TMP_MOUNT="$(mktemp -d)"
|
|
test -z ${TMP_MOUNT+x} && echo "Unable to find temporary directory!" && exit 1
|
|
|
|
mkdir -p "${TMP_MOUNT}${m}" || exit 1
|
|
mount --bind "${m}" "${TMP_MOUNT}${m}" || exit 1
|
|
${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${FC} -r "${TMP_MOUNT}" "${TMP_MOUNT}${m}"
|
|
umount "${TMP_MOUNT}${m}" || exit 1
|
|
rm -rf "${TMP_MOUNT}" || echo "Error cleaning up."
|
|
done;
|
|
fi
|
|
else
|
|
echo >&2 "fixfiles: No suitable file systems found"
|
|
fi
|
|
if [ ${OPTION} != "Relabel" ]; then
|
|
return
|
|
fi
|
|
echo "Cleaning up labels on /tmp"
|
|
rm -rf /tmp/gconfd-* /tmp/pulse-* /tmp/orbit-*
|
|
|
|
UNDEFINED=`get_undefined_type` || exit $?
|
|
UNLABELED=`get_unlabeled_type` || exit $?
|
|
find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) \( -type s -o -type p \) -delete
|
|
find /tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /tmp {} \;
|
|
find /var/tmp \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /var/tmp {} \;
|
|
find /var/run \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /var/run {} \;
|
|
[ ! -e /var/lib/debug ] || find /var/lib/debug \( -context "*:${UNLABELED}*" -o -context "*:${UNDEFINED}*" \) -exec chcon --no-dereference --reference /lib {} \;
|
|
;;
|
|
esac
|
|
}
|
|
|
|
fullrelabel() {
|
|
echo "Cleaning out /tmp"
|
|
find /tmp/ -mindepth 1 -delete
|
|
restore Relabel
|
|
}
|
|
|
|
|
|
relabel() {
|
|
if [ -n "$RESTORE_MODE" -a "$RESTORE_MODE" != DEFAULT ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [ $fullFlag == 1 ]; then
|
|
fullrelabel
|
|
return
|
|
fi
|
|
|
|
echo -n "
|
|
Files in the /tmp directory may be labeled incorrectly, this command
|
|
can remove all files in /tmp. If you choose to remove files from /tmp,
|
|
a reboot will be required after completion.
|
|
|
|
Do you wish to clean out the /tmp directory [N]? "
|
|
read answer
|
|
if [ "$answer" = y -o "$answer" = Y ]; then
|
|
fullrelabel
|
|
else
|
|
restore Relabel
|
|
fi
|
|
}
|
|
|
|
process() {
|
|
#
|
|
# Make sure they specified one of the three valid commands
|
|
#
|
|
case "$1" in
|
|
restore) restore Relabel;;
|
|
check) VERBOSE="-v"; restore Check -n;;
|
|
verify) VERBOSE="-v"; restore Verify -n;;
|
|
relabel) relabel;;
|
|
onboot)
|
|
if [ -n "$RESTORE_MODE" -a "$RESTORE_MODE" != DEFAULT ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
> /.autorelabel || exit $?
|
|
[ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel
|
|
[ -z "$BOOTTIME" ] || echo -N $BOOTTIME >> /.autorelabel
|
|
[ -z "$BIND_MOUNT_FILESYSTEMS" ] || echo "-M" >> /.autorelabel
|
|
# Force full relabel if SELinux is not enabled
|
|
selinuxenabled || echo -F > /.autorelabel
|
|
echo "System will relabel on next boot"
|
|
;;
|
|
*)
|
|
usage
|
|
exit 1
|
|
esac
|
|
}
|
|
usage() {
|
|
echo $"""
|
|
Usage: $0 [-v] [-F] [-M] [-f] relabel
|
|
or
|
|
Usage: $0 [-v] [-F] [-B | -N time ] { check | restore | verify }
|
|
or
|
|
Usage: $0 [-v] [-F] { check | restore | verify } dir/file ...
|
|
or
|
|
Usage: $0 [-v] [-F] -R rpmpackage[,rpmpackage...] { check | restore | verify }
|
|
or
|
|
Usage: $0 [-v] [-F] -C PREVIOUS_FILECONTEXT { check | restore | verify }
|
|
or
|
|
Usage: $0 [-F] [-M] [-B] onboot
|
|
"""
|
|
}
|
|
|
|
if [ $# -eq 0 ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
set_restore_mode() {
|
|
if [ -n "$RESTORE_MODE" ]; then
|
|
# can't specify two different modes
|
|
usage
|
|
exit 1
|
|
fi
|
|
RESTORE_MODE="$1"
|
|
}
|
|
|
|
# See how we were called.
|
|
while getopts "N:BC:FfR:l:vM" i; do
|
|
case "$i" in
|
|
B)
|
|
BOOTTIME=`/bin/who -b | awk '{print $3}'`
|
|
set_restore_mode DEFAULT
|
|
;;
|
|
N)
|
|
BOOTTIME=$OPTARG
|
|
set_restore_mode BOOTTIME
|
|
;;
|
|
R)
|
|
RPMFILES=$OPTARG
|
|
set_restore_mode RPMFILES
|
|
;;
|
|
C)
|
|
PREFC=$OPTARG
|
|
set_restore_mode PREFC
|
|
;;
|
|
v)
|
|
VERBOSE="-v"
|
|
;;
|
|
l)
|
|
# Old scripts use obsolete option `-l logfile`
|
|
echo "Redirecting output to $OPTARG"
|
|
exec >>"$OPTARG" 2>&1
|
|
;;
|
|
M)
|
|
BIND_MOUNT_FILESYSTEMS="-M"
|
|
;;
|
|
F)
|
|
FORCEFLAG="-F"
|
|
;;
|
|
f)
|
|
fullFlag=1
|
|
;;
|
|
*)
|
|
usage
|
|
exit 1
|
|
esac
|
|
done
|
|
# Move out processed options from arguments
|
|
shift $(( OPTIND - 1 ))
|
|
|
|
# Check for the command
|
|
if [ $# -eq 0 ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
command="$1"
|
|
|
|
# Move out command from arguments
|
|
shift
|
|
|
|
if [ $# -gt 0 ]; then
|
|
set_restore_mode FILEPATH
|
|
while [ $# -gt 0 ]; do
|
|
FILEPATH="$1"
|
|
process "$command" || exit $?
|
|
shift
|
|
done
|
|
else
|
|
process "$command"
|
|
fi
|
|
|