Skip to content

Commit

Permalink
Fix jail rc.d script privilege escalation via symlink attack against
Browse files Browse the repository at this point in the history
/var/log/console.log and mount points.

Security:	FreeBSD-SA-07:01.jail
Approved by:	re (bmah)
  • Loading branch information
simonlbn committed Jan 11, 2007
1 parent 1f77dbd commit 79db24b
Showing 1 changed file with 115 additions and 12 deletions.
127 changes: 115 additions & 12 deletions etc/rc.d/jail
Expand Up @@ -67,6 +67,8 @@ init_variables()
[ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
[ -z "${_flags}" ] && _flags="-l -U root"
eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
[ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"

# Debugging aid
#
Expand All @@ -86,6 +88,7 @@ init_variables()
debug "$_j exec start: $_exec_start"
debug "$_j exec stop: $_exec_stop"
debug "$_j flags: $_flags"
debug "$_j consolelog: $_consolelog"

if [ -z "${_hostname}" ]; then
err 3 "$name: No hostname has been defined for ${_j}"
Expand Down Expand Up @@ -126,34 +129,122 @@ set_sysctl()
fi
}

# is_current_mountpoint()
# Is the directory mount point for a currently mounted file
# system?
#
is_current_mountpoint()
{
local _dir _dir2

_dir=$1

_dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
[ ! -d "${_dir}" ] && return 1
_dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
[ "${_dir}" = "${_dir2}" ]
return $?
}

# is_symlinked_mountpoint()
# Is a mount point, or any of its parent directories, a symlink?
#
is_symlinked_mountpoint()
{
local _dir

_dir=$1

[ -L "$_dir" ] && return 0
[ "$_dir" = "/" ] && return 1
is_symlinked_mountpoint `dirname $_dir`
return $?
}

# secure_umount
# Try to unmount a mount point without being vulnerable to
# symlink attacks.
#
secure_umount()
{
local _dir

_dir=$1

if is_current_mountpoint ${_dir}; then
umount -f ${_dir} >/dev/null 2>&1
else
debug "Nothing mounted on ${_dir} - not unmounting"
fi
}


# jail_umount_fs
# This function unmounts certain special filesystems in the
# currently selected jail. The caller must call the init_variables()
# routine before calling this one.
#
jail_umount_fs()
{
local _device _mountpt _rest

if checkyesno _fdescfs; then
if [ -d "${_fdescdir}" ] ; then
umount -f ${_fdescdir} >/dev/null 2>&1
secure_umount ${_fdescdir}
fi
fi
if checkyesno _devfs; then
if [ -d "${_devdir}" ] ; then
umount -f ${_devdir} >/dev/null 2>&1
secure_umount ${_devdir}
fi
fi
if checkyesno _procfs; then
if [ -d "${_procdir}" ] ; then
umount -f ${_procdir} >/dev/null 2>&1
secure_umount ${_procdir}
fi
fi
if checkyesno _mount; then
[ -f "${_fstab}" ] || warn "${_fstab} does not exist"
umount -a -F "${_fstab}" >/dev/null 2>&1
tail -r ${_fstab} | while read _device _mountpt _rest; do
case ":${_device}" in
:#* | :)
continue
;;
esac
secure_umount ${_mountpt}
done
fi
}

# jail_mount_fstab()
# Mount file systems from a per jail fstab while trying to
# secure against symlink attacks at the mount points.
#
# If we are certain we cannot secure against symlink attacks we
# do not mount all of the file systems (since we cannot just not
# mount the file system with the problematic mount point).
#
# The caller must call the init_variables() routine before
# calling this one.
#
jail_mount_fstab()
{
local _device _mountpt _rest

while read _device _mountpt _rest; do
case ":${_device}" in
:#* | :)
continue
;;
esac
if is_symlinked_mountpoint ${_mountpt}; then
warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
return
fi
done <${_fstab}
mount -a -F "${_fstab}"
}

jail_start()
{
echo -n 'Configuring jails:'
Expand Down Expand Up @@ -183,12 +274,16 @@ jail_start()
if [ ! -f "${_fstab}" ]; then
err 3 "$name: ${_fstab} does not exist"
fi
mount -a -F "${_fstab}"
jail_mount_fstab
fi
if checkyesno _devfs; then
# If devfs is already mounted here, skip it.
df -t devfs "${_devdir}" >/dev/null
if [ $? -ne 0 ]; then
if is_symlinked_mountpoint ${_devdir}; then
warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
continue
fi
info "Mounting devfs on ${_devdir}"
devfs_mount_jail "${_devdir}" ${_ruleset}
# Transitional symlink for old binaries
Expand All @@ -209,13 +304,21 @@ jail_start()
# cd "$__pwd"
fi
if checkyesno _fdescfs; then
info "Mounting fdescfs on ${_fdescdir}"
mount -t fdescfs fdesc "${_fdescdir}"
if is_symlinked_mountpoint ${_fdescdir}; then
warn "${_fdescdir} has symlink as parent, not mounting"
else
info "Mounting fdescfs on ${_fdescdir}"
mount -t fdescfs fdesc "${_fdescdir}"
fi
fi
if checkyesno _procfs; then
info "Mounting procfs onto ${_procdir}"
if [ -d "${_procdir}" ] ; then
mount -t procfs proc "${_procdir}"
if is_symlinked_mountpoint ${_procdir}; then
warn "${_procdir} has symlink as parent, not mounting"
else
info "Mounting procfs onto ${_procdir}"
if [ -d "${_procdir}" ] ; then
mount -t procfs proc "${_procdir}"
fi
fi
fi
_tmp_jail=${_tmp_dir}/jail.$$
Expand All @@ -224,7 +327,7 @@ jail_start()
if [ "$?" -eq 0 ] ; then
echo -n " $_hostname"
_jail_id=$(head -1 ${_tmp_jail})
tail +2 ${_tmp_jail} >${_rootdir}/var/log/console.log
tail +2 ${_tmp_jail} >${_consolelog}
echo ${_jail_id} > /var/run/jail_${_jail}.id
else
jail_umount_fs
Expand All @@ -251,7 +354,7 @@ jail_stop()
init_variables $_jail
if [ -n "${_exec_stop}" ]; then
eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
>> ${_rootdir}/var/log/console.log 2>&1
>> ${_consolelog} 2>&1
fi
killall -j ${_jail_id} -TERM > /dev/null 2>&1
sleep 1
Expand Down

0 comments on commit 79db24b

Please sign in to comment.