From b58abc5e12a174e11b7bc57f5f92fe48b25d13da Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Fri, 10 Aug 2007 21:01:05 +0000 Subject: [PATCH] Bring some changes from FreeBSD into the jail rc script. Submitted-by: Pawel Biernacki With some adjustments by me. --- etc/defaults/rc.conf | 35 +++- etc/rc.d/jail | 343 +++++++++++++++++++++++++++++++++++---- share/man/man5/rc.conf.5 | 165 ++++++++++++++++++- 3 files changed, 495 insertions(+), 48 deletions(-) diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 8cb53a31d0..422808bbee 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -14,7 +14,7 @@ # All arguments must be in double or single quotes. # # $FreeBSD: src/etc/defaults/rc.conf,v 1.180 2003/06/26 09:50:50 smkelly Exp $ -# $DragonFly: src/etc/defaults/rc.conf,v 1.41 2007/08/06 23:47:19 swildner Exp $ +# $DragonFly: src/etc/defaults/rc.conf,v 1.42 2007/08/10 21:01:05 swildner Exp $ ############################################################## ### Important initial Boot-time options #################### @@ -418,14 +418,39 @@ update_motd="YES" # update version info in /etc/motd (or NO) start_vinum="NO" # set to YES to start vinum rand_irqs="NO" # Stir the entropy pool (like "5 11" or NO). dmesg_enable="YES" # Save dmesg(8) to /var/run/dmesg.boot +resident_enable="NO" # Process /etc/resident.conf +varsym_enable="NO" # Process /etc/varsym.conf +watchdogd_enable="NO" # Start the software watchdog daemon + +############################################################## +### Jail Configuration ####################################### +############################################################## + jail_enable="NO" # Set to NO to disable starting of any jails jail_list="" # Space separated list of names of jails jail_set_hostname_allow="YES" # Allow root user in a jail to change its hostname jail_socket_unixiproute_only="YES" # Route only TCP/IP within a jail -jail_sysvipc_allow="NO" # Allow SystemV IPC use from within a jail -resident_enable="NO" # Process /etc/resident.conf -varsym_enable="NO" # Process /etc/varsym.conf -watchdogd_enable="NO" # Start the software watchdog daemon +jail_sysvipc_allow="NO" # Allow SystemV IPC use from within a jail + +# +# To use rc's built-in jail infrastructure create entries for +# each jail, specified in jail_list, with the following variables. +# NOTES: +# - replace 'example' with the jail's name. +# - except rootdir, hostname and ip, all of the following variables may be made +# global jail variables if you don't specify a jail name (ie. jail_interface). +# +#jail_example_rootdir="/usr/jail/default" # Jail's root directory +#jail_example_hostname="default.domain.com" # Jail's hostname +#jail_example_ip="192.168.0.10" # Jail's IP number +#jail_example_interface="" # Interface to create the IP alias on +#jail_example_exec_start="/bin/sh /etc/rc" # command to execute in jail for starting +#jail_example_exec_stop="/bin/sh /etc/rc.shutdown" # command to execute in jail for stopping +#jail_example_fdesc_enable="NO" # mount fdesc in the jail +#jail_example_procfs_enable="NO" # mount procfs in jail +#jail_example_mount_enable="NO" # mount/umount jail's fs +#jail_example_fstab="" # fstab(5) for mount/umount +#jail_example_flags="-l -U root" # flags for jail(8) ############################################################## ### Define source_rc_confs, the mechanism used by /etc/rc.* ## diff --git a/etc/rc.d/jail b/etc/rc.d/jail index 78ad28f589..3e6dbc65de 100644 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -1,7 +1,7 @@ #!/bin/sh # -# $FreeBSD: src/etc/rc.d/jail,v 1.4 2003/05/05 15:38:41 mtm Exp $ -# $DragonFly: src/etc/rc.d/jail,v 1.4 2005/11/19 21:47:32 swildner Exp $ +# $FreeBSD: src/etc/rc.d/jail,v 1.23.2.9 2007/01/11 18:16:58 simon Exp $ +# $DragonFly: src/etc/rc.d/jail,v 1.5 2007/08/10 21:01:05 swildner Exp $ # # PROVIDE: jail @@ -15,55 +15,330 @@ rcvar=`set_rcvar` start_cmd="jail_start" stop_cmd="jail_stop" -jail_start() +# init_variables _j +# Initialize the various jail variables for jail _j. +# +init_variables() { - echo -n 'Configuring jails:' - echo -n ' set_hostname_allowed=' - if checkyesno jail_set_hostname_allow ; then - echo -n 'YES' - ${SYSCTL_W} 1>/dev/null jail.set_hostname_allowed=1 + _j="$1" + + if [ -z "$_j" ]; then + warn "init_variables: you must specify a jail" + return + fi + + eval _rootdir=\"\$jail_${_j}_rootdir\" + _fdescdir="${_rootdir}/dev/fd" + _procdir="${_rootdir}/proc" + eval _hostname=\"\$jail_${_j}_hostname\" + eval _ip=\"\$jail_${_j}_ip\" + eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\" + eval _exec=\"\$jail_${_j}_exec\" + eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\" + eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\" + if [ -n "${_exec}" ]; then + # simple/backward-compatible execution + _exec_start="${_exec}" + _exec_stop="" else - echo -n 'NO' - ${SYSCTL_W} 1>/dev/null jail.set_hostname_allowed=0 + # flexible execution + if [ -z "${_exec_start}" ]; then + _exec_start="/bin/sh /etc/rc" + if [ -z "${_exec_stop}" ]; then + _exec_stop="/bin/sh /etc/rc.shutdown" + fi + fi + fi + + eval _fdesc=\"\${jail_${_j}_fdesc_enable:-${jail_fdesc_enable}}\" + [ -z "${_fdesc}" ] && _fdesc="NO" + eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\" + [ -z "${_procfs}" ] && _procfs="NO" + + eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\" + [ -z "${_mount}" ] && _mount="NO" + # "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified. + eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\" + [ -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 + # + debug "$_j fdesc enable: $_fdesc" + debug "$_j procfs enable: $_procfs" + debug "$_j mount enable: $_mount" + debug "$_j hostname: $_hostname" + debug "$_j ip: $_ip" + debug "$_j interface: $_interface" + debug "$_j root: $_rootdir" + debug "$_j fdescdir: $_fdescdir" + debug "$_j procdir: $_procdir" + debug "$_j fstab: $_fstab" + 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}" + fi + if [ -z "${_rootdir}" ]; then + err 3 "$name: No root directory has been defined for ${_j}" fi + if [ -z "${_ip}" ]; then + err 3 "$name: No IP address has been defined for ${_j}" + fi + +} - echo -n ' unixiproute_only=' - if checkyesno jail_socket_unixiproute_only ; then - echo -n 'YES' - ${SYSCTL_W} 1>/dev/null jail.socket_unixiproute_only=1 +# set_sysctl rc_knob mib msg +# If the mib sysctl is set according to what rc_knob +# specifies, this function does nothing. However if +# rc_knob is set differently than mib, then the mib +# is set accordingly and msg is displayed followed by +# an '=" sign and the word 'YES' or 'NO'. +# +set_sysctl() +{ + _knob="$1" + _mib="$2" + _msg="$3" + + _current=`${SYSCTL} -n $_mib 2>/dev/null` + if checkyesno $_knob ; then + if [ "$_current" -ne 1 ]; then + echo -n " ${_msg}=YES" + ${SYSCTL_W} 1>/dev/null ${_mib}=1 + fi else - echo -n 'NO' - ${SYSCTL_W} 1>/dev/null jail.socket_unixiproute_only=0 + if [ "$_current" -ne 0 ]; then + echo -n " ${_msg}=NO" + ${SYSCTL_W} 1>/dev/null ${_mib}=0 + fi 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 $? +} - echo -n ' sysvipc_allow=' - if checkyesno jail_sysvipc_allow ; then - echo -n 'YES' - ${SYSCTL_W} 1>/dev/null jail.sysvipc_allowed=1 +# 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 - echo -n 'NO' - ${SYSCTL_W} 1>/dev/null jail.sysvipc_allowed=0 + 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 _fdesc; then + if [ -d "${_fdescdir}" ] ; then + secure_umount ${_fdescdir} + fi + fi + if checkyesno _procfs; then + if [ -d "${_procdir}" ] ; then + secure_umount ${_procdir} + fi + fi + if checkyesno _mount; then + [ -f "${_fstab}" ] || warn "${_fstab} does not exist" + 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:' + set_sysctl jail_set_hostname_allow jail.set_hostname_allowed \ + set_hostname_allow + set_sysctl jail_socket_unixiproute_only \ + jail.socket_unixiproute_only unixiproute_only + set_sysctl jail_sysvipc_allow jail.sysvipc_allowed \ + sysvipc_allow echo '.' - echo 'Starting Jails.' - for _jail in ${jail_list} + echo -n 'Starting jails:' + _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \ + err 3 "$name: Can't create temp dir, exiting..." + for _jail in ${jail_list} do - eval jail_rootdir=\"\$jail_${_jail}_rootdir\" - eval jail_hostname=\"\$jail_${_jail}_hostname\" - eval jail_ip=\"\$jail_${_jail}_ip\" - eval jail_exec=\"\$jail_${_jail}_exec\" - [ -z ${jail_exec} ] && jail_exec="/bin/sh /etc/rc" - - jail ${jail_rootdir} ${jail_hostname} ${jail_ip} ${jail_exec} + init_variables $_jail + if [ -f /var/run/jail_${_jail}.id ]; then + echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]" + continue; + fi + if [ -n "${_interface}" ]; then + ifconfig ${_interface} alias ${_ip} netmask 255.255.255.255 + fi + if checkyesno _mount; then + info "Mounting fstab for jail ${_jail} (${_fstab})" + if [ ! -f "${_fstab}" ]; then + err 3 "$name: ${_fstab} does not exist" + fi + jail_mount_fstab + fi + if checkyesno _fdesc; then + if is_symlinked_mountpoint ${_fdescdir}; then + warn "${_fdescdir} has symlink as parent, not mounting" + else + info "Mounting fdesc on ${_fdescdir}" + mount -t fdesc fdesc "${_fdescdir}" + fi + fi + if checkyesno _procfs; then + 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.$$ + eval jail ${_flags} -i ${_rootdir} ${_hostname} \ + ${_ip} ${_exec_start} > ${_tmp_jail} 2>&1 + if [ "$?" -eq 0 ] ; then + echo -n " $_hostname" + _jail_id=$(head -1 ${_tmp_jail}) + tail +2 ${_tmp_jail} >${_consolelog} + echo ${_jail_id} > /var/run/jail_${_jail}.id + else + jail_umount_fs + if [ -n "${_interface}" ]; then + ifconfig ${_interface} -alias ${_ip} + fi + echo " cannot start jail \"${_jail}\": " + tail +2 ${_tmp_jail} + fi + rm -f ${_tmp_jail} done + rmdir ${_tmp_dir} + echo '.' } jail_stop() { - kill -TERM $(ps aux | awk '$8 ~ /.*J/ {print $2};') + echo -n 'Stopping jails:' + for _jail in ${jail_list} + do + if [ -f "/var/run/jail_${_jail}.id" ]; then + _jail_id=$(cat /var/run/jail_${_jail}.id) + if [ ! -z "${_jail_id}" ]; then + init_variables $_jail + if [ -n "${_exec_stop}" ]; then + eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \ + >> ${_consolelog} 2>&1 + fi + killall -j ${_jail_id} -TERM > /dev/null 2>&1 + sleep 1 + killall -j ${_jail_id} -KILL > /dev/null 2>&1 + jail_umount_fs + echo -n " $_hostname" + fi + if [ -n "${_interface}" ]; then + ifconfig ${_interface} -alias ${_ip} + fi + rm /var/run/jail_${_jail}.id + else + echo " cannot stop jail ${_jail}. No jail id in /var/run" + fi + done + echo '.' } - load_rc_config $name -run_rc_command "$1" +cmd="$1" +if [ $# -gt 0 ]; then + shift +fi +if [ -n "$*" ]; then + jail_list="$*" +fi +run_rc_command "${cmd}" diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5 index df2729b2e1..c66908f73c 100644 --- a/share/man/man5/rc.conf.5 +++ b/share/man/man5/rc.conf.5 @@ -23,8 +23,8 @@ .\" SUCH DAMAGE. .\" .\" $FreeBSD: src/share/man/man5/rc.conf.5,v 1.197 2003/07/28 13:56:00 mbr Exp $ -.\" $DragonFly: src/share/man/man5/rc.conf.5,v 1.43 2007/07/13 07:36:26 swildner Exp $ -.Dd July 13, 2007 +.\" $DragonFly: src/share/man/man5/rc.conf.5,v 1.44 2007/08/10 21:01:05 swildner Exp $ +.Dd August 10, 2007 .Dt RC.CONF 5 .Os .Sh NAME @@ -2409,13 +2409,157 @@ you would have the following dependent variables: jail_vjail_hostname="jail.example.com" jail_vjail_ip="192.168.1.100" jail_vjail_rootdir="/var/jails/vjail/root" -jail_vjail_exec="/bin/sh /etc/rc" .Ed .Pp -The last one is optional. -It defaults to -.Pa /etc/rc -if it is not set. +.It Va jail_flags +.Pq Vt str +Unset by default. +When set, use as default value for +.Va jail_ Ns Ao Ar jname Ac Ns Va _flags +for every jail in +.Va jail_list . +.It Va jail_interface +.Pq Vt str +Unset by default. +When set, use as default value for +.Va jail_ Ns Ao Ar jname Ac Ns Va _interface +for every jail in +.Va jail_list . +.It Va jail_fstab +.Pq Vt str +Unset by default. +When set, use as default value for +.Va jail_ Ns Ao Ar jname Ac Ns Va _fstab +for every jail in +.Va jail_list . +.It Va jail_mount_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +sets +.Va jail_ Ns Ao Ar jname Ac Ns Va _mount_enable +to +.Dq Li YES +by default for every jail in +.Va jail_list . +.It Va jail_fdesc_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +sets +.Va jail_ Ns Ao Ar jname Ac Ns Va _fdesc_enable +to +.Dq Li YES +by default for every jail in +.Va jail_list . +.It Va jail_procfs_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +sets +.Va jail_ Ns Ao Ar jname Ac Ns Va _fdesc_enable +to +.Dq Li YES +by default for every jail in +.Va jail_list . +.It Va jail_exec_start +.Pq Vt str +Unset by default. +When set, use as default value for +.Va jail_ Ns Ao Ar jname Ac Ns Va _exec_start +for every jail in +.Va jail_list . +.It Va jail_exec_stop +Unset by default. +When set, use as default value for +.Va jail_ Ns Ao Ar jname Ac Ns Va _exec_stop +for every jail in +.Va jail_list . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _rootdir +.Pq Vt str +Unset by default. +Set to the root directory used by jail +.Va jname . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _hostname +.Pq Vt str +Unset by default. +Set to the fully qualified domain name (FQDN) assigned to jail +.Va jname . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _ip +.Pq Vt str +Unset by default. +Set to the IP address assigned to jail +.Va jname . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _flags +.Pq Vt str +Set to +.Dq Li -l -U root +by default. +These are flags to pass to +.Xr jail . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _interface +.Pq Vt str +Unset by default. +When set, sets the interface to use when setting IP address alias. +Note that the alias is created at jail startup and removed at jail shutdown. +.It Va jail_ Ns Ao Ar jname Ac Ns Va _fstab +.Pq Vt str +Set to +.Pa /etc/fstab. Ns Aq Ar jname +by default. +This is the file system information file to use for jail +.Va jname . +.It Va jail_ Ns Ao Ar jname Ac Ns Va _mount_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +mount all file systems from +.Va jail_ Ns Ao Ar jname Ac Ns Va _fstab +at jail startup. +.It Va jail_ Ns Ao Ar jname Ac Ns Va _fdesc_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +mount the file-descriptor file system inside jail +.Ar jname +at jail startup. +.It Va jail_ Ns Ao Ar jname Ac Ns Va _procfs_enable +.Pq Vt bool +Set to +.Dq Li NO +by default. +When set to +.Dq Li YES , +mount the process file system inside jail +.Ar jname +at jail startup. +.It Va jail_ Ns Ao Ar jname Ac Ns Va _exec_start +.Pq Vt str +Set to +.Dq Li /bin/sh /etc/rc +by default. +This is the command executed at jail startup. +.It Va jail_ Ns Ao Ar jname Ac Ns Va _exec_stop +.Pq Vt str +Set to +.Dq Li /bin/sh /etc/rc.shutdown +by default. +This is the command executed at jail shutdown. .It Va jail_set_hostname_allow .Pq Vt bool If set to @@ -2424,8 +2568,10 @@ do not allow the root user in a jail to set its hostname. .It Va jail_socket_unixiproute_only .Pq Vt bool If set to -.Dq Li NO , -do not allow any protocol, besides TCP/IP, to be used within a jail. +.Dq Li YES , +do not allow any sockets, +besides UNIX/IP/route sockets, +to be used within a jail. .It Va jail_sysvipc_allow .Pq Vt bool If set to @@ -2614,6 +2760,7 @@ has not completed within the specified time (in seconds). .Xr inetd 8 , .Xr isdnd 8 , .Xr isdntrace 8 , +.Xr jail 8 , .Xr kldxref 8 , .Xr lpd 8 , .Xr makewhatis 8 , -- 2.41.0