Index: usr.sbin/mergemaster/mergemaster.8 =================================================================== --- usr.sbin/mergemaster/mergemaster.8 +++ usr.sbin/mergemaster/mergemaster.8 @@ -389,6 +389,11 @@ # Files to always avoid comparing #IGNORE_FILES='/etc/motd /etc/printcap foo bar' # +# Files that are allowed to fail type checking if they are a symbolic link to +# the correct type. /boot is always allowed to be a symbolic link. If a +# destination directory is specified, the link must not point outside of it. +#ALLOW_SYMLINK='/boot /var' # separate multiple files with spaces +# # Additional options for diff. This will get unset when using -s. #DIFF_OPTIONS='-Bb' # Ignore changes in whitespace # Index: usr.sbin/mergemaster/mergemaster.sh =================================================================== --- usr.sbin/mergemaster/mergemaster.sh +++ usr.sbin/mergemaster/mergemaster.sh @@ -353,6 +353,15 @@ esac done +# Resolve a potentially relative destination directory which is +# required to later catch symbolic links pointing outside of it +if [ -n "${DESTDIR}" ]; then + DESTDIR=`realpath "${DESTDIR}"` + if [ $? != 0 ]; then + exit 1 + fi +fi + if [ -n "$AUTO_RUN" ]; then if [ -n "$FREEBSD_ID" -o -n "$AUTO_UPGRADE" -o -n "$AUTO_INSTALL" ]; then echo '' @@ -1034,6 +1043,28 @@ TEMPROOT_TYPE=`echo $TEMPROOT_TYPE | tr [:upper:] [:lower:]` INSTALLED_TYPE=`echo $INSTALLED_TYPE | tr [:upper:] [:lower:]` + # Ignore the type mismatch for user specified files if the installed + # file is of type symlink and the following conditions are met: + # - installed type is symlink + # - symlink target has the correct type + # - if DESTDIR is set, symlink does not point outside of it + # - file is listed in ALLOW_SYMLINK + # Always allow /boot to be a symlink to handle bsdinstall linking /boot + # to an unencrypted boot volume + if [ "${INSTALLED_TYPE}" = 'symbolic link' ]; then + SYMLINK_TARGET=`realpath "${DESTDIR}${COMPFILE#.}"` + SYMLINK_TARGET_TYPE=`stat -f '%HT' "${SYMLINK_TARGET}" | tr "[:upper:]" "[:lower:]"` + + if [ "${TEMPROOT_TYPE}" = "${SYMLINK_TARGET_TYPE}" ]; then + # if DESTDIR is set it must be a removable prefix of SYMLINK_TARGET + if [ -z "${DESTDIR}" ] || [ "${SYMLINK_TARGET}" != "${SYMLINK_TARGET##${DESTDIR}}" ]; then + case " ${ALLOW_SYMLINK} /boot " in + *" ${COMPFILE#.} "*) continue ;; + esac + fi + fi + fi + echo "*** The installed file ${DESTDIR}${COMPFILE#.} has the type \"$INSTALLED_TYPE\"" echo " but the new version has the type \"$TEMPROOT_TYPE\"" echo '' @@ -1062,6 +1093,7 @@ esac ;; *) echo '' echo "*** See the man page about adding ${COMPFILE#.} to the list of IGNORE_FILES" + echo "*** or ALLOW_SYMLINK" press_to_continue ;; esac echo ''